封装RecyclerView添加头的适配器与嵌套ScrollView时的滑动冲突卡顿以及动画的添加

1.当RecyclerView嵌套在ScrollView里,滑动的时候会比较卡顿,解决办法

linearLayoutManager = new LinearLayoutManager(getActivity()) {
            @Override
            public boolean canScrollVertically() {
                return false;//解决RecyclerView嵌套ScrollView时滑动卡顿的问题
            }
        };
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);

然后在recyclerview的父布局加上:android:descendantFocusability="blocksDescendants"  

<RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:descendantFocusability="blocksDescendants">
                <android.support.v7.widget.RecyclerView
                    android:background="@color/white"
                    android:id="@+id/recyclerView_single"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </RelativeLayout>

 

 

 

2.对RecyclerView添加头的封装,当然,你可以同理,继续增加添加尾的封装

/**
 * RecyclerView的 基本适配器
 */
public abstract class MyBaseAdapter extends RecyclerView.Adapter{

    /**
     * 头
     */
    public View headerView;
    /**
     * 头的类型
     */
    private final int HEADER_TYPE = 10000;
    private OnRecyclerItemClickListener mOnItemClickListener;

    /**
     * 添加头
     * @param header
     */
    public void addHeaderView(View header){
        this.headerView = header;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == HEADER_TYPE){
            return new HeaderViewHolder(headerView);
        }else{
            return onCreateViewHolder_my(parent, viewType);
        }
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
        int itemViewType = getItemViewType(position);
        if(itemViewType == HEADER_TYPE){
            return;
        }
        if(headerView == null){
            onBindViewHolder_my(holder,position);
        }else{
            onBindViewHolder_my(holder,position - 1);
        }
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mOnItemClickListener != null){
                    if(headerView == null){
                        mOnItemClickListener.onItemClick(view,holder.getLayoutPosition());
                    }else{
                        mOnItemClickListener.onItemClick(view,holder.getLayoutPosition() - 1);
                    }
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        if(headerView == null){
            return getData().size();
        }
        return getData().size() + 1;
    }

    @Override
    public int getItemViewType(int position) {
        if(headerView == null){
            return getItemViewType_my(position);
        }else {
            //有头
            if(position == 0){
                return HEADER_TYPE;
            }else{
                return getItemViewType_my(position - 1);//除去头
            }
        }
    }

    /**
     * 头
     */
    private class HeaderViewHolder extends RecyclerView.ViewHolder {
        public HeaderViewHolder(View itemView) {
            super(itemView);
        }
    }

    /**
     * 针对GridLayoutManager,解决添加的头不会单独占据一行
     * @param recyclerView
     */
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){
                @Override
                public int getSpanSize(int position)
                {
                    int viewType = getItemViewType(position);
                    if (viewType == HEADER_TYPE) {
                        return gridLayoutManager.getSpanCount();//跨距整个列数
                    }
                    return 1;//正常情况为1列
                }
            });
            gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
        }
    }

    public abstract List getData();

    /**
     * 头类型  使用的10000 不同就行
     * @param position  不用管包不包括头
     * @return
     */
    public abstract int getItemViewType_my(int position);

    public abstract RecyclerView.ViewHolder onCreateViewHolder_my(ViewGroup parent, int viewType);

    public abstract void onBindViewHolder_my(RecyclerView.ViewHolder holder, int position);

    /**
     * 处理item的点击事件
     */
    public interface OnRecyclerItemClickListener {
        void onItemClick(View view, int position);//点击的View,适配器中的索引position
    }


    /**
     * 暴露给外面的设置单击事件
     */
    public void setOnItemClickListener(OnRecyclerItemClickListener onItemClickListener){
        mOnItemClickListener = onItemClickListener;
    }
}

使用方法还是跟之前一样,不需要管有没有头对position的影响,测试适配器如下

public class TestAdapter extends MyBaseAdapter {

    private List<String> data;
    private Context context;

    public TestAdapter(List<String> data, Context context) {
        this.data = data;
        this.context = context;
    }

    @Override
    public List getData() {
        return data;
    }

    @Override
    public int getItemViewType_my(int position) {
        return 0;//如果没有多布局,返回0就行了
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder_my(ViewGroup parent, int viewType) {
        View inflate = LayoutInflater.from(context).inflate(R.layout.recycler_item_layout, parent, false);
        return new MyViewHolder(inflate);
    }

    @Override
    public void onBindViewHolder_my(RecyclerView.ViewHolder holder, int position) {
        MyViewHolder myHolder = (MyViewHolder) holder;
        myHolder.textView.setText(data.get(position));
    }

    class MyViewHolder extends RecyclerView.ViewHolder{

        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.textView);
        }
    }
}

