[Android开发]从Android官方Demo谈RecyclerView的用法
来源:互联网 发布:mysql w10 编辑:程序博客网 时间:2024/06/09 16:40
RecyclerView是Android5.0中出现的新控件,官方API解释就一句话:
A flexible view for providing a limited window into a large data set
整体架构如下图:
RecyclerView的灵活性体现在6个方面:
- 可以控制显示方式,包括三个内置的不觉管理器,也可以定制
- LinearLayoutManager 以垂直或水平滚动列表方式显示项目
- GridLayoutManager 在网格中显示项目
- StaggeredGridLayoutManager 瀑布了流中显示项目
- 默认情况下显示增加删除的动画,也扩RecyclerView.ItemAnimator定制
- 默认情况无分割线,可以扩展ItemDecoration定制
参考资料
官方API
官方Training:创建列表与卡片
深入理解 RecyclerView 系列之一:ItemDecoration
Android RecyclerView 使用完全解析 体验艺术般的控件
官方Demo效果
官方提供了一个Demo(github地址)的运行效果是这样的:
代码比较简单,重要的内容包括RecyclerView的初始化和其对应的Adapter的构造。
引申需求
设置分割线
分割线官方并没有提供默认的类型,默认也并没有分隔线。要提供分隔线必须自己实现RecyclerView.ItemDecoration。
/** * An ItemDecoration allows the application to add a special drawing and layout offset * to specific item views from the adapter's data set. This can be useful for drawing dividers * between items, highlights, visual grouping boundaries and more. * * <p>All ItemDecorations are drawn in the order they were added, before the item * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()} * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView, * RecyclerView.State)}.</p> */public static abstract class ItemDecoration { /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView */ public void onDraw(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } /** * @deprecated * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)} */ @Deprecated public void onDraw(Canvas c, RecyclerView parent) { } /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn after the item views are drawn * and will thus appear over the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView. */ public void onDrawOver(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } /** * @deprecated * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)} */ @Deprecated public void onDrawOver(Canvas c, RecyclerView parent) { } /** * @deprecated * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)} */ @Deprecated public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { outRect.set(0, 0, 0, 0); } /** * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies * the number of pixels that the item view should be inset by, similar to padding or margin. * The default implementation sets the bounds of outRect to 0 and returns. * * <p> * If this ItemDecoration does not affect the positioning of item views, it should set * all four fields of <code>outRect</code> (left, top, right, bottom) to zero * before returning. * * <p> * If you need to access Adapter for additional data, you can call * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the * View. * * @param outRect Rect to receive the output. * @param view The child view to decorate * @param parent RecyclerView this ItemDecoration is decorating * @param state The current state of RecyclerView. */ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); }}
这里参考深入理解 RecyclerView 系列之一:ItemDecoration(http://www.tuicool.com/articles/fIbuYfI)来实现该接口。
import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;/** * 参考:https://android.googlesource.com/platform/development/+/master/samples/Support7Demos/src * /com/example/android/supportv7/widget/decorator/DividerItemDecoration.java#101 */public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDraw(Canvas c, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); 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 left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } /** * outRect是用来设置left、top、right、bottom的padding值的 * */ @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } }}
点击事件
RecyclerView本身不提供单击和长按事件,需要自己实现。分为几个步骤。
第一步,需要在CustomAdapter中自己定义回调接口。
/** * 点击事件接口 * */ public interface OnItemClickListener{ void onItemClick(View view,int position); void onItemLongClick(View view,int position); } private OnItemClickListener onItemClickListener; public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; }
第二步,在CustomAdapter中的onBindViewHolder(ViewHolder viewHolder, final int position)中调用接口函数。
@Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { Log.d(TAG, "Element " + position + " set."); // Get element from your dataset at this position and replace the contents of the view // with that element viewHolder.getTextView().setText(mDataSet[position]); viewHolder.setColor(position); if (onItemClickListener!=null){ //可以获得每个item的包装类itemView viewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onItemClickListener.onItemClick(v,position); } }); viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { onItemClickListener.onItemLongClick(v,position); return true; } }); } }
第三步,在CustomAdapter初始化的地方传入该接口实例。
mAdapter.setOnItemClickListener(new CustomAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { ××××单击事件×××××× } @Override public void onItemLongClick(View view, int position) { ××××长按事件×××××× } });
多选模式
多选模式可以采用ActionMode来进行UI设计,本质上是通过长按进入ActionMode模式,可以点击按钮取消多选模式。
这里配合上面的点击事件,仅仅模拟了多选的操作,而没有添加ActionMode。
mAdapter.setOnItemClickListener(new CustomAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { if (isOnLonCliked){ addOrRemove(position); Log.i(TAG, position+"OnLonCliked"); }else { Toast.makeText(getActivity(),position+" clicked",Toast.LENGTH_LONG).show(); } } @Override public void onItemLongClick(View view, int position) { isOnLonCliked=true; Log.i(TAG, position+"OnLonCliked"); }});
其中,addOrRemove(int position)多选的逻辑。
** * 模拟多选情况 * */private void addOrRemove(int position){ if(mAdapter.positionSet.contains(position)){ mAdapter.positionSet.remove(position); }else { mAdapter.positionSet.add(position); } if (mAdapter.positionSet.size()==0){ isOnLonCliked=false; } mAdapter.notifyDataSetChanged();}
CustomAdapter中有一个集合在记录多选模式下已经点选的位置,点击时判断该集合是否包含了该位置,如果已经包含,就取消颜色,否则改变颜色。
/** * Provide views to RecyclerView with data from mDataSet. */ ××××××省略无关代码×××××××××××××× public static Set<Integer> positionSet = new HashSet<>(); // BEGIN_INCLUDE(recyclerViewSampleViewHolder) /** * Provide a reference to the type of views that you are using (custom ViewHolder) */ public static class ViewHolder extends RecyclerView.ViewHolder { public final TextView textView; public ViewHolder(View v) { super(v); // Define click listener for the ViewHolder's View. v.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "Element " + getAdapterPosition() + " clicked."); } }); textView = (TextView) v.findViewById(R.id.textView); Log.d(TAG, "ViewHolder "); } public TextView getTextView() { return textView; } public void setColor(int position){ if (positionSet.contains(position)){ textView.setTextColor(Color.GREEN); }else { textView.setTextColor(Color.BLACK); } } }××××××省略无关代码××××××××××××××
最后达成的效果是
长按RecyclerView中的某一项,会进入到多选模式
如果点击的项已经在CustomAdapter中的集合中,则去除这些项,如果集合清空,则退出多选模式
多选模式下再点击某些项,这些项会记录到CustomAdapter中的集合中
GitHub地址
本文的工程地址为:
https://github.com/caoyanfeng/GoogleSamples
如果觉得写得不错,请给我的GitHub点star哦~
- [Android开发]从Android官方Demo谈RecyclerView的用法
- Android开发 ---RecyclerView基本用法
- Android RecyclerView使用Demo
- android开发MediaPlayer用法demo
- 简单的Android RecyclerView 使用小Demo
- Android列表RecyclerView的用法
- android RecyclerView的简单用法
- Android RecyclerView的基本用法
- android 官方demo地址
- Android中RecyclerView用法
- 【Android】RecyclerView具体用法
- Android RecyclerView用法
- Android RecyclerView 和CardView的用法
- Android中RecyclerView的基本用法
- Android RecyclerView 你不知道的用法
- Android控件RecyclerView的基本用法
- 基于Android官方Paging Library的RecyclerView分页加载框架
- 基于Android官方Paging Library的RecyclerView分页加载框架
- OpenGL -- 位图 glBitmap
- Linux 进程和网络端口相关命令
- UDP 多播服务模型
- 【排序】直接插入
- Android中图片的裁剪和徐徐展开控件ClipDrawable
- [Android开发]从Android官方Demo谈RecyclerView的用法
- jQuery select下拉选框操作小结
- Javascript基础——利用定时器实现的图片无缝滚动(offsetLeft)
- 本地套接字domain通信
- jQuery 实现邮箱下拉列表自动补全功能
- Google APAC 2017 University Test Round E
- 编写精美的聊天界面
- hdu 1062 Text Reverse
- Android之自定义ViewGroup经典例子