在我的适配器类的 onCreateViewHolder
中,我将屏幕的总高度分布在我拥有的项目上,如下所示:
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_card, parent, false);
// float weight = 1 / (mCards.size() * 1.0f);
// LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, weight);
// view.setMinimumHeight(params.height);
int height = parent.getMeasuredHeight() / mCards.size();
view.setMinimumHeight(height - 15);
return new ViewHolder(view, listener);
}
但是当我调用 adapter.notifyDataSetChanged()
时,只有新项目获得新高度。所有其他(已经存在的)项目都保持旧高度。
我应该把高度计算移到哪里才能在数据集更新时检查它?
最佳答案
在 RecyclerView 中,onCreateViewHolder() 在创建新 View 对象并附加到父 View 时被调用,onBindViewHolder() 在 View 离开时被调用滚动屏幕,屏幕上会出现一个新 View 。
回收适配器.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder>{
private Context context;
private ArrayList<String> months = new ArrayList<>();
public RecyclerAdapter(Context context, ArrayList<String> months){
this.context = context;
this.months = months;
}
@Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View vi = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
Log.d("RECYCLER_CALLBACKS", "onCreateViewHolder() " + parent.getChildCount());
return new ViewHolder(vi);
}
@Override
public void onBindViewHolder(RecyclerAdapter.ViewHolder holder, int position) {
holder.month.setText(months.get(position));
Log.d("RECYCLER_CALLBACKS", "onBindViewHolder() " + months.get(holder.getAdapterPosition()));
}
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
Log.d("RECYCLER_CALLBACKS", "onViewRecycled() " + months.get(holder.getAdapterPosition()));
}
@Override
public int getItemCount() {
return months.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private CardView cardView;
private TextView month;
private TextView date;
public ViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.cardView);
month = (TextView) itemView.findViewById(R.id.textView2);
date = (TextView) itemView.findViewById(R.id.textView3);
}
}
主 Activity .java
public class MainActivity extends AppCompatActivity {
private Button button;
private RecyclerView recyclerView;
private LinearLayoutManager layoutManager;
private RecyclerAdapter adapter;
private static int MONTH_COUNT = 1;
private ArrayList<String> monthsList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
monthsList.add("January");
monthsList.add("February");
monthsList.add("March");
monthsList.add("April");
monthsList.add("May");
monthsList.add("June");
monthsList.add("July");
monthsList.add("August");
monthsList.add("September");
monthsList.add("October");
monthsList.add("November");
monthsList.add("December");
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerAdapter(this, monthsList);
recyclerView.setAdapter(adapter);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
monthsList.add("New Month " + MONTH_COUNT);
MONTH_COUNT++;
adapter.notifyDataSetChanged();
}
});
}
08-26 21:32:23.547 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 0
08-26 21:32:23.557 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 1
08-26 21:32:23.557 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() February
08-26 21:32:23.563 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 2
08-26 21:32:23.563 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() March
08-26 21:32:23.569 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 3
08-26 21:32:23.569 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() April
08-26 21:32:23.575 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 4
08-26 21:32:23.575 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() May
08-26 21:32:23.581 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 5
08-26 21:32:23.581 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() June
最初,在创建 View 时,会为每个 View 调用 onCreateViewHolder() 和 onBindViewHolder()。当我们向下滚动到底部时
08-26 21:37:36.579 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 6
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() July
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 7
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() August
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 7
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() September
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 7
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() October
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() January
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() November
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() February
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() December
28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() March
因此,onCreateViewHolder() 在第 8 个 View 后停止调用,而是调用 onViewRecycled()创建一个新 View 。 现在,当我们滚动回顶部时:
08-26 21:54:20.262 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() March
08-26 21:54:20.784 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() December
08-26 21:54:21.471 28518-28518/com.stabstudio.aftera nimation D/RECYCLER_CALLBACKS: onBindViewHolder() February
08-26 21:54:21.835 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() November
08-26 21:54:22.277 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() January
08-26 21:54:26.050 28518-28518/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() October
当我们向上滚动时,十二月首先离开屏幕,三月进入屏幕。所以,
- 12 月被回收,以通过回调让位于 3 月 onViewRecycled() 十二月 和 onBindViewHolder() 三月。
- 同样,11 月被回收,2 月取而代之 回调 onViewRecycled() November 和 onBindViewHolder() 二月。
- 最后,onViewRecycled() 十月 和 onBindViewHolder() 一月。
现在,当我们创建一个新的月份时,我们调用 notifyDataSetChanged() 将更改报告给适配器:
2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() 5 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() 4 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() 3 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() -1 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() -1 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() -1 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() -1 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() -1 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onViewRecycled() -1 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() July 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() August 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() September 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() October 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() November 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 5 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() December 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onCreateViewHolder() 6 2597-2597/com.stabstudio.afteranimation D/RECYCLER_CALLBACKS: onBindViewHolder() New Month 1
一旦 notifyDataSetChanged() 被调用,所有的 View 都会被回收,并且 onCreateViewHolder() 会被再次调用,次数与显示的数量相同在屏幕上 + 2。 1 个在屏幕顶部,1 个在屏幕底部,这是不可见的。在本例中,无论 RecyclerView 中有多少项,它都只有 8 次。
因此,您应该将高度计算移至 onBindViewHolder(),它会在所有 View 中被调用,而不是 onCreateViewHolder(),后者仅被调用与屏幕上可见项目的数量一样多.
关于Android RecyclerView : Update all items height after notifyDataSetChanged,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45884240/