【问题标题】:RecyclerView and AdapterView, fails to show itemsRecyclerView 和 AdapterView,无法显示项目
【发布时间】:2017-09-18 18:44:41
【问题描述】:

我正在做一些简单的示例,将它们作为指南等。我有一个带有自己的适配器的 RecyclerView。这些项目是数据模型,带有文本和图像。 ViewHolder 除了包含相应的视图外,我还添加了一个布尔值来控制图像是否可见。

当我单击时,例如在第一个项目中,图像会消失(如果再次单击,图像会出现)。

问题是,如果您单击(例如第一个元素)图像会按预期消失,但是当滚动并且回收器加载不可见的新元素时,会突然出现一个带有隐藏图像的元素。

稍微调试一下,我发现在加载元素时,depends 出现,布尔值为 true,理论上应该为 false。

我无法理解发生了什么,因为列表中的元素不同。

P.S:正如我所说,代码真的很简单,所以不要指望有什么好东西。

MainActivity:

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

        recyclerView = (RecyclerView) findViewById(R.id.recycler);

        List<Person> personList = new ArrayList<>();
        personList.add(new Person ("User1"));
        personList.add(new Person ("User2"));
        personList.add(new Person ("User3"));
        personList.add(new Person ("User4"));
        personList.add(new Person ("User5"));
        personList.add(new Person ("User6"));
        personList.add(new Person ("User7"));
        personList.add(new Person ("User8"));
        personList.add(new Person ("User9"));
        personList.add(new Person ("User10"));
        personList.add(new Person ("User11"));
        personList.add(new Person ("User12"));
        personList.add(new Person ("User13"));
        personList.add(new Person ("User14"));
        personList.add(new Person ("User15"));
        personList.add(new Person ("User16"));
        personList.add(new Person ("User17"));
        personList.add(new Person ("User18"));
        personList.add(new Person ("User19"));
        personList.add(new Person ("User20"));
        personList.add(new Person ("User22"));
        personList.add(new Person ("User23"));


        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        CustomImageAdapter adapter = new CustomImageAdapter(personList);
        recyclerView.setAdapter(adapter);

适配器:

public class CustomImageAdapter extends RecyclerView.Adapter<CustomImageAdapter.ViewHolder> {

    private List<Person> personList;

    public CustomImageAdapter(List<Person> personList) {
        this.personList = personList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.image_person, parent, false);

        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {

        Person person = personList.get(position);
        holder.name.setText(person.getName());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!holder.imageHide) {
                    holder.image.setVisibility(View.INVISIBLE);

                } else {
                    holder.image.setVisibility(View.VISIBLE);
                }
                holder.imageHide = !holder.imageHide;
            }
        });
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView name;
        ImageView image;
        boolean imageHide = false;


        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.name);
            image = (ImageView) itemView.findViewById(R.id.image);
            imageHide = false;
        }
    }
}

数据模型:(只是偷偷摸摸)

public class Person {
    private String name;
    private String image;


    public Person(String name) {
        this.name = name;
    }
    ....
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp">

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <ImageView
        android:id="@+id/image"
        android:layout_width="30dp"
        android:layout_height="30dp"
        app:srcCompat="@mipmap/ic_launcher"/>
</LinearLayout>

以几张图片为例:

【问题讨论】:

    标签: android onclicklistener android-adapter android-recyclerview


    【解决方案1】:

    ViewHolder 类旨在用于快速访问“视图”相关的项目,例如 textviews 或 imageViews 这种性质的东西。

    当内容需要基于对象模型进行动态化时,对象模型需要驱动可见性模式。不是嵌套在 viewholder 类中的布尔值。

    这样想。回收器视图回收 (n) 个视图。

    --View 1 (显示人 1) boolean visible in viewholder 1

    --View 2 (显示人 2) boolean 在 vi​​ewholder 1 中可见

    --View 3 (显示人 3) boolean 在 vi​​ewholder 1 中可见

    点击查看 1

    --查看1--保存布尔false“图片不可见”

    点击后的当前视图

    --View 1 (显示人 1) boolean invisible in viewholder 1

    --View 2 (显示人 2) boolean 在 vi​​ewholder 1 中可见

    --View 3 (显示人 3) boolean 在 vi​​ewholder 1 中可见

    现在你滚动回收器

    视图 1 已离开屏幕并在下一个屏幕上被回收,因为 Person 4 现在在 viewholder 模式中保留布尔值

    --View 2(显示人 2)布尔值在 viewholder 2 中可见

    --View 3 (显示人 3) boolean 在 vi​​ewholder 3 中可见

    --View 1(显示人 4)布尔在 viewholder 1 中不可见

    所以要纠正这个: 只需像这样修改您的代码:

    public class Person {
    private String name;
    private String image;
    private boolean isVisible;
    
