【问题标题】:How To Add Multiple Cards Of The Same CardView To A RecyclerView?RecyclerView如何添加同一个CardView的多张卡片?
【发布时间】:2021-09-13 01:46:58
【问题描述】:

这是我尝试做的事情的视频,并解释了我遇到的问题。转到下面的链接。

https://file.re/2021/09/12/2021-09-1210-43-21/

这里是 XML、Java 和清单代码视频。转到下面的链接。

https://file.re/2021/09/12/2021-09-1211-32-13/

答案有效,但现在我有两个新问题。这是下面的视频链接。

https://file.re/2021/09/12/2021-09-1212-08-04/

我正在创建一个将CardView 布局列出到RecyclerView 的应用程序。

我的应用程序会将CardView 布局添加到RecyclerView 列表中,但它只列出了一个。我希望它在用户单击按钮添加卡片时添加多个相同的 CardView(基本上是在另一个下面克隆 CardView 布局)。

这是我的按钮单击中的内容...

ftocConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    ArrayList<RecyclerItem> addFahToCelCard = new ArrayList<>();
                    addFahToCelCard.add(new RecyclerItem());
                    recyclerView = findViewById(R.id.recycler_item_view);
                    recyclerView.setHasFixedSize(true);
                    layoutManager = new LinearLayoutManager(MainActivity.this);
                    recyclerItemAdapter = new RecyclerItemAdapter(addFahToCelCard);
                    recyclerView.setLayoutManager(layoutManager);
                    recyclerView.setAdapter(recyclerItemAdapter);
                }
            }
        });

我尝试将 ArrayList&lt;RecyclerItem&gt; addFahToCelCard = new ArrayList&lt;&gt;(); 放在 MainActivity extends AppCompatActivity 类下,就在 onCreate 之前...

public class MainActivity extends AppCompatActivity {

final private ArrayList<RecyclerItem> addFahToCelCard = new ArrayList<>();

那没用。

如果我不在按钮单击侦听器中保留ArrayList&lt;RecyclerItem&gt; addFahToCelCard = new ArrayList&lt;&gt;();,并且我添加了一个新的 CardView,它会在每次单击按钮时在原始卡片后面添加一个新卡片,如果我删除卡片,它会不断弹出备份,直到我将它们全部删除。如何按照我希望它的行为方式解决这个问题?我希望这一切都有意义。

感谢您的帮助!

这是 java 类中的所有内容..

public class MainActivity extends AppCompatActivity {

    ArrayList<RecyclerItem> addFahToCelCard;

    private Animation fromBottom;
    private Animation toBottom;
    private Boolean clicked = false;
    private RecyclerView recyclerView;
    private RecyclerItemAdapter recyclerItemAdapter;
    private RecyclerView.LayoutManager layoutManager;

    public FloatingActionButton mainConverterMenuFloatBtn;
    public TextView chooseConverterLabel, ftocConverterLabelBtn, ftokConverterLabelBtn, ctofConverterLabelBtn, ctokConverterLabelBtn, ktofConverterLabelBtn, ktocConverterLabelBtn;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fromBottom = AnimationUtils.loadAnimation(MainActivity.this, R.anim.from_bottom_animation);
        toBottom = AnimationUtils.loadAnimation(MainActivity.this, R.anim.to_bottom_animation);

        mainConverterMenuFloatBtn = findViewById(R.id.add_temp_converter_float_btn);
        chooseConverterLabel = findViewById(R.id.choose_converter_label);
        ftocConverterLabelBtn = findViewById(R.id.add_f_to_c_converter_label_btn);
        ftokConverterLabelBtn = findViewById(R.id.add_f_to_k_converter_label_btn);
        ctofConverterLabelBtn = findViewById(R.id.add_c_to_f_converter_label_btn);
        ctokConverterLabelBtn = findViewById(R.id.add_c_to_k_converter_label_btn);
        ktofConverterLabelBtn = findViewById(R.id.add_k_to_f_converter_label_btn);
        ktocConverterLabelBtn = findViewById(R.id.add_k_to_c_converter_label_btn);

