java - Android:在 RecyclerView 中添加 View 时出现奇怪的 react

标签 java android android-recyclerview

我正在使用一个自定义的 recyclerView,它可以有一个页脚和一个页眉,它应该不会影响动画,这里是一个正在发生的事情的视频:http://www.videosprout.com/video?id=00fae6ac-39ff-47b6-b981-803d2773b67b

为什么每个 View 都向后移动一个位置,然后又回到原来的位置,而不是不这样做?

这是我的适配器:

public class AddEventsAdapter extends HFRecyclerViewAdapter<String, AddEventsAdapter.ViewHolder> {

    public AddEventsAdapter(Context context) {
        super(context);
    }

    @Override
    public void footerOnVisibleItem() {

    }

    @Override
    public void addData(int position, String item) {
        super.addData(position, item);
    }

    @Override
    public ViewHolder onCreateDataItemViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.event_item, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindDataItemViewHolder(ViewHolder holder, int position) {
        holder.itemTv.setText(getData().get(position));
    }

    class ViewHolder extends RecyclerView.ViewHolder{
        TextView itemTv;
        public ViewHolder(View itemView) {
            super(itemView);
            itemTv = (TextView)itemView.findViewById(R.id.eventName);

        }
    }
}

实现:

    final AddEventsAdapter MyAdapter = new AddEventsAdapter(this);
    AddEventsRecycler.setAdapter(MyAdapter);
    AddEventsRecycler.setLayoutManager(new LinearLayoutManager(this));

    //add footer
    final View footerView = LayoutInflater.from(this).inflate(R.layout.events_footer, AddEventsRecycler, false);
    MyAdapter.setFooterView(footerView);

    footerView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            MyAdapter.addData(0, "Event number" + ++g);
        }
    });

    ArrayList<String> data = new ArrayList<>();
    data.add("Vacation");

    MyAdapter.setData(data);

自定义 RecyclerAdapter:

public abstract class HFRecyclerViewAdapter<T, VH extends RecyclerView.ViewHolder> extends BaseRecyclerViewAdapter<T> {

    public HFRecyclerViewAdapter(Context context) {
        super(context);
    }

    private static final int TYPE_HEADER = Integer.MAX_VALUE;
    private static final int TYPE_FOOTER = Integer.MAX_VALUE - 1;
    private static final int ITEM_MAX_TYPE = Integer.MAX_VALUE - 2;
    private RecyclerView.ViewHolder headerViewHolder;
    private RecyclerView.ViewHolder footerViewHolder;

    class HFViewHolder extends RecyclerView.ViewHolder {
        HFViewHolder(View v) {
            super(v);
        }
    }

    public void setHeaderView(View header){
        if (headerViewHolder == null || header != headerViewHolder.itemView) {
            headerViewHolder = new HFViewHolder(header);
            notifyDataSetChanged();
        }
    }

    public void setFooterView(View foot){
        if (footerViewHolder == null || foot != footerViewHolder.itemView) {
            footerViewHolder = new HFViewHolder(foot);
            notifyDataSetChanged();
        }
    }

    public void removeHeader(){
        if (headerViewHolder != null){
            headerViewHolder = null;
            notifyDataSetChanged();
        }
    }
    public void removeFooter(){
        if (footerViewHolder != null){
            footerViewHolder = null;
            notifyDataSetChanged();
        }
    }

    public boolean isHeader(int position){
        return hasHeader() && position == 0;
    }

    public boolean isFooter(int position){
        return hasFooter() && position == getDataItemCount() + (hasHeader() ? 1 : 0);
    }

    private int itemPositionInData(int rvPosition){
        return rvPosition - (hasHeader() ? 1 : 0);
    }
    private int itemPositionInRV(int dataPosition){
        return dataPosition + (hasHeader() ? 1 : 0);
    }

