Android—RecyclerView带你飞

1、RecyclerView是什么?

  根据Googl给出的说明:“能够在有限的窗口中展示大数据集合的灵活视图”
  RecyclerView看上去和我们一直用的ListVIew可以说很是一样,但是我们为什么还要用RecyclerView呢?
  首先我们先来看一个场景,由于尺寸限制,用户的设备不能以此性展示所有条目,用户需要上下滚动查看会更多的的条目。滚出可见区域的条目将被回收,并在下一条目可见的时候被复用。
  在这个场景可以知道,RecyclertView的缓存可以更大的减少内存的开销和CPU的计算,这意味着我们不用每次都创建新的条目,这样就大大的减少了内存开销和CPU的计算。,有效的降低屏幕的卡顿,保证滑动的顺滑。
  说了半天你们会说还是没有说明白和LIstView的区别,毕竟我们用ListView很长一段时间了,其实在应用RecyclerView的时候,RecyclerView只管回收和复用View,其他的我们自己去设置。可以根据开发者的需要去设置任何样式的的动画和布局View,可以很轻松的实现LsitView和GirdView,瀑布流的效果。

2、引入RecyclerView

  我们在应用RecyclerView的时候,需要添加依赖。
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
在添加依赖的时候这两个依赖包的版本号要统一,否则会报错。

3、在布局文件中应用RecyclerView

  
<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />


4、使用RecyclerView

我们先来了解一下RecyclerView中几个重要的类,都是内部类
Class功能
Adapter处理数据集合并负责绑定数据
ViewHolder持有所有的用于绑定数据或者需要操作的View
LayoutManager负责摆放视图等相关操作
ItemDecoration负责绘制Item附近的分割线
ItemAnimator为Item的一般操作添加动画效果

4.1RecyclerView.ViewHolder

这里的ViewHolder和ListVIew里面的ViewHolder差不多是一样的,但是在ListView中,并没有强制我们使用ViewHolder,但是在RecyclerView中,Google强制我们必须使用ViewHolder这种模式。(不了解ViewHolder可以去查一下,网上有很多说明,面试重点)
在RecycleView中的ViewHolder子类可以通过访问公共成员itemView来访问ViewHolder的根视图,所以不需要再ViewHolder子类中存储。
public static class MyViewHolder extends RecyclerView.ViewHolder {

    TextView tv;

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

4.2、Adapter

adapter有两个功能。一.根据不同Viewtype创建与之相应的Item-Layout,二.访问数据集合并将数据绑定到正确的View上。在实现这两个方面的时候,需要我们重写三个方法:
。public VH onCreateViewHolder(ViewGroup parent,int ViewType)创建Item视图,并返回相应的ViewHolder
。public void onBindViewHolder(VH holder,int position)绑定数据到正确的Item视图上
。public int getItemCount()返回该Adapter所持有的item数量
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)
            .inflate(R.layout.item_recycler_view, parent, false));
    return holder;
}

@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
    holder.tv.setText(mDatas.get(position));
}

@Override
public int getItemCount() {
    return mDatas.size();
}

4.3、RecyclerView.LayoutManager

LayoutManager的职责是摆放Item的位置,并且负责决定何时回收和重用item。他有一个默认的实现:LinearLayoutManager,他可以用于垂直和水平列表。RecycleVIew.LayoutManager是一个抽象类,RecycleView提供了三个实现类:
1、LinearlayoutManager现行管理器,支持横向,纵向。
2、GridLayoutManager网格布局管理器
3、StaggeredGridLayoutManager瀑布流式布局管理器
     4.3.1LinearlayoutManager
LinearlayoutManager是LayoutManager的默认实现。可以使用这个类来创建垂直或水平列表

