Android:在RecyclerView中添加视图时的奇怪反应

时间:2016-04-17 15:28:07

标签: java android android-recyclerview

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

为什么每个视图都会向后移动一个位置然后再移回到原来的位置而不是不这样做?

这是我的适配器:

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



}

编辑:使用removeData(getAdapterPosition()

删除视图时也会发生同样的情况

1 个答案:

答案 0 :(得分:1)

为什么

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

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

解决方案

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

你可能需要做一些关于页眉和页脚放置在适配器中的内容,以确保它们在RecyclerView.Adapter中作为页眉和页脚保留但是... RecyclerView.LayoutManager在显示内容时反转。