    @Override
    public void notifyMyItemInserted(int itemPosition) {
        notifyItemInserted(itemPositionInRV(itemPosition));
    }
    @Override
    public void notifyMyItemRemoved(int itemPosition) {
        notifyItemRemoved(itemPositionInRV(itemPosition));
    }

    @Override
    public void notifyMyItemChanged(int itemPosition) {
        notifyItemChanged(itemPositionInRV(itemPosition));
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_HEADER) {
            return headerViewHolder;
        } else if (viewType == TYPE_FOOTER) {
            return footerViewHolder;
        }
        return onCreateDataItemViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (!isHeader(position) && !isFooter(position))
            onBindDataItemViewHolder((VH)holder, itemPositionInData(position));

        if (isFooter(position)){
            footerOnVisibleItem();
        }
    }

    public abstract void footerOnVisibleItem();

    @Override
    public int getItemCount() {
        int itemCount = getDataItemCount();
        if (hasHeader()) {
            itemCount += 1;
        }
        if (hasFooter()) {
            itemCount += 1;
        }
        return itemCount;
    }

    @Override
    public int getItemViewType(int position) {
        if (isHeader(position)) {
            return TYPE_HEADER;
        }
        if (isFooter(position)) {
            return TYPE_FOOTER;
        }
        int dataItemType = getDataItemType(itemPositionInData(position));
        if (dataItemType > ITEM_MAX_TYPE) {
            throw new IllegalStateException("getDataItemType() must be less than " + ITEM_MAX_TYPE + ".");
        }
        return dataItemType;
    }

    public int getDataItemCount() {
        return super.getItemCount();
    }

    /**
     * make sure your dataItemType < Integer.MAX_VALUE-1
     *
     * @param position item view position in rv
     * @return item viewType
     */
    public int getDataItemType(int position){
        return 0;
    }


    public boolean hasHeader(){
        return headerViewHolder != null;
    }
    public boolean hasFooter(){
        return footerViewHolder != null;
    }

    public abstract VH onCreateDataItemViewHolder(ViewGroup parent, int viewType);

    public abstract void onBindDataItemViewHolder(VH holder, int position);



}

编辑: 删除 View 时会发生同样的情况,使用 removeData(getAdapterPosition()

最佳答案

为什么

这是因为元素被添加到数组的开头(索引 0)。发生这种情况时,RecyclerView 将做出视频中所示的 react ,因为它假装后备数据存储是一个列表,并且所有元素都移动到一个索引上,并且该元素被插入到开头...恰好在顶部。

您可以看到,如果在适配器末尾添加元素,它不会执行这种丑陋的行为:MyAdapter.addData(MyAdapter.getItemCount() - 1, "Event "); .但是当然,这也不是你想要的,因为它是错误的索引......现在看起来现有元素实际上在 GUI 和其他东西上跳了一个索引......但这是一个有趣的实验验证理论。

一个解决方案

仍然使用 MyAdapter.addData(MyAdapter.getItemCount() - 1, "Event "); 在数组末尾添加元素,但使 LinearLayoutManager 显示逆向元素!这可以通过以下方式完成:

您可能需要对位于适配器中的页眉和页脚做一些事情,以确保它们在 RecyclerView.Adapter 中保留为页眉和页脚,但是...一旦 RecyclerView .LayoutManager 正在反向显示内容。

关于java - Android:在 RecyclerView 中添加 View 时出现奇怪的 react ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36678466/

相关文章:

java - 使用 If 语句确定图像的 ColorModel?

android - 意外的行为改造+协程

java - Android - 读取大文本文件的更有效方法

android - 如何在初始化 recyclerview 适配器时保持 UI 解锁?

java - Spring 4 安全配置运行但未激活

java - 谷歌眼镜语音识别

java - 如何在数组中调用我存储的数据(字符串)?

java - android.view.InflateException : Binary XML file line #2: Binary XML file line #2: Error inflating class android. 部件.RelativeLayout

android - RecyclerView ItemTouchHelper 轻扫

android - 按像素垂直滚动 Android 中的 RecyclerView