设置纵向布局
LinearLayoutManager layoutManager= new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
设置横向布局
LinearLayoutManager layoutManager= new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
在LinearLayoutManager中还有一些很实用的API:
。findFirstVisibleItemPosition()返回当前第一个可见的Item的position
。findLastVisibleItemPosition()返回当前最后一个可见的Item的position
。findFirstCompletelyVisibleItemPosition()返回当前的第一个完全可见的Item的position
。findLastCompletelyVisibleItemPosition()返回当前最后一个完全可见Item的position
剩下的两个RecycleView的实现类就不多说了,大家可以查看官方文档,很简单。

4.4、RecyclerView.ItemDecoration

设置:
// 给纵向显示RecyclerView设置分割线
recyclerView.addItemDecoration(new DividerItemDecoration(activity, DividerItemDecoration.VERTICAL));
// 给横向显示RecyclerView设置分割线
recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecoration.HORIZONTAL));
当然,我们也可以对RecyclerView设置多个ItemDecoration,列表展示的时候会遍历所有的ItemDecoration并调用里面的绘制方法,对Item进行装饰。
RecyclerView.ItemDecoration也是一个抽象类,重写他的三个方法来实现Item之间的偏移量或者装饰效果:
。public void onDraw(Canvas c,RecyclerView parent)装饰的绘制在Item条目绘制之前调用,所以这有可能被Item的内容所遮挡
。public void onDrawOver(Canvas c,RecyclerView  parent)装饰的绘制在Item条目绘制之后调用,因此装饰奖浮于Item之上
。public void getItemOffsets(Rect outRect,int itemPositon,RecyclerView parent)和padding或者margin类似,LayoutManager在测量阶段会调用这个方法,计算出每一个Item的正确尺寸并设置偏移量。

4.5、RecyclerView.ItemAnimator

ItemAnimator能够帮助Item实现独立的动画。我们可以通过以下代码为Item增加动画效果:
	recyclerView.setItemAnimator(new DefaultItemAnimator());
在之前我们开发过程中,表中的集合发生改变的时候,我们通过调用.notifyDataSetChanged()来刷新列表,这样做会触发列表重绘,所以并不会出现任何动画效果,因此需要调用一些以notifyItem*()最为作为前缀的特殊方法。
。public final void notifyItemInserted(int  position)向指定位置插入Item
。public final void notifyItemRemoved(int position)移除指定位置的Item
。public final void notifyItemChanged(int position)更新指定位置Item
例:
btnAdd.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        adapter.addData(1);
    }
});

btnRemove.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        adapter.removeData(2);
    }
});
在适配器中添加两个方法:
public void addData(int position) {
    mDatas.add(position, "新添加的");
    mHeights.add( (int) (100 + Math.random() * 300));
    notifyItemInserted(position);
}

public void removeData(int position) {
    mDatas.remove(position);
    notifyItemRemoved(position);
}
下面给大家上一下全部代码:
public class MainActivity extends Activity {
    private Activity activity;
    private Button btnAdd,btnRemove;
    private RecyclerView recyclerView;
    private RecyclerAdapter adapter;
    private List<String> mDatas = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        activity = this;
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        btnAdd = (Button) findViewById(R.id.btn_add);
        btnRemove = (Button) findViewById(R.id.btn_remove);

        initDatas();
        adapter = new RecyclerAdapter(activity,mDatas);

        // 设置RecyclerView布局方式为纵向布局
//        LinearLayoutManager layoutManager= new LinearLayoutManager(this);
//        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//        recyclerView.setLayoutManager(layoutManager);

        // 设置RecyclerView布局方式为横向布局
//        LinearLayoutManager layoutManager= new LinearLayoutManager(this);
//        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//        recyclerView.setLayoutManager(layoutManager);

        // 设置纵向的4列的表格布局
//        GridLayoutManager layoutManager = new GridLayoutManager(this,4,GridLayoutManager.VERTICAL,false);
//        recyclerView.setLayoutManager(layoutManager);
//        recyclerView.addItemDecoration(new DividerGridItemDecoration(activity));l