        addFahToCelCard = new ArrayList<>();
        recyclerView = findViewById(R.id.recycler_item_view);
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(MainActivity.this);
        recyclerItemAdapter = new RecyclerItemAdapter(addFahToCelCard);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(recyclerItemAdapter);

        mainConverterMenuFloatBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mainConverterMenu();
            }
        });

        ftocConverterLabelBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                if (clicked) {
                    addFahToCelCard.add(new RecyclerItem());
                    recyclerItemAdapter.notifyDataSetChanged();
                    closeActionButton();
                }
            }
        });

        ftokConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (clicked) {
                    closeActionButton();
                }
            }
        });

        ctofConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (clicked) {
                    closeActionButton();
                }
            }
        });

        ctokConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (clicked) {
                    closeActionButton();
                }
            }
        });

        ktofConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (clicked) {
                    closeActionButton();
                }
            }
        });

        ktocConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (clicked) {
                    closeActionButton();
                }
            }
        });

    }

    private void addFahToCelCard() {

    }

    private void mainConverterMenu() {
        setVisibility(clicked);
        setClickable(clicked);
        setAnimation(clicked);
        clicked = !clicked;
    }

    private void setVisibility(Boolean clicked) {

        if (!clicked) {
            chooseConverterLabel.setVisibility(View.VISIBLE);
            ftocConverterLabelBtn.setVisibility(View.VISIBLE);
            ftokConverterLabelBtn.setVisibility(View.VISIBLE);
            ctofConverterLabelBtn.setVisibility(View.VISIBLE);
            ctokConverterLabelBtn.setVisibility(View.VISIBLE);
            ktofConverterLabelBtn.setVisibility(View.VISIBLE);
            ktocConverterLabelBtn.setVisibility(View.VISIBLE);
        } else {
            chooseConverterLabel.setVisibility(View.GONE);
            ftocConverterLabelBtn.setVisibility(View.GONE);
            ftokConverterLabelBtn.setVisibility(View.GONE);
            ctofConverterLabelBtn.setVisibility(View.GONE);
            ctokConverterLabelBtn.setVisibility(View.GONE);
            ktofConverterLabelBtn.setVisibility(View.GONE);
            ktocConverterLabelBtn.setVisibility(View.GONE);
        }

    }

    private void setClickable(Boolean clicked) {

        if (!clicked) {
            chooseConverterLabel.setClickable(true);
            ftocConverterLabelBtn.setClickable(true);
            ftokConverterLabelBtn.setClickable(true);
            ctofConverterLabelBtn.setClickable(true);
            ctokConverterLabelBtn.setClickable(true);
            ktofConverterLabelBtn.setClickable(true);
            ktocConverterLabelBtn.setClickable(true);
        } else {
            chooseConverterLabel.setClickable(false);
            ftocConverterLabelBtn.setClickable(false);
            ftokConverterLabelBtn.setClickable(false);
            ctofConverterLabelBtn.setClickable(false);
            ctokConverterLabelBtn.setClickable(false);
            ktofConverterLabelBtn.setClickable(false);
            ktocConverterLabelBtn.setClickable(false);
        }

    }

    private void setAnimation(Boolean clicked) {

        if (!clicked) {
            chooseConverterLabel.startAnimation(fromBottom);
            ftocConverterLabelBtn.startAnimation(fromBottom);
            ftokConverterLabelBtn.startAnimation(fromBottom);
            ctofConverterLabelBtn.startAnimation(fromBottom);
            ctokConverterLabelBtn.startAnimation(fromBottom);
            ktofConverterLabelBtn.startAnimation(fromBottom);
            ktocConverterLabelBtn.startAnimation(fromBottom);
        } else {
            chooseConverterLabel.startAnimation(toBottom);
            ftocConverterLabelBtn.startAnimation(toBottom);
            ftokConverterLabelBtn.startAnimation(toBottom);
            ctofConverterLabelBtn.startAnimation(toBottom);
            ctokConverterLabelBtn.startAnimation(toBottom);
            ktofConverterLabelBtn.startAnimation(toBottom);
            ktocConverterLabelBtn.startAnimation(toBottom);
        }
    }

    private void closeActionButton() {
        setVisibility(clicked);
        setClickable(clicked);
        setAnimation(clicked);
        clicked = !clicked;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.app_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.show_hide_float_convert_btn) {

            if (mainConverterMenuFloatBtn.isShown()) {
                mainConverterMenuFloatBtn.setVisibility(View.GONE);
                item.setIcon(R.drawable.ic_baseline_visibility_off_32);
            } else if (!mainConverterMenuFloatBtn.isShown()) {
                mainConverterMenuFloatBtn.setVisibility(View.VISIBLE);
                item.setIcon(R.drawable.ic_baseline_visibility_32);
            }

        } else if (id == R.id.app_help) {

        } else if (id == R.id.tip_developer) {

        } else if (id == R.id.premium_features) {

        } else if (id == R.id.about_app) {

        } else if (id == R.id.exit_app) {

        }

        return super.onOptionsItemSelected(item);
    }

    public static class RecyclerItemAdapter extends RecyclerView.Adapter<RecyclerItemAdapter.RecyclerViewHolder> {

        public ArrayList<RecyclerItem> recyclerItemList;
        public AdapterView.OnItemClickListener recyclerItemListener;

        public interface OnItemClickListener {
            void onItemClick (int position);
        }

        public void setOnItemClickListener(OnItemClickListener listener) {
            recyclerItemListener = (AdapterView.OnItemClickListener) listener;
        }

        public static class RecyclerViewHolder extends RecyclerView.ViewHolder {

            EditText inputFahValueET;
            TextView fahtoCelResult;
            ImageView tempIconAndConvertBtn;
            ImageView deleteCardBtn;
            String shortResult, longResult;
            
            public RecyclerViewHolder(@NonNull View itemView, final OnItemClickListener listener) {
                super(itemView);

                inputFahValueET = itemView.findViewById(R.id.input_fahrenheit_value_to_convert);
                fahtoCelResult = itemView.findViewById(R.id.output_result_ftc);
                tempIconAndConvertBtn = itemView.findViewById(R.id.temp_icon_convert_btn);
                deleteCardBtn = itemView.findViewById(R.id.remove_card);

                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if (listener != null) {
                            int position = getAdapterPosition();
                            if (position != RecyclerView.NO_POSITION) {
                                listener.onItemClick(position);
                            }
                        }
                    }
                });
            }

        }

        public RecyclerItemAdapter(ArrayList<RecyclerItem> rList) {
            recyclerItemList = rList;
        }

        @NonNull
        @Override
        public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fahrenheit_to_celsius_converter_layout, parent, false);
            RecyclerViewHolder recyclerViewHolder = new RecyclerViewHolder(v, (OnItemClickListener) recyclerItemListener);
            return recyclerViewHolder;
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
            RecyclerItem currentItem = recyclerItemList.get(position);
            final String[] result = new String[1];

            holder.tempIconAndConvertBtn.setOnClickListener(new View.OnClickListener() {
                @SuppressLint("SetTextI18n")
                @Override
                public void onClick(View view) {
                    String getIputFahValue = holder.inputFahValueET.getText().toString();
                    NumberFormat nf = new DecimalFormat("0.000");
                    if(!getIputFahValue.isEmpty()) {
                        double d = Double.parseDouble(getIputFahValue);
                        double dd = d - 32;
                        double ddd = dd * 5;
                        double dddd = ddd / 9;
                        result[0] = Double.toString(dddd);

                        holder.fahtoCelResult.setText(nf.format(dddd) + "°C");
                        holder.fahtoCelResult.setVisibility(View.VISIBLE);
                        holder.shortResult = nf.format(dddd) + "°C";
                        holder.longResult = getIputFahValue + "°F is " + nf.format(dddd) + "°C";

                        if (result[0].contains(".0")) {
                            result[0] = result[0].replace(".0", "");
                            holder.fahtoCelResult.setText(result[0] + "°C");
                            holder.fahtoCelResult.setVisibility(View.VISIBLE);
                            holder.shortResult = result[0] + "°C";
                            holder.longResult = getIputFahValue + "°F is " + result[0] + "°C";
                        }else if (result[0].contains(".000")) {
                            result[0] = result[0].replace(".000", "");
                            holder.fahtoCelResult.setText(result[0] + "°C");
                            holder.fahtoCelResult.setVisibility(View.VISIBLE);
                            holder.shortResult = result[0] + "°C";
                            holder.longResult = getIputFahValue + "°F is " + result[0] + "°C";
                        }

                    }else {
                        Toast.makeText(view.getContext(), "Fahrenheit Value Field Cannot Be Blank!", Toast.LENGTH_LONG).show();
                    }
                }
            });

            holder.fahtoCelResult.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    AlertDialog.Builder adb = new AlertDialog.Builder(view.getContext());
                    adb.setIcon(R.drawable.ic_baseline_file_copy_32);
                    adb.setTitle("Copy Result");
                    adb.setMessage("You can copy the result to your clipboard if you would like. Choose if you want the short or long result copied to your clipboard.\n\nExample of Short and Long Result:\nShort Result: 32°C\nLong Result: 0°F is 32°C");

                    adb.setPositiveButton("Short", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            ClipboardManager cbm = (ClipboardManager) view.getContext().getSystemService(CLIPBOARD_SERVICE);
                            ClipData clip = ClipData.newPlainText("Copy", holder.shortResult);
                            cbm.setPrimaryClip(clip);
                            Toast.makeText(view.getContext(), "Result Copied!", Toast.LENGTH_SHORT).show();
                        }
                    });

                    adb.setNegativeButton("Long", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            ClipboardManager cbm = (ClipboardManager) view.getContext().getSystemService(CLIPBOARD_SERVICE);
                            ClipData clip = ClipData.newPlainText("Copy", holder.longResult);
                            cbm.setPrimaryClip(clip);
                            Toast.makeText(view.getContext(), "Result Copied!", Toast.LENGTH_SHORT).show();
                        }
                    });

                    adb.setNeutralButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {}});

                    adb.create();
                    adb.show();

                    return false;
                }
            });

            holder.deleteCardBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    recyclerItemList.remove(position);
                    notifyItemRemoved(position);
                }
            });


        }

        @Override
        public int getItemCount() {
            return recyclerItemList.size();
        }
    }

    public class RecyclerItem {

        public RecyclerItem() {

        }

    }
}