使用:

mDatas = new ArrayList<String>();
testAdapter = new TestAdapter(mDatas,this);
View headerView = View.inflate(this, R.layout.recycler_item_layout, null);
TextView textView = headerView.findViewById(R.id.textView);
textView.setText("我是头啊");
testAdapter.addHeaderView(headerView);//添加头
testAdapter.setOnItemClickListener(new MyBaseAdapter.OnRecyclerItemClickListener() {
     @Override
     public void onItemClick(View view, int position) {
          ToastUtils.showToast("点击了=" + mDatas.get(position));
     }
});
//recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setLayoutManager(new GridLayoutManager(this,3));
recyclerView.setAdapter(testAdapter);

3.为RecyclerView添加 滑动时,item进入屏幕的动画     跟上面相比,其实也就是增加了三个方法

public class TestAdapter extends MyBaseAdapter {

    private List<String> data;
    private Context context;
    private LinearLayoutManager linearLayoutManager;

    /**
     * 用来记录最后一个执行动画的索引  当刷新数据的时候,需要将该值值零(不然动画将不一致)
     */
    private int mLastPosition = 0;

    public TestAdapter(List<String> data, Context context,LinearLayoutManager linearLayoutManager) {
        this.data = data;
        this.context = context;
        this.linearLayoutManager = linearLayoutManager;
    }

    @Override
    public List getData() {
        return data;
    }

    @Override
    public int getItemViewType_my(int position) {
        return 0;//如果没有多布局,返回0就行了
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder_my(ViewGroup parent, int viewType) {
        View inflate = LayoutInflater.from(context).inflate(R.layout.recycler_item_layout, parent, false);
        return new MyViewHolder(inflate);
    }

    @Override
    public void onBindViewHolder_my(RecyclerView.ViewHolder holder, int position) {
        MyViewHolder myHolder = (MyViewHolder) holder;
        myHolder.textView.setText(data.get(position));

        int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();

        if(position < mLastPosition && position > firstVisibleItemPosition){
            LogUtil.e("上拉加载更新notifyDataSetChanged()后,之前显示的item不再执行动画");
        }else{
            //添加动画
            setAnimation(holder.itemView, position);
        }
    }

    /**
     *  将动画对象加入集合中  根据左右滑动加入不同
     */
    private void setAnimation(View view, int position) {
        if (position >= mLastPosition) {
            // 执行底部的item进入屏幕的动画
            Animation animation = AnimationUtils.loadAnimation(view.getContext(), R.anim.item_slide_bottom_up);
            view.startAnimation(animation);
            mLastPosition = position;
        }else{
            // 执行顶部的item进入屏幕的动画
            Animation animation = AnimationUtils.loadAnimation(view.getContext(), R.anim.item_slide_top_down);//上面进入屏幕的动画
            view.startAnimation(animation);
            mLastPosition = position;
        }
    }

    /**
     * 将离开屏幕的item,清除动画,防止快速滑动时数据错乱与卡屏
     * @param holder
     */
    @Override
    public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        holder.itemView.clearAnimation();
    }


    class MyViewHolder extends RecyclerView.ViewHolder{

        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.textView);
        }
    }

}

使用如下:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        testAdapter = new TestAdapter(mDatas,this,linearLayoutManager);
        View headerView = View.inflate(this, R.layout.recycler_item_layout, null);
        TextView textView = (TextView) headerView.findViewById(R.id.textView);
        textView.setText("我是头啊");
        testAdapter.addHeaderView(headerView);
        testAdapter.setOnItemClickListener(new MyBaseAdapter.OnRecyclerItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                ToastUtils.showToast("点击了=" + mDatas.get(position));
            }
        });
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(testAdapter);

动画文件:

item_slide_bottom_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="100%"
        android:toXDelta="0%"
        android:fromYDelta="100%"
        android:toYDelta="0%"
        android:duration="1000"/>

    <alpha android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="1000"/>
</set>

item_slide_top_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="-100%"
        android:toXDelta="0%"
        android:fromYDelta="-100%"
        android:toYDelta="0%"
        android:duration="1000"/>

    <alpha android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="1000"/>
</set>

效果图:当第二次刷新时,第一条item的动画是从上往下的,所以为了避免这个问题,在刷新的时候需要手动将 mLastPosition=0 (切记)

 

posted @ 2017-07-22 10:32  ts-android  阅读(532)  评论(0编辑  收藏  举报