Android RecyclerView:在notifyDataSetChanged之后更新所有项目的高度

时间:2017-08-25 14:58:20

标签: android android-recyclerview recycler-adapter

在我的适配器类的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()时,只有新项目获得新的高度。所有其他(已经存在的)物品都坚持旧的高度。

我应该在何处移动高度计算,以便在更新数据集时进行检查?

1 个答案:

答案 0 :(得分:1)

在RecyclerView中,当创建新视图对象并将其附加到父视图时, onCreateViewHolder()会被调用,当视图离开时会调用 onBindViewHolder()滚动屏幕,屏幕上出现新视图。

RecyclerAdapter.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);
    }
}

}

MainActivity.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();
        }
    });
}

}

enter image description here 目前,屏幕上只能显示6个项目。应用程序启动后立即

  

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()二月

     

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()4月

     

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()可能

     

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

最初,在创建视图时,会为每个视图调用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()7月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onCreateViewHolder()7

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onBindViewHolder()八月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onCreateViewHolder()7

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onBindViewHolder()9月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onCreateViewHolder()7

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onBindViewHolder()十月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onViewRecycled()1月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onBindViewHolder()11月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onViewRecycled()二月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onBindViewHolder()12月

     

28518-28518 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:    onViewRecycled()March

因此, onCreateViewHolder()在第8个视图后停止调用,而是调用 onViewRecycled(),它使用相同的视图,而不是屏幕创建一个新视图。 现在,当我们回滚到顶部时:

  

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()12月

     

08-26 21:54:21.471 28518-28518 / com.stabstudio.aftera nimation   D / RECYCLER_CALLBACKS: onBindViewHolder()二月

     

08-26 21:54:21.835 28518-28518 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS: onViewRecycled()11月

     

08-26 21:54:22.277 28518-28518 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS: onBindViewHolder()1月

     

08-26 21:54:26.050 28518-28518 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS: onViewRecycled()十月

当我们向上滚动时,12月首先退出屏幕,3月进入屏幕。所以,

  1. 12月被回收利用回调来回到三月 onViewRecycled()12月 onBindViewHolder() 3月。
  2. 同样地,十一月被回收,而二月来到了它的位置 回调 onViewRecycled()11月 onBindViewHolder() 二月即可。
  3. 最后, onViewRecycled()十月 onBindViewHolder()一月
  4. 现在,当我们创建一个新月时,我们调用 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()7月   2597-2597 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:   onBindViewHolder()8月2597-2597 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS:onBindViewHolder()9月   2597-2597 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:   onBindViewHolder()10月2597-2597 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS:onBindViewHolder()11月   2597-2597 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:   onCreateViewHolder()5 2597-2597 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS:onBindViewHolder()12月   2597-2597 / com.stabstudio.afteranimation D / RECYCLER_CALLBACKS:   onCreateViewHolder()6 2597-2597 / com.stabstudio.afteranimation   D / RECYCLER_CALLBACKS:onBindViewHolder()新月1

    调用 notifyDataSetChanged()后,所有视图都会被回收, onCreateViewHolder()会再次被调用显示的项目数量在屏幕+ 2 。屏幕底部1,屏幕底部1,不可见。在这种情况下,无论 RecyclerView 中有多少项,它只有8次。

    所以,你应该将高度计算移动到 onBindViewHolder(),它将被调用所有视图而不是onCreateViewHolder(),它只被调用的次数与屏幕中可见的项目数一样多