recyclerView 应该列出 CardViews 并允许重复。

【问题讨论】:

  • 关于删除某些项目时出现的异常问题,请尝试使用holder.getAbsoluteAdapterPosition(),而不是getAdapterPosition或旧的最终位置值。
  • 每当您在侦听器中使用值时,我想它会采用现在存在的值并将其保存为最终值,因此如果您有 5 个项目并删除了前 3 个项目,那么最后两个项目仍然有他们的位置存储为 4 和 5 而不是 1 和 2,这就是为什么你应该调用 holder.getAbsoluteAdapterPosition() 来获取当前位置而不是最终存储的位置,这样他将持有者存储为 final 而不是存储 const int价值
  • 您先生是个天才!太感谢了!现在一切正常!非常感谢大家!!!
  • 也许你也可以帮我解决这个问题? stackoverflow.com/questions/69175887/…

标签: java android


【解决方案1】:

好吧,我认为您只是以错误的方式使用RecyclerView

在您的代码 sn-p 中,每次用户单击按钮时,您都会初始化 RecyclerView 以及适配器和所有其他组件。

首先,您必须在RecyclerItemAdapter 类中创建插入方法。

RecyclerItemAdapter.java

class RecyclerItemAdapter extends RecyclerView.Adapter<YourViewHolder> {

        private ArrayList<RecyclerItem> items;

        RecyclerItemAdapter(ArrayList<RecyclerItem> recyclerItems) {
            this.items = recyclerItems;
        }

        //...


        public void addItem(RecyclerItem item) {
            items.add(item);
            notifyDataSetChanged();
        }
    }

然后,您只需初始化一次RecyclerView。最好的方法是使用onCreate 方法。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ArrayList<RecyclerItem> addFahToCelCard;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addFahToCelCard = new ArrayList<>();
        setupRecyclerView();
        setupClickListener();
    }

    private void setupRecyclerView() {
        recyclerView = findViewById(R.id.recycler_item_view);
        recyclerItemAdapter = new RecyclerItemAdapter(addFahToCelCard);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
        recyclerView.setAdapter(recyclerItemAdapter);
    }
}

现在添加您的onClickListener,这只会将卡片添加到列表中。

private void setupClickListener() {
        ftocConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                recyclerItemAdapter.addItem(new RecyclerItem());
            }
        });
    }

【讨论】:

  • 谢谢,但您的回答仍然没有给我想要的行为。
【解决方案2】:

这个卡片视图的 xml 布局是什么?看起来这个卡片视图在另一个布局中,它的宽度和高度都匹配父级。 如果是这样的话,案例项目太大而无法显示。


好的,所以尝试使第一个相关布局高度 = 100dp 以匹配 fahrenheit_to_celsius_converter_layout.xml 中的卡片视图

【讨论】:

  • 它确实列出了 CardView。在我添加第一个之后,当我去添加另一个然后另一个时,它会继续添加到第一个 CardView 后面。因此,它彼此堆叠,而不是在彼此下方列出。
  • 我知道我看过你的视频,但如果像我说的那样,它总是只显示第一个
  • 好的。我将使用您要求的 XML 更新我的问题。一秒……
  • 我必须添加另一个显示 XML 的视频,因为我的问题已达到字符数限制。
  • 也许可以在这里作为评论尝试?
【解决方案3】:

好吧,我不太了解这个问题,但根据我的理解,你应该这样做:

  • 首先,您不应该在每次单击按钮时都创建一个新的回收器视图,而是应该将初始化回收器视图的代码放在活动类中存在的 onCreate 方法中,并且只保留对包含数据和适配器作为全局变量。

  • 每当用户单击按钮时,您应该向数据数组列表添加一个新项目,并使用 adapter.notifyDataItemSetChanged 告诉回收视图检查回收视图是否发生任何更改,并在必要时采取措施

这里有一段代码解释了我在说什么,我希望你即使这不能回答你的问题,你也能瞥见如何处理 recyclerview :

首先,正如我所说,您应该保留对将数据和适配器保存为全局变量的数组列表的引用,以便将它们放在活动中的任何方法之外

RecyclerItemAdapter recyclerItemAdapter ; 
ArrayList <RecyclerItem>addFahToCelCard ;

然后把这个代码代替按钮代码

    addFahToCelCard = new ArrayList<>();
    recyclerView = findViewById(R.id.recycler_item_view);
    layoutManager = new LinearLayoutManager(MainActivity.this);
    recyclerItemAdapter = new RecyclerItemAdapter(addFahToCelCard);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(recyclerItemAdapter);
    ftocConverterLabelBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            addFahToCelCard.add(new RecyclerItem());
            recyclerItemAdapter.notifyDataSetChanged();
        }
    }
});

这样,只要您想随时编辑 recyclerView 数据,您就可以从全局数组列表中添加/删除项目并通知适配器,就像按钮 OnClickListener 中的代码一样


更新到最后发布的有关异常的视频

当您删除某些项目时会出现此问题,请尝试使用 holder.getAbsoluteAdapterPosition(),而不是 getAdapterPosition 或旧的最终位置值。

每当您在侦听器中使用值时,我想它会采用现在存在的值并将其保存为最终值,因此如果您有 5 个项目并删除了前 3 个项目,最后两个项目的位置仍将存储为 4和 5 而不是 1 和 2,这就是为什么您应该调用 holder.getAbsoluteAdapterPosition() 来获取当前位置而不是最终存储的位置,这样他将持有者存储为 final 而不是存储 const int 值。

【讨论】:

  • 谢谢,但您的回答仍然没有给我想要的行为。
  • 然后解释一下,我说过我不明白你的应用程序的流程
  • 好的,给我几分钟。我将在视频中解释所有内容,并将视频添加到我的问题中。
  • 好的,你去。我已经更新了我的问题。视频链接在我的问题的开头。
  • 希望视频为您解释一切。
猜你喜欢
  • 2022-10-01
  • 2020-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-17
相关资源
最近更新 更多