RecyclerView 和 AdapterView,无法显示项目
RecyclerView and AdapterView, fails to show items
我正在做一些简单的示例,将它们作为指南等。我有一个带有自己的适配器的 RecyclerView。这些项目是数据模型,带有文本和图像。 ViewHolder除了包含相应的视图外,我还添加了一个布尔值来控制图像是否可见。
当我点击时,例如在第一项中,图像消失(或再次点击时出现)。
问题是,如果您单击(例如第一个元素)图像会按预期消失,但是当滚动并且回收器加载不可见的新元素时,一个元素突然出现并带有隐藏图像。
稍微调试一下,我看到加载元素时,depends 出现时布尔值为 true,而理论上应该为 false。
我不明白发生了什么,因为列表中的元素不同。
P.S: 正如我所说,代码真的很简单,所以不要指望有什么好东西。
主要活动:
@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>
以图片为例:
您的代码看起来不错,但这可能与 RecyclerViews 的工作方式有关。我认为这会发生在您身上,因为您只是在更改持有人的价值,而持有人正在 回收 以持有不同的数据项。
您能否尝试将布尔值 imageHide
附加到您的人物 class,然后在 onClick 中更改人物 class 中的布尔值并设置图像的可见性。然后在 onBind 中有一些逻辑来检查这个人是否应该隐藏或可见图像。
您需要在 onBindViewHolder 上添加验证,如下所示:
holder.image.setVisibility(holder.imageHide ?View.VISIBLE:View.INVISIBLE);
问候。
ViewHolder Class 旨在用于快速访问 "View" 相关项目,例如 textviews 或 imageViews 等性质的东西。
当内容需要基于对象模型是动态的时,对象模型需要驱动可见性模式。不是嵌套在取景器内的布尔值 class.
这样想。回收器视图回收 (n) 个视图。
--View 1 (shows person 1) boolean visible in viewholder 1
--View 2 (shows person 2) boolean visible in viewholder 1
--View 3 (shows person 3) boolean visible in viewholder 1
点击视图 1
--视图 1 -- 保存布尔值 false "image not visible"
点击后的当前视图
--View 1 (shows person 1) boolean invisible in viewholder 1
--View 2 (shows person 2) boolean visible in viewholder 1
--View 3 (shows person 3) boolean visible in viewholder 1
现在你滚动回收器
视图 1 离开屏幕并回收用于下一个屏幕,因为第 4 个人现在在观察者模式中保留布尔值
--View 2 (shows person 2) boolean visible in viewholder 2
--View 3 (shows person 3) boolean visible in viewholder 3
--View 1 (shows person 4) boolean invisible in 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();
}
});
}
然后将 root id 添加到你的 XML 文件和 viewholder class 如果你选择执行 findViewById 路由(推荐比通知更有效)
您的指南可能会考虑的另一件事是解释如何处理适配器外部的点击。如果我不进行数据绑定,我通常更喜欢接口。将此添加到适配器底部。
public interface ItemSelectedListener {
void personList_onItemClick(View view, int position, final Person person);
void personList_onItemLongClick(View view, int position, final Person person);
}
然后在构造函数中需要 ItemSelectedListener 并存储在适配器中 class。然后你可以修改你的 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);
}
我正在做一些简单的示例,将它们作为指南等。我有一个带有自己的适配器的 RecyclerView。这些项目是数据模型,带有文本和图像。 ViewHolder除了包含相应的视图外,我还添加了一个布尔值来控制图像是否可见。
当我点击时,例如在第一项中,图像消失(或再次点击时出现)。
问题是,如果您单击(例如第一个元素)图像会按预期消失,但是当滚动并且回收器加载不可见的新元素时,一个元素突然出现并带有隐藏图像。
稍微调试一下,我看到加载元素时,depends 出现时布尔值为 true,而理论上应该为 false。
我不明白发生了什么,因为列表中的元素不同。
P.S: 正如我所说,代码真的很简单,所以不要指望有什么好东西。
主要活动:
@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>
以图片为例:
您的代码看起来不错,但这可能与 RecyclerViews 的工作方式有关。我认为这会发生在您身上,因为您只是在更改持有人的价值,而持有人正在 回收 以持有不同的数据项。
您能否尝试将布尔值 imageHide
附加到您的人物 class,然后在 onClick 中更改人物 class 中的布尔值并设置图像的可见性。然后在 onBind 中有一些逻辑来检查这个人是否应该隐藏或可见图像。
您需要在 onBindViewHolder 上添加验证,如下所示:
holder.image.setVisibility(holder.imageHide ?View.VISIBLE:View.INVISIBLE);
问候。
ViewHolder Class 旨在用于快速访问 "View" 相关项目,例如 textviews 或 imageViews 等性质的东西。
当内容需要基于对象模型是动态的时,对象模型需要驱动可见性模式。不是嵌套在取景器内的布尔值 class.
这样想。回收器视图回收 (n) 个视图。
--View 1 (shows person 1) boolean visible in viewholder 1
--View 2 (shows person 2) boolean visible in viewholder 1
--View 3 (shows person 3) boolean visible in viewholder 1
点击视图 1
--视图 1 -- 保存布尔值 false "image not visible"
点击后的当前视图
--View 1 (shows person 1) boolean invisible in viewholder 1
--View 2 (shows person 2) boolean visible in viewholder 1
--View 3 (shows person 3) boolean visible in viewholder 1
现在你滚动回收器
视图 1 离开屏幕并回收用于下一个屏幕,因为第 4 个人现在在观察者模式中保留布尔值
--View 2 (shows person 2) boolean visible in viewholder 2
--View 3 (shows person 3) boolean visible in viewholder 3
--View 1 (shows person 4) boolean invisible in 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();
}
});
}
然后将 root id 添加到你的 XML 文件和 viewholder class 如果你选择执行 findViewById 路由(推荐比通知更有效)
您的指南可能会考虑的另一件事是解释如何处理适配器外部的点击。如果我不进行数据绑定,我通常更喜欢接口。将此添加到适配器底部。
public interface ItemSelectedListener {
void personList_onItemClick(View view, int position, final Person person);
void personList_onItemLongClick(View view, int position, final Person person);
}
然后在构造函数中需要 ItemSelectedListener 并存储在适配器中 class。然后你可以修改你的 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);
}