跨多个RecyclerView拖动排序
来源:互联网 发布:linux 命令 ls l 编辑:程序博客网 时间:2024/05/21 09:46
先介绍一下本文出现的背景,项目中有这样一个需求,拖动一个列表的某一项排序或者拖动到另外一个列表中。
其效果如下图:
拖动排序在RecyclerView有现成的解决方案,配合ItemTouchHelper即可轻松实现。但是要将一个列表中的Item拖动到另一个列表中去,就不那么容易了。
先来看看这种跨界面实现由那些难点,我们先分析,再一个一个的解决。
- 拖动视图的保存,ItemTouchHelper的实现思路是获取到长按的View后,对这个View做Translate位移,但是这样做的局限在于这个View就只能在它所属的RecyclerView中移动,超出的部分就被隐藏了。
- 当拖动Item到边缘后,两个界面怎么切换,是使用系统的ViewPager还是自定义ViewGroup。
- 在一个RecyclerView中拖动和跨多个拖动用到的策略是否一样。
- 由于RecyclerView已经接收了触摸事件,那么怎么获取触摸信息,比如判断滑到边缘了,以及Item是否长按。
现在我们来一个一个的解决上面的问题:
1. 对于第一个问题,解决方法是当判断Item被长按后,将当前Item记录为一张图片,然后设置给一个隐藏的ImageView,对这个ImageView做Translate平移。这里需要额外费心的是这个ImageView与长按Item视图的重合以及显隐判断。
2. 如果使用ViewPager,由于要跨越两个page,那么触摸事件,保存的图片等都要交给其父控制器,还不如自定义一个ViewGroup。
3. 由于系统提供了在一个RecyclerView中拖动的Helper类,我们无需去解决拖动的起始位置这些,那何乐不为呢?所以,跨界面拖动用自己的实现。
4. 触摸point信息的获取:dispatchTouchEvent方法是最先到的,在我们自定义的ViewPager中重写该方法。在adapter中对itemview添加手势监听,获取到被长按的View。
下面来看代码实现:
(1) 自定义的父视图:
public class NewLinearLayout extends LinearLayout { /*将触摸点坐标传递出去*/ private IGetX iGetX; /*弹性滑动*/ private Scroller mScroller; public NewLinearLayout(Context context) { super(context); init(context); } public NewLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public NewLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } /*initial*/ public void init(Context context){ mScroller = new Scroller(context); } @Override public void computeScroll(){ super.computeScroll(); /*判断是否完成滑动*/ if(mScroller.computeScrollOffset()){ scrollTo(mScroller.getCurrX() , 0); /*循环调用该方法*/ postInvalidate(); } } /*开启弹性滑动*/ public void beginScroll(int dx ){ mScroller.startScroll(mScroller.getCurrX() , 0 , dx , 0 , 1000); /*调用computeScroll()方法*/ invalidate(); } @Override public boolean dispatchTouchEvent(MotionEvent event){ float dx = event.getX(); float dy = event.getY(); if(event.getAction() == MotionEvent.ACTION_MOVE) iGetX.point(dx , dy); return super.dispatchTouchEvent(event); } public void set(IGetX iGetX){ this.iGetX = iGetX; } public interface IGetX{ void point(float dx , float dy); }}
(2) View转bitmap
public Bitmap view2bitmap(View view) { int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); view.draw(new Canvas(bitmap)); return bitmap; }
(3) Adapter的实现
private class Recycler1Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private ArrayList<String> mData; public void setData(ArrayList<String> mData) { this.mData = mData; } public void addData(ArrayList<String> mData) { this.mData.addAll(mData); notifyDataSetChanged(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(SpanDragActivity.this).inflate(R.layout.item_launch_title, null); final Recycler1ViewHolder viewHolder = new Recycler1ViewHolder(itemView); viewHolder.itemView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mDetector.onTouchEvent(event); if(event.getAction() == MotionEvent.ACTION_DOWN){ bitmap = null; TempItemView = viewHolder.itemView; startX = TempItemView.getLeft(); startY = TempItemView.getTop(); } /*恢复计点*/ if(event.getAction() == MotionEvent.ACTION_UP){ isFirstPoint = true; } return false; } }); return viewHolder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ((Recycler1ViewHolder) holder).mTv.setText(mData.get(position)); } @Override public int getItemCount() { return mData.size(); } /*create viewholder*/ class Recycler1ViewHolder extends RecyclerView.ViewHolder { private TextView mTv; public Recycler1ViewHolder(View itemView) { super(itemView); mTv = (TextView) itemView.findViewById(R.id.item_launch_title_tv_title); } } }
(4) 滑动到边缘后触发的事件
/*设置接口获取手指位置*/ activitySpanLl.set(new NewLinearLayout.IGetX() { @Override public void point(float dx , float dy) { Log.v("out", "手指位置:" + dx); if(isFirstPoint){ firstX = dx; firstY = dy; isFirstPoint = false; } if(bitmap != null) { activitySpanImg.setTranslationX(dx-firstX+startX); activitySpanImg.setTranslationY(dy-firstY+startY); } if(dx >=800){ } if (isFirstScroll) if (dx >= 1000) { activitySpanLl.beginScroll(1080); isFirstScroll = false; /*向右边滑动了,所以现在可以向左滑动了*/ isFirstLeftScroll = true; int a = activitySpanLl.getScrollX(); float b = activitySpanLl.getX(); } if(isFirstLeftScroll) if(dx <= 80){ activitySpanLl.beginScroll(-1080); isFirstLeftScroll = false; /*向左边滑动了,所以现在可以向右滑动了*/ isFirstScroll = true; int a = activitySpanLl.getScrollX(); float b = activitySpanLl.getX(); } } });
基本思路和重要的代码都在上面了,在实际项目中应用还需要对坐标,滑动等作出优化。
有更多问题留言交流。
1 0
- 跨多个RecyclerView拖动排序
- RecyclerView左右滑动及拖动排序
- RecyclerView滑动删除和拖动排序
- RecyclerView 下拉刷新 加载更多 左滑删除 拖动排序
- RecyclerView系列(三)拖动排序,横滑删除
- RecyclerView 实现侧滑删除和拖动排序
- ItemTouchHelper实现RecyclerView拖动排序和滑动删除
- RecyclerView实现拖动排序和滑动删除功能
- Android recyclerView的拖动
- RecyclerView上下拖动条目排序,左右划出屏幕删除条目的最简单的实现
- RecyclerView更全解析之 - 仿支付宝侧滑删除和拖动排序
- RecyclerView的item拖动排序效果实现和它的ItemTouchHelper详解
- RecyclerView 拖动才刷新内容
- RecyclerView的拖动和滑动
- RecyclerView实现拖动和滑动
- RecyclerView 滑动删除与拖动的实现
- 二维RecyclerView,可拖动面板控件
- div拖动并且排序
- 建造者模式
- margin、edge
- 零基础学习网页制作(一)
- 21、Bitmap二次采样
- studio虚拟机乱码问题
- 跨多个RecyclerView拖动排序
- Android 开发笔记
- listview
- 手机拍摄功能详解
- P2P、P2C、O2O、B2C、B2B、C2C 的区别
- 对list对象进行去重操作,并排序
- Java导出excel(无模板导出excel)
- Arm Linux系统调用流程详细解析-SWI
- .net平台下C#socket通信(上)