        // 设置横向的3行的表格布局
//        GridLayoutManager layoutManager = new GridLayoutManager(this,3,GridLayoutManager.HORIZONTAL,false);
//        recyclerView.setLayoutManager(layoutManager);

        // 给纵向显示RecyclerView设置分割线
//        recyclerView.addItemDecoration(new DividerItemDecoration(activity, DividerItemDecoration.VERTICAL));
        // 给横向显示RecyclerView设置分割线
//        recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecoration.HORIZONTAL));

        // 设置纵向的瀑布流布局
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        // 给RecyclerView设置默认动画效果
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        adapter.setLitener(new RecyclerAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(activity,"第"+(position+1)+"项被点击了",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(activity,"第"+(position+1)+"项被长按了",Toast.LENGTH_SHORT).show();
            }
        });

        recyclerView.setAdapter(adapter);

        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                adapter.addData(1);
            }
        });

        btnRemove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                adapter.removeData(2);
            }
        });
    }

    private void initDatas(){
        for (int i = 0;i<50;i++){
            mDatas.add(String.valueOf(i+1));
        }
    }

}
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
    private Context context;
    private List<String> mDatas;
    private List<Integer> mHeights;

    public RecyclerAdapter(Context context, List<String> mDatas) {
        this.context = context;
        this.mDatas = mDatas;
        mHeights = new ArrayList<Integer>();
        for (int i = 0; i < mDatas.size(); i++) {
            mHeights.add((int) (100 + Math.random() * 300));
        }
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)
                .inflate(R.layout.item_recycler_view, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
        lp.height = mHeights.get(position);
        holder.tv.setLayoutParams(lp);

        holder.tv.setText(mDatas.get(position));
        // 如果设置了回调,则响应点击事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (litener != null) {
                    litener.onItemClick(v, position);
                }
            }
        });

        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (litener != null) {
                    litener.onItemLongClick(v, position);
                }
                return false;
            }
        });
    }

    @Override
    public int getItemCount() {
        return mDatas == null ? 0 : mDatas.size();
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView tv;

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

    public void addData(int position) {
        mDatas.add(position, "新添加的");
        mHeights.add( (int) (100 + Math.random() * 300));
        notifyItemInserted(position);
    }
    
    public void removeData(int position) {
        mDatas.remove(position);
        notifyItemRemoved(position);
    }

    public interface OnItemClickLitener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickLitener litener;

    public void setLitener(OnItemClickLitener litener) {
        this.litener = litener;
    }
}
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    private Drawable mDivider;

    public DividerGridItemDecoration(Context context) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, State state) {

        drawHorizontal(c, parent);
        drawVertical(c, parent);

    }

    private int getSpanCount(RecyclerView parent) {
        // 列数
        int spanCount = -1;
        LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {

            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            spanCount = ((StaggeredGridLayoutManager) layoutManager)
                    .getSpanCount();
        }
        return spanCount;
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin
                    + mDivider.getIntrinsicWidth();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);

            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicWidth();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
                                int childCount) {
        LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
            {
                return true;
            }
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
                {
                    return true;
                }
            } else {
                childCount = childCount - childCount % spanCount;
                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
                    return true;
            }
        }
        return false;
    }

    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
                              int childCount) {
        LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            childCount = childCount - childCount % spanCount;
            if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
                return true;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            int orientation = ((StaggeredGridLayoutManager) layoutManager)
                    .getOrientation();
            // StaggeredGridLayoutManager 且纵向滚动
            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
                childCount = childCount - childCount % spanCount;
                // 如果是最后一行,则不需要绘制底部
                if (pos >= childCount)
                    return true;
            } else
            // StaggeredGridLayoutManager 且横向滚动
            {
                // 如果是最后一行,则不需要绘制底部
                if ((pos + 1) % spanCount == 0) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void getItemOffsets(Rect outRect, int itemPosition,
                               RecyclerView parent) {
        int spanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();
        if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
        {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
        {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(),
                    mDivider.getIntrinsicHeight());
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值