RecyclerView和AdapterView无法显示项

时间:2017-09-18 18:44:41

标签: android android-recyclerview onclicklistener android-adapter recycler-adapter

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

当我点击时,例如在第一个项目中,图像消失(或者如果再次点击则显示)。

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

稍微调试一下,我看到在加载元素时,依赖于boolean为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>

以图片为例:

enter image description here

enter image description here

3 个答案:

答案 0 :(得分:1)

ViewHolder类旨在用于快速访问&#34; View&#34;相关项目,例如textview或imageViews那种性质的东西。

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

这样想。回收者视图回收(n)次数。

- 在视图1中查看1(显示人1)布尔可见

- 在视图1中查看2(显示人2)布尔值可见

- 在视图1中查看3(显示人3)布尔值可见

点击查看1

- 视图1 - 保存布尔值假&#34;图像不可见&#34;

点击后的当前视图

- 在视图符号1中查看1(显示人1)布尔不可见

- 在视图1中查看2(显示人2)布尔值可见

- 在视图1中查看3(显示人3)布尔值可见

现在滚动回收器

视图1在屏幕外显示并在屏幕上显示,因为Person 4现在在视图模式中保留了布尔值

- 在视图2中查看2(显示人2)布尔值可见

- 视图3(显示人3)布尔值在视图3中可见

- 在视图1中查看1(显示人4)布尔不可见

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

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文件和viewholder类(建议更高效,然后通知)

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

 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;

        }

    });

}

当然也可以将监听器添加到你的bindview中以便长按

@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);
    }

答案 1 :(得分:0)

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

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

答案 2 :(得分:-1)

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

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

问候。