点滴RecyclerView
来源:互联网 发布:aloha软件 编辑:程序博客网 时间:2024/06/05 08:21
1.为RecyclerView添加分割线
RecyclerView添加分割线可以在item的布局中设置,这里通过实现ItemDecoration来实现分割线效果。
思路:
a.创建一个类继承RecyclerView.ItemDecoration,主要重写两个方法getItemOffsets(..)和onDraw(…),
b.getItemOffsets(…)确定的是item四边的偏移量,onDraw(…)就是绘制分割线
/** * RecyclerView的LinearLayoutManager分割线 */public class RecyclerViewLinearDivider extends RecyclerView.ItemDecoration { private Drawable mDivider; private int mDividerHeight = 2;//分割线高度,默认是2px private int mOrientation;//列表方向:LinearLayoutManager.VERTICAL 或LinearLayoutManager.Horienzontal private int mDividerHeaderMargin; private int mDividerFooterMargin; /** * 自定义分割线 * * @param context * @param orientation 列表方向 * @param drawableId 分割线drawable资源 * @param headerMargin 分割线距离头的距离 单位:像素 * @param footerMargin 分割线距离尾的距离 单位:像素 */ public RecyclerViewLinearDivider(Context context, int orientation, @DrawableRes int drawableId, int headerMargin, int footerMargin) { if (orientation != LinearLayoutManager.HORIZONTAL && orientation != LinearLayoutManager.VERTICAL) { throw new IllegalArgumentException("orientation must be LinearLayoutManager.HORIZONTAL or LinearLayoutManager.VERTICAL"); } mOrientation = orientation; mDivider = ContextCompat.getDrawable(context, drawableId); mDividerHeight = Math.abs(mDivider.getIntrinsicHeight());//返回drawable的内在高度。 mDividerHeaderMargin = headerMargin; mDividerFooterMargin = footerMargin; } //设置四个方向的偏移量,根据位置索引可以指定view的偏移量。这里是当时画横线时,bottom的偏移量就是分割线的高度,也就是上下item的间隔,当画纵线时,right的偏移量就是分割线的厚度,也就是左右item的间隔 @Override public void getItemOffsets(Rect outRect, View view, RecyclerView recyclerView, RecyclerView.State state) { int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); if (mOrientation == LinearLayoutManager.VERTICAL) { outRect.set(0, 0, mDividerHeight, 0); } else { outRect.set(0, 0, 0, mDividerHeight); } } //绘制分割线 @Override public void onDraw(Canvas c, RecyclerView recyclerView, RecyclerView.State state) { if (mOrientation == LinearLayoutManager.VERTICAL) { drawVertical(c, recyclerView); } else { drawHorizontal(c, recyclerView); } } //绘制横向item分割线 private void drawHorizontal(Canvas c, RecyclerView recyclerView) { int left = recyclerView.getPaddingLeft(); int right = recyclerView.getMeasuredWidth() - recyclerView.getPaddingRight(); int childSize = recyclerView.getChildCount(); for (int i = 0; i < childSize; i++) { View child = recyclerView.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); int top = child.getBottom() + layoutParams.bottomMargin; int bottom = top + mDividerHeight; if (mDivider != null) { mDivider.setBounds(left + mDividerHeaderMargin, top, right - mDividerFooterMargin, bottom); mDivider.draw(c); } } } //绘制纵向item分割线 private void drawVertical(Canvas canvas, RecyclerView recyclerView) { int top = recyclerView.getPaddingTop(); int bottom = recyclerView.getMeasuredHeight() - recyclerView.getPaddingBottom(); int childSize = recyclerView.getChildCount(); for (int i = 0; i < childSize; i++) { View child = recyclerView.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); int left = child.getRight() + layoutParams.rightMargin; int right = left + mDividerHeight; if (mDivider != null) { mDivider.setBounds(left, top + mDividerHeaderMargin, right, bottom - mDividerFooterMargin); mDivider.draw(canvas); } } }}
/** * RecyclerView的GridLayoutManager的分割线 */public class RecyclerViewGridDivider extends RecyclerView.ItemDecoration { private static final String TAG = RecyclerViewGridDivider.class.getName(); private Drawable mDivider; private int mDividerHeight = 2;//分割线高度,默认是2px public RecyclerViewGridDivider(Context context, @DrawableRes int drawableId) { mDivider = ContextCompat.getDrawable(context, drawableId); mDividerHeight = Math.abs(mDivider.getIntrinsicHeight());//返回drawable的内在高度。 } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (((GridLayoutManager) parent.getLayoutManager()).getOrientation() != GridLayoutManager.VERTICAL) { throw new RuntimeException("GridLayoutManager's oritention must be GridLayoutManager.VERTICAL"); } int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); int spanCount = getSpanCount(parent);//列数 int childCount = parent.getAdapter().getItemCount(); int left = 0; @SuppressWarnings("SuspiciousNameCombination") int right = mDividerHeight; int top ; int bottom = mDividerHeight; if (isfirstRow(parent, itemPosition, spanCount, childCount)) {//如果是第一行,这里做的是第一行距离顶端是分割线的高度 top = mDividerHeight; } else { top = 0; } if (isLastRow(parent, itemPosition, spanCount, childCount)) {//如果是最后一行,item底端的偏移量置为0,不再绘制分割线 bottom = 0; } if (isRightMost(parent, itemPosition, spanCount, childCount)) {//如果是最右边的一列,item的右边偏移量置为0,不再绘制分割线 right = 0; } outRect.set(left, top, right, bottom); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); draw(c, parent); } //绘制横向 item 分割线 private void draw(Canvas canvas, RecyclerView parent) { int childSize = parent.getChildCount(); for (int i = 0; i < childSize; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); int left; int right; int top; int bottom; //画水平分隔线 left = child.getLeft(); right = child.getRight(); top = child.getBottom() + layoutParams.bottomMargin; bottom = top + mDividerHeight; if (mDivider != null) { mDivider.setBounds(left, top, right, bottom); mDivider.draw(canvas); } //画垂直分割线 top = child.getTop(); bottom = child.getBottom() + mDividerHeight; left = child.getRight() + layoutParams.rightMargin; right = left + mDividerHeight; if (mDivider != null) { mDivider.setBounds(left, top, right, bottom); mDivider.draw(canvas); } } } /** * 判断是否是最后一行 * * @param parent * @param pos * @param spanCount * @param childCount * @return */ private boolean isLastRow(RecyclerView parent, int pos, int spanCount, int childCount) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { int lines = childCount % spanCount == 0 ? childCount / spanCount : childCount / spanCount + 1; return lines == pos / spanCount + 1; } else { throw new RuntimeException("LayoutManager must be GridLayoutManager"); } } /** * 判断是否是第一行 * * @param parent * @param pos * @param spanCount * @param childCount * @return */ private boolean isfirstRow(RecyclerView parent, int pos, int spanCount, int childCount) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { int lines = childCount % spanCount == 0 ? childCount / spanCount : childCount / spanCount + 1;//得到有多少行 if ((pos / spanCount) == 0) {//只有第一行的position<spanCount,其比值的int值一定是0 return true; } else { return false; } } else { throw new RuntimeException("LayoutManager must be GridLayoutManager"); } } /** * 是否是最右边的一列 * * @param parent * @param pos * @param spanCount * @param childCount * @return */ private boolean isRightMost(RecyclerView parent, int pos, int spanCount, int childCount) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { if ((pos % spanCount) == (spanCount - 1)) { return true; } else { return false; } } else { throw new RuntimeException("LayoutManager must be GridLayoutManager"); } } /** * 获取列数 * * @param parent * @return */ private int getSpanCount(RecyclerView parent) { int spanCount = -1; RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } else { throw new RuntimeException("LayoutManager must be GridLayoutManager"); } return spanCount; }}
2.RecyclerView条目点击事件的优化
RecyclerView点击事件很多的做法就是对item每一个都设置点击监听,明显是很消耗性能的方式,这里通过触摸监听来实现点击事件的监听,进行优化,adapter只负责数据的绑定
思路:
1.为RecyclerView添加手势触摸的监听
2.重写点击事件的处理
3.OnRecyclerItemClickListener将别点击的View的id和ViewHolder对象传递给RecyclerView,然后根据业务做处理
OnGestureListener主要回调各种单击事件,必须实现所有方法
OnDoubleTapListener主要回调各种双击事件,必须实现所有方法
SimpeOnGestureListener实现了上面两个接口,都是空方法
OnGestureListener://用户按下屏幕就会触发public boolean onDown(MotionEvent e);//如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行public void onShowPress(MotionEvent e);//一次单独的轻击抬起操作,也就是轻击一下屏幕,就是普通点击事件public boolean onSingleTapUp(MotionEvent e);//在屏幕上拖动事件public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);//长按触摸屏,超过一定时长,就会触发这个事件public void onLongPress(MotionEvent e);//滑屏,用户按下触摸屏、快速移动后松开public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);OnDoubleTapListener://单击事件。用来判定该次点击是SingleTap而不是DoubleTap,//如果连续点击两次就是DoubleTap手势,如果只点击一次,//系统等待一段时间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,//然后触发SingleTapConfirmed事件public boolean onSingleTapConfirmed(MotionEvent e);//双击事件public boolean onDoubleTap(MotionEvent e);//双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作public boolean onDoubleTapEvent(MotionEvent e);
/** * 实例化手势探测器,需要一个手势监听器:OnGestureListener, * OnGestureListener主要回调各种单击事件,必须实现所有方法 * OnDoubleTapListener主要回调各种双击事件,必须实现所有方法 * SimpeOnGestureListener实现了上面两个接口,都是空方法 */public abstract class OnRecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private static final String TAG = OnRecyclerItemClickListener.class.getName(); private GestureDetectorCompat mGestureDetector; private RecyclerView recyclerView; public OnRecyclerItemClickListener(RecyclerView recyclerView) { this.recyclerView = recyclerView; mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener()); } public abstract void onItemClick(int viewId, RecyclerView.ViewHolder viewHolder); public abstract void onItemLongClick(RecyclerView.ViewHolder vh); @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { mGestureDetector.onTouchEvent(e);//解析坐标点和触摸规律来识别触摸手势 return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { mGestureDetector.onTouchEvent(e);//解析坐标点和触摸规律来识别触摸手势 } @Override//用来处理触摸冲突 public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener { @Override//点击事件处理 public boolean onSingleTapUp(MotionEvent e) { final View itemRecycler = recyclerView.findChildViewUnder(e.getX(), e.getY());//获取被点击item的view if (itemRecycler instanceof ViewGroup) { ViewGroup itemView = (ViewGroup) itemRecycler; for (int i = 0; i < itemView.getChildCount(); i++) { itemView.getChildAt(i).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onItemClick(v.getId(), recyclerView.getChildViewHolder(itemRecycler)); } }); } } else { itemRecycler.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (itemRecycler != null) { onItemClick(itemRecycler.getId(), recyclerView.getChildViewHolder(itemRecycler)); } } }); } return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child != null) { RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child); onItemLongClick(vh); } } }}
mRecycler.addOnItemTouchListener(new OnRecyclerItemClickListener(mRecycler) { @Override public void onItemClick(int viewId, RecyclerView.ViewHolder viewHolder) { int position = viewHolder.getAdapterPosition(); MyAdapter.ViewHolder myViewHolder = (MyAdapter.ViewHolder) viewHolder; switch (viewId){ case R.id.tv: Toast.makeText(MainActivity.this,"第"+position+"个条目的TextView被点击"+myViewHolder.tv.getText(),Toast.LENGTH_SHORT).show(); break; case R.id.img: Toast.makeText(MainActivity.this,"第"+position+"个条目的ImageView被点击",Toast.LENGTH_SHORT).show(); break; } } @Override public void onItemLongClick(RecyclerView.ViewHolder vh) { } });
3.RecyclerView实现拖拽效果
/** * RecyclerView实现拖拽的帮助类,(swipe方式侧滑删除与拖拽同时存在时,会有冲突,这里只有拖拽) */public class RecyclerViewDragHelper extends ItemTouchHelper.Callback { private ItemTouchAdapter mItemTouchAdapter; private OnDragListener mOnDragListener; public RecyclerViewDragHelper(ItemTouchAdapter itemTouchAdapter) { this.mItemTouchAdapter = itemTouchAdapter; } @Override//设置recyclerview是否支持长按拖拽,默认是true,如果这里返回true,所有的Item都支持拖拽,如果有特定的item不支持拖拽,这里就要返回false,在长按的状态下进行处理 public boolean isLongPressDragEnabled() { return false; } @Override//设置item是否可以侧滑删除 public boolean isItemViewSwipeEnabled() { return true; } @Override//设置是否处理拖拽事件和滑动事件以及拖拽和滑动操作的方向 public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof GridLayoutManager){ int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//拖拽标志 int swipeFlags = 0;//滑动标志,设置为0,不处理滑动操作 return makeMovementFlags(dragFlags,swipeFlags); }else if (layoutManager instanceof LinearLayoutManager){ int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = 0 ;//列表可以实现侧滑删除,这里用0 处理,侧滑删除和拖拽都需要长时间按住,所以手势识别有冲突 return makeMovementFlags(dragFlags,swipeFlags); }else { throw new IllegalArgumentException("LayoutManager must be GridLayoutManager or LinearLayoutManager"); } } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { int fromPosition = viewHolder.getAdapterPosition();//获取拖动viewholder的position int toPosition = target.getAdapterPosition();//获取目标viewholder的position mItemTouchAdapter.onMove(fromPosition,toPosition); return true; } @Override//侧滑删除时调用,这里没有使用 public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { int position = viewHolder.getAdapterPosition(); mItemTouchAdapter.onSwiped(position); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE){ float alpha = 1 - Math.abs(dX)/(float)viewHolder.itemView.getWidth(); viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); }else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } } @Override//当长按选中item的时候调用(拖拽的时候) public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (actionState == ItemTouchHelper.ACTION_STATE_DRAG ){ viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(R.color.md_red_A400)); } } @Override//当手指松开时调用 public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(R.color.md_red_A200)); if (mOnDragListener != null) mOnDragListener.onFinishDrag(); } public RecyclerViewDragHelper setOnDragListener(OnDragListener onDragListener){ this.mOnDragListener = onDragListener; return this; } public interface OnDragListener{ void onFinishDrag(); } public interface ItemTouchAdapter{ void onMove(int fromPosition,int toPosition);//拖拽 void onSwiped(int position);//侧滑删除 }}
//Adapter要实现拖拽帮助类的接口,拖拽的接口, private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements RecyclerViewDragHelper.ItemTouchAdapter{ ... @Override public void onMove(int fromPosition, int toPosition) { if (fromPosition == mList.size() -1 || toPosition == mList.size() -1){ return; } if (fromPosition < toPosition){ for (int i = fromPosition; i < toPosition; i++) { Collections.swap(mList,i,i + 1); } }else { for (int i = fromPosition; i > toPosition ; i--) { Collections.swap(mList,i,i -1); } } notifyItemMoved(fromPosition,toPosition); } ... }
//RecyclerView的监听处理 mRecycler.addOnItemTouchListener(new OnRecyclerItemClickListener(mRecycler) { @Override public void onItemClick(RecyclerView.ViewHolder vh) { int position = vh.getLayoutPosition(); Toast.makeText(MainActivity.this,"第"+position+"被点击了",Toast.LENGTH_SHORT).show(); } @Override public void onItemLongClick(RecyclerView.ViewHolder vh) { int childCount = ((RecyclerView)vh.itemView.getParent()).getAdapter().getItemCount(); if (vh.getLayoutPosition() != childCount -1){//最后一个不能拖动 mDragHelper.startDrag(vh);//可以拖动 VibratorUtil.vibrate(MainActivity.this,70); } } });
阅读全文
0 0
- RecyclerView点滴
- 点滴RecyclerView
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- 点滴
- Eclipse中改变jsp默认编码iso-8859-1
- 【数据结构】之二叉树
- ValueAnimator源码——动画驱动
- 进程的同步与通信,进程与线程同步的区别,进程与线程通信的区别
- Java开发中的23种设计模式详解----策略模式(strategy)
- 点滴RecyclerView
- 004 mediaplayer播放流程分析
- MailBee.NET Objects接收电子邮件(POP3)教程二:接收和显示HTML电子邮件
- 回调(异步回调)在实际开发过程中的应用
- leetcode-6 ZigZag Conversion
- redis操作总结
- JNDI Resources HOW-TO(Tomcat 9)
- 为项目重新设置git remote url
- var_dump输出格式