    public boolean getIsVisible(){
         return isVisible;
    }
    public void setIsVisible(boolean value){
        isVisible = value;
    }
    
    
    public Person(String name) {
        this.name = name;
    }
    ....
    

    }

    然后像这样修改你的适配器:

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
    
        final Person person = personList.get(position);
        holder.name.setText(person.getName());
        holder.image.setVisibility(person.getIsVisibility() ? VISIBLE : INVISIBLE);
        onItemClick(holder.root, person, position);
    }
    
       /*///////////////////////////////////////////////////////////////
    // CLICK LISTENERS
    *////////////////////////////////////////////////////////////////
    private void onItemClick(final LinearLayout root, final Person model, final int position){
        root.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                person.setIsVisible(!person.getIsVisible());
                root.findViewById(YOUR_IMAGE_ID).setVisibility(person.getIsVisible() ? VISIBLE : INVISIBLE);
                 //or if you prefer to not findViewById, you can just update person boolean and call
                //notifyDataSetChanged();
    
            }
    
        });
    
    }
    

    如果您选择执行 findViewById 路由,则将根 id 添加到您的 XML 文件和查看器类(建议比通知更有效)

    您可以为指南考虑的另一件事是解释如何处理适配器外部的点击。如果我不进行数据绑定,我通常更喜欢接口。将此添加到适配器的底部。

     public interface ItemSelectedListener {
        void personList_onItemClick(View view, int position, final Person person);
        void personList_onItemLongClick(View view, int position, final Person person);
    
    }
    

    然后在构造函数中需要 ItemSelectedListener 并存储在适配器类中。然后你可以修改你的 onClick 处理程序来做

      private void onItemClick(final LinearLayout root, final Person person, final int position){
        root.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mItemSelectedListener != null){
                    mItemSelectedListener.personList_onClick(v, position, person);
    
                }
    
            }
    
        });
    
    }
    

    当然要重复上述操作以处理长按。

       private void onItemLongClick(final LinearLayout root, final Person person, final int position){
        root.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if(mItemSelectedListener != null){
                    mItemSelectedListener.personList_onItemLongClick(v, position, model);
    
                }
    
                return false;
    
            }
    
        });
    
    }
    

    当然也可以将长按的监听器添加到您的绑定视图中

    @Override
        public void onBindViewHolder(final ViewHolder holder, int position) {
    
            final Person person = personList.get(position);
            holder.name.setText(person.getName());
            holder.image.setVisibility(person.getIsVisibility() ? VISIBLE : INVISIBLE);
            onItemClick(holder.root, person, position);
            onItemLongClick(holder.root, person, position);
        }
    

    【讨论】:

    • 我明白你的解释是怎么回事,我已经按照你的建议修改了代码,但仍然在做这种奇怪的行为。也许“clickListener”是如何完成的?我的意思是,我知道有更好的方法来实现 onclick,正如你所说,它只是“快速”的教育。稍后我将尝试对 onclicklistener 实现更好的近似
    • 哎呀哈哈,我忘了初始化绑定的可见性,但在这里我将提取以及清理它。请尝试以上方法
    • 哦,如果您正在执行 root.findViewById,则也不需要 notifyDataSetChanged,只需执行其中一项即可。通过 id 查找视图(更有效)或更新人员,然后调用 notifyDataSet Changed(不要同时执行)
    • 是的!终于奏效了!谢谢 :D 有点奇怪的行为.. 哈哈哈
    【解决方案2】:

    您的代码看起来不错,但可能是 RecyclerViews 的工作方式存在问题。我认为这发生在您身上,因为您只是更改了持有人的价值,并且持有人正在回收以保存不同的数据项。

    您可以尝试将布尔值imageHide 附加到您的 Person 类,然后在 onClick 中更改 person 类中的布尔值并设置图像的可见性。然后在 onBind 中有一些逻辑来检查该人是否应该隐藏或可见图像。

    【讨论】:

    • 我尝试将布尔值更改为模型,但仍然这样做:/
    【解决方案3】:

    您需要在 onBindViewHolder 上添加一个验证,如下所示:

    holder.image.setVisibility(holder.imageHide ?View.VISIBLE:View.INVISIBLE);
    

    问候。

    【讨论】:

    • 测试在“点击”中添加您的行,并“恢复”布尔标志。仍然在做同样的奇怪行为。
    • 您需要在点击监听器之外添加该行,然后将其添加到 onBindViewHolder
    • 如果我把点击放在外面,不会改变可见性
    • 也许我不太清楚,当您单击图像时,您必须将状态保存在持有人或 Person.java 上,以便在调用 onBindViewHolder 时检查该状态并更新视图。
    猜你喜欢
    • 2016-09-18
    • 1970-01-01
    • 1970-01-01
    • 2019-05-25
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多