Android-------RecycleView自定义拖拽、侧滑的实现
关于recycleView的拖拽和侧滑的实现,android原生已经为我们提供了实现方法,个人认为原生实现的方法其实已经很强大了,对于很多功能都是适用的,而且实现方法很简单。尤其是它带的拖拽功能非常好,动画也很流畅,效果很好。实现方法如下:
ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//控制view可移动操作方向方向
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//当拖拽移动交换
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
Collections.swap(list, fromPosition, toPosition);
adapter.addData(list);
adapter.notifyItemMoved(fromPosition, toPosition);
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//当侧滑到一定程度时删除
adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
}
@Override
public boolean isLongPressDragEnabled() {
//是否长按
return true;
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//可以在选择的时候做一些选中改变
viewHolder.itemView.setBackgroundColor(0xf0f0f0);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//当对某个view操作完后 也就是手松开后 如果侧滑,拖拽时做出了颜色的改变什么的等等,在这里使它复原,防止复用这个view时显示不对
super.clearView(recyclerView, viewHolder);
}
@Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
// 当对view进行拖拽,侧滑的过程中不断调用这个函数
//仅对侧滑状态下的效果做出改变
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
//在这里做一些操作可以自定义侧滑
}
//仅对拖拽状态下的效果做出改变
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
}
super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
});
mItemTouchHelper.attachToRecyclerView(binding.rvList1);
因为我个人比较想巩固自定义view,动画等方面的知识,所以我没有引用Android原生自带的拖拽功能,而是通过实现重写RecyclerView.OnItemTouchListener方法来自定义这些功能。RecyclerView.OnItemTouchListener不是对item的监听,而是对recycleView触摸事件的监听,也就是说是以recycleView为中心,以recycleView建立的坐标系。
具体如何实现我就不具体介绍了,代码的注释很详细,讲明了流程,直接上代码。
item_expand
-
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:id="@+id/view_root" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/gray_f0" android:orientation="horizontal" android:paddingBottom="1dp"> <LinearLayout android:id="@+id/view_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/pink" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="20dp" android:layout_height="20dp" android:layout_marginLeft="10dp" android:scaleType="fitXY" android:src="@mipmap/example" android:visibility="visible" /> <TextView android:id="@+id/tv_content" style="@style/title_b" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="15dp" /> </LinearLayout> <LinearLayout android:id="@+id/view_operate" android:layout_width="240dp" android:layout_height="match_parent" android:background="@color/white" android:orientation="horizontal"> <TextView android:id="@+id/tv_look" style="@style/body_w" android:layout_width="80dp" android:layout_height="match_parent" android:background="@color/green" android:gravity="center" android:text="查看" /> <TextView android:id="@+id/tv_delete" style="@style/body_w" android:layout_width="80dp" android:layout_height="match_parent" android:background="@color/gray" android:gravity="center" android:text="删除" /> <TextView android:id="@+id/tv_jump" style="@style/body_w" android:layout_width="80dp" android:layout_height="match_parent" android:background="@color/blue" android:gravity="center" android:text="跳转" /> </LinearLayout> </LinearLayout> </layout>
ExpandAdapter
-
public class ExpandAdapter extends BaseRecycleViewAdapter<String> { public ExpandAdapter(Context context) { super(context); } @Override public ViewDataBinding createView(ViewGroup parent) { ItemExpandBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_expand, parent, false); BaseBindingViewHolder holder = new BaseBindingViewHolder(binding); binding.tvDelete.setOnClickListener(this); binding.tvJump.setOnClickListener(onClickListener); binding.tvLook.setOnClickListener(onClickListener); return binding; } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { super.onBindViewHolder(holder, position); BaseBindingViewHolder viewHolder = (BaseBindingViewHolder) holder; ItemExpandBinding binding = (ItemExpandBinding) viewHolder.binding; binding.tvLook.setTag(position); binding.tvJump.setTag(position); binding.tvDelete.setTag(position); binding.tvContent.setText("" + list.get(position)); } View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { int position = (int) v.getTag(); switch (v.getId()) { case R.id.tv_delete: ToastUtils.ViewToast(context, "删除"); break; case R.id.tv_look: ToastUtils.ViewToast(context, "查看"); break; case R.id.tv_jump: ToastUtils.ViewToast(context, "跳转"); break; } } }; /** * 获取侧滑的宽度 * * @param view * @return */ public int getExpandWidth(View view) { if (view != null) { View expandView = view.findViewById(R.id.view_operate); return expandView.getLayoutParams().width; } else { return 0; } } }
RecycleViewSlideActivity
-
public class RecycleViewSlideActivity extends BaseActivity { ExpandAdapter adapter; ActivityExampleViewBinding binding; private ArrayList<String> list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_example_view, getParentView(), false); setMyContentView(binding.getRoot(), "测试"); initView(); initData(); } @Override public void initView() { super.initView(); list.add("0\n人生若只如初见,何事秋风悲画扇。 \n等闲变却故人心,却道故人心易变。 \n骊山语罢清宵半,泪雨霖铃终不怨。 \n何如薄幸锦衣郎,比翼连枝当日愿。"); list.add("1\n明月多情应笑我,笑我如今,辜负春心,独自闲行独自吟。"); list.add("2\n我是人间惆怅客, \n" + "知君何事泪纵横, \n" + "断肠声里忆平生。"); list.add("3\n谁念西风独自凉?萧萧黄叶闭疏窗,沉思往事立残阳。 \n" + "被酒莫惊春睡重,赌书消得泼茶香,当时只道是寻常。"); list.add("4\n一生一代一双人,争教两处销魂。相思相望不相亲,天为谁春?"); list.add("5\n浮生如此,别多会少,不如莫遇。"); list.add("6\n回廊一寸相思地, \n" + "落月成孤倚。 \n" + "背灯和月就花阴, \n" + "已是十年踪迹十年心。"); list.add("7\n明月多情应笑我,笑我如今。 \n" + "辜负春心,独自闲行独自吟。 \n" + "近来怕说当时事,结遍兰襟。 \n" + "月浅灯深,梦里云归何处寻?"); list.add("8\n人生若只如初见,何事秋风悲画扇?"); list.add("9\n山一程,水一程,身向榆关那畔行,夜深千帐灯。 \n" + "风一更,雪一更,聒碎乡心梦不成,故园无此声。"); list.add("10\n肠断月明红豆蔻,月似当时,人似当时否? "); RecycleViewTool.setRecycleViewVertical(this, binding.rvList1); adapter = new ExpandAdapter(this); adapter.addData(list); binding.rvList1.setAdapter(adapter); binding.rvList1.addOnItemTouchListener(new RecycleViewOnItemTouchListener(adapter, onItemTouchCallBack, this)); } RecycleViewOnItemTouchListener.OnItemTouchCallBack onItemTouchCallBack = new RecycleViewOnItemTouchListener.OnItemTouchCallBack() { @Override public void onDragFinish(View vew) { } @Override public void onSwipe(View view) { } @Override public boolean isLongPressEnable() { return true; } @Override public void onMove(int needExchangePosition, int targetPosition) { Collections.swap(list, targetPosition, needExchangePosition); adapter.addData(list); adapter.notifyItemMoved(targetPosition, needExchangePosition); } @Override public boolean onSelectedChanged(View view) { if (view != null && view instanceof LinearLayout) { ((LinearLayout) view).getChildAt(0).setBackgroundColor(0xfffefefe); } return true; } @Override public boolean clearView(View view) { if (view != null && view instanceof LinearLayout) { ((LinearLayout) view).getChildAt(0).setBackgroundColor(0xfffce4ec); } return false; } }; }
activity_example_view
-
<?xml version="1.0" encoding="utf-8"?> <layout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_list_1" android:layout_width="match_parent" android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView> </LinearLayout> </layout>
RecycleViewOnItemTouchListener
-
/** * 自定义recycleview的拖拽,侧滑 */ public class RecycleViewOnItemTouchListener implements RecyclerView.OnItemTouchListener { /** * 按下时X轴坐标 */ private float downPointX; /** * 按下时Y轴坐标 */ private float downPointY; /** * 上一个点的X轴坐标 */ private float startPointX; /** * 上一个点的Y轴坐标 */ private float startPointY; /** * 要进行拖动,侧滑的控件 */ private View mTargetView; /** * adapter */ private ExpandAdapter adapter; /** * 是否有down事件 */ private boolean isDown = false; /** * 是否为长按 */ private boolean isLongPress; /** * 操作回调 */ private OnItemTouchCallBack callBack; /** * 上下文 */ private Context context; /** * 上一次交换的view */ private View exchangeView = null; /** * 上一次滑动拖拽方向 */ private int exchangeDirection;//-1 没有交换过 0向上 1向下 /** * 每一次拖动所进行的一系列动画 */ private ArrayList<Float> animations = new ArrayList<>(); /** * 长按计时任务 */ private Timer timer; /** * 属性位移动画 */ private ObjectAnimator translateAnimation; /** * 是否正在交换 */ private boolean isExchanging; /** * 被拖拽的view在交换后它的top值或者bottom值,以此判断是否完成交换 */ private float needDistance; public RecycleViewOnItemTouchListener(ExpandAdapter adapter, OnItemTouchCallBack callBack, Context context) { this.adapter = adapter; this.callBack = callBack; this.context = context; } /** * 拦截true 表示拦截,调用onTouch false表示不拦截,把时间传递给子View * * @return */ @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { if (rv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) { //列表为静止状态,可以操作 switch (e.getAction()) { case MotionEvent.ACTION_DOWN: //初始化 isExchanging = false; mTargetView = null; exchangeView = null; exchangeDirection = -1; animations.clear(); isDown = true;//记录此时按下了 isLongPress = false; mTargetView = rv.findChildViewUnder(e.getX(), e.getY()); startPointX = e.getX(); startPointY = e.getY(); downPointX = e.getX(); downPointY = e.getY(); if (callBack.isLongPressEnable()) { timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { //长按100毫秒表示长按可移动 isLongPress = true; Vibrator vibrator = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE); vibrator.vibrate(100); } }, ViewConfiguration.getLongPressTimeout()); } return false; case MotionEvent.ACTION_UP: if (timer != null) { timer.cancel(); } if (isDown) { //点击事件 不拦截 isDown = false; mTargetView = null; return false; } else { //上一个动作不是down,可能是move、cancel、outside if (mTargetView == null) { return false; } else { return judgeNeedIntercept(); } } case MotionEvent.ACTION_MOVE: if (mTargetView == null) { if (timer != null) { timer.cancel(); } isDown = false; return false; } else { if (isDown) { //前一个动作时按下 if (isLongPress) { //长按后再移动 isDown = false; if (callBack != null) { if (callBack.onSelectedChanged(mTargetView)) { //可以拖拽 } else { //不可以拖拽 clearView(); mTargetView = null; return false; } } return true; } else { float distanceX = startPointX - e.getX(); float distanceY = startPointY - e.getY(); if (Math.max(Math.abs(distanceX), Math.abs(distanceY)) < 20) { //当从按下开始如果移动小于20,则任然视为按下,不能作为移动 return false; } else { isDown = false; if (timer != null) { timer.cancel(); } isLongPress = false; if (Math.abs(distanceX) > Math.abs(distanceY)) { //x方向的移动距离大于y方向的距离 if (callBack != null) { if (callBack.onSelectedChanged(mTargetView)) { //可以侧滑 } else { //不可以侧滑 clearView(); mTargetView = null; return false; } } return true; } else { mTargetView = null; return false; } } } } else { //x方向的移动距离大于y方向的距离 return true; } } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_OUTSIDE: if (timer != null) { timer.cancel(); } isDown = false; if (mTargetView == null) { return false; } else { return judgeNeedIntercept(); } } } return false; } /** * 在view被放开之后的状态ui还原 */ public void clearView() { if (mTargetView != null) { if (callBack != null) { callBack.clearView(mTargetView); } } } /** * 判断是否拦截事件 */ public boolean judgeNeedIntercept() { //此处注明:view的scroll操作,其实是对view内部进行滚动,初始时状态偏移量为0 mTargetView.getScrollX() 获取的是绝对总偏移量,如果向左滚动,则偏移量为正,否则为负,,如果向上滚动,则偏移量为正,否则为负,就是偏移量=初始坐标-结束坐标 //view.scrollTo()是指从初始状态移动多少,内部的值为偏移量值,是总偏移量,绝对值 //view.scrollBy()是指从当前状态移动多少,内部的值为偏移量值,是部分偏移量,是相对值 if (isLongPress) { //长按之后放开 clearView(); return true; } else { //判断移动距离 if (mTargetView.getScrollX() == 0) { //没有移动过 不作操作 clearView(); mTargetView = null; return false; } else if (-mTargetView.getScrollX() == adapter.getExpandWidth(mTargetView)) { //移动到底部,不作操作 clearView(); mTargetView = null; return false; } else { //需要做操作 return true; } } } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { if (isLongPress) { switch (e.getAction()) { case MotionEvent.ACTION_MOVE: if (isExchanging) { if (exchangeDirection == 0) { //向上 if (needDistance == mTargetView.getTop()) { //如果交换完成 则重新设置translation等的值,也可以进行动画 isExchanging = false; mTargetView.setTranslationY(e.getY() - downPointY + exchangeView.getHeight()); // mTargetView.setTranslationY(0); downPointY = e.getY(); judgeIsExchange(e, rv); } //未完成则继续交换 } else if (exchangeDirection == 1) { //向下 if (needDistance == mTargetView.getBottom()) { //如果在mTargetView在顶部的话,向下交换之后的时候就会看不到被交换的view,这个时候设置滚到被交换的viewde位置,可以防止这一操作 ((RecyclerView) mTargetView.getParent()).scrollToPosition(((RecyclerView) mTargetView.getParent()).getChildAdapterPosition(mTargetView) - 1); isExchanging = false; mTargetView.setTranslationY(e.getY() - downPointY - exchangeView.getHeight()); // mTargetView.setTranslationY(0); downPointY = e.getY(); judgeIsExchange(e, rv); } } } else { judgeIsExchange(e, rv); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_OUTSIDE: //取消所有拖拽动画,复原位置 if (translateAnimation != null) { translateAnimation.cancel(); animations.clear(); } mTargetView.setTranslationY(0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mTargetView.setTranslationZ(0.0f); } if (mTargetView != null && callBack != null) { callBack.onDragFinish(mTargetView); clearView(); } adapter.notifyDataSetChanged(); mTargetView = null; exchangeView = null; isExchanging = false; exchangeDirection = -1; break; } } else { switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float distanceX = startPointX - e.getX();//获取需要再次滚动的偏移量 int mScrollX = (int) (mTargetView.getScrollX() + distanceX);//最终的偏移量 if (mScrollX >= adapter.getExpandWidth(mTargetView)) {//已经全部展开侧滑栏 mScrollX = adapter.getExpandWidth(mTargetView); } else if (mScrollX <= 0) {//未展开侧滑栏 mScrollX = 0; } mTargetView.scrollTo(mScrollX, mTargetView.getScrollY()); startPointX = e.getX(); startPointY = e.getY(); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_OUTSIDE: if (mTargetView.getScrollX() > adapter.getExpandWidth(mTargetView) / 2) { //移动的距离大于侧滑栏长度的一半,则把侧滑栏全部显示 mTargetView.scrollTo(adapter.getExpandWidth(mTargetView), mTargetView.getScrollY()); } else { //隐藏侧滑栏 mTargetView.scrollTo(0, mTargetView.getScrollY()); } if (mTargetView != null && callBack != null) { callBack.onSwipe(mTargetView); } clearView(); mTargetView = null; isLongPress = false; break; } } } /** * 创建动画用于拖拽 */ public void createAnimation() { if (mTargetView != null && animations.size() > 0) { translateAnimation = ObjectAnimator.ofFloat(mTargetView, "translationY", mTargetView.getTranslationY(), mTargetView.getTranslationY() + animations.get(0)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mTargetView.setTranslationZ(0.1f); } translateAnimation.setDuration(0); translateAnimation.addListener(animatorListener); translateAnimation.start(); // ObjectAnimator translateZAnimation = ObjectAnimator.ofFloat(mTargetView, "translationZ", 0, 100); // AnimatorSet animatorSet = new AnimatorSet(); // //使用play方法把两个动画拼接起来 // animatorSet.playTogether(translateAnimation, translateZAnimation); // //时间 // animatorSet.setDuration(3000); // //开始执行 // animatorSet.start(); // animatorSet.addListener(animatorListener); } } Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { if (animations.size() > 0) { animations.remove(0); } if (animations.size() > 0) { createAnimation(); } } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }; /** * 对每次移动进行操作判断 */ public void judgeIsExchange(MotionEvent e, RecyclerView rv) { // 每次移动,记录移动的距离,加入动画列表,当上一个位移动画完成时,完成当前位移动画 if (animations.size() == 0) { animations.add(e.getY() - startPointY); createAnimation(); } else { animations.add(e.getY() - startPointY); } //获取被拖拽view的位置 int targetPosition = rv.getChildAdapterPosition(mTargetView); //记录移动方向 int tempExchangeDirection; View view; if (e.getY() - startPointY > 0) { //向下移动 tempExchangeDirection = 1; view = findChildViewUnder(mTargetView.getLeft(), mTargetView.getBottom() + e.getY() - downPointY, rv, tempExchangeDirection); } else { //向上移动 tempExchangeDirection = 0; view = findChildViewUnder(mTargetView.getLeft(), mTargetView.getTop() + e.getY() - downPointY, rv, tempExchangeDirection); } //记录当前移动位置坐标 startPointY = e.getY(); startPointX = e.getX(); //获取当前手指所在的View // View view = findChildViewUnder(e.getX(), e.getY(), rv); int currentPosition = rv.getChildAdapterPosition(view); //注意:view进行属性动画或者补间动画的时候,view.getTop等值是不变的,任然是view未偏移之前的初始位置的getop值,也就是偏移只改变了translateY的值 mTargetView.getTranslationY()=当前坐标-初始未偏移之前的坐标=偏移量 if (targetPosition != -1 && currentPosition != -1 && currentPosition != targetPosition) { if (tempExchangeDirection == 0) { //向上 if (mTargetView.getTop() == view.getBottom()) { //如果手指所在位置和被拖拽view的位置是上下相邻 if (mTargetView.getTop() + e.getY() - downPointY <= view.getTop()) { //如果手指所在位置的view和被拖拽view的top是重合了,则交换位置 changeView(view, tempExchangeDirection, targetPosition, currentPosition); } } else if (mTargetView.getTop() > view.getBottom()) { //如果手指所在view和被拖拽view的位置是不相邻,则被拖拽的view和手指所在view的下一个view交换 changeView(rv.getChildAt(currentPosition + 1 - ((LinearLayoutManager) rv.getLayoutManager()).findFirstVisibleItemPosition()), tempExchangeDirection, targetPosition, currentPosition + 1); } } else { //向下 if (mTargetView.getBottom() == view.getTop()) { //如果手指所在位置和被拖拽view的位置是下上相邻 if (mTargetView.getBottom() + e.getY() - downPointY >= view.getBottom()) { //如果手指所在位置的view和被拖拽view的bottom是重合了,则交换位置 changeView(view, tempExchangeDirection, targetPosition, currentPosition); } } else if (mTargetView.getBottom() < view.getTop()) { //如果手指所在view和被拖拽view的位置是不相邻,则被拖拽的view和手指所在view的上一个view交换, // 这里有一个Android的bug,rv.getChildAt(position)获取的并不是当前位置的view,这个position指的是那些可看见的view的数组的位置,即((LinearLayoutManager)rv.getLayoutManager()).findFirstVisibleItemPosition()在该列表里的位置为0 changeView(rv.getChildAt(currentPosition - 1 - ((LinearLayoutManager) rv.getLayoutManager()).findFirstVisibleItemPosition()), tempExchangeDirection, targetPosition, currentPosition - 1); } } } } /** * 交换位置 * * @param view * @param tempExchangeDirection 拖拽方向 0向上 1向下 * @param needExchangePosition 被交换的位置 * @param targetPosition 被拖拽的控件所在的位置 */ public void changeView(View view, int tempExchangeDirection, int targetPosition, int needExchangePosition) { //在一个方向上(向上或向下)不可能被拖拽的控件不可能和另一个控件先后两次交换 if (exchangeView == null || !(exchangeView == view && tempExchangeDirection == exchangeDirection)) { exchangeView = view; exchangeDirection = tempExchangeDirection;//记录此时的拖拽方向和交换控件 animations.clear(); translateAnimation.cancel(); isExchanging = true; if (exchangeDirection == 0) { if (mTargetView.getTop() <= 0) { needDistance = mTargetView.getTop(); } else { needDistance = view.getTop(); } } else { if (mTargetView.getTop() <= 0) { needDistance = mTargetView.getBottom(); } else { needDistance = view.getBottom(); } } if (callBack != null) { callBack.onMove(needExchangePosition, targetPosition); } } } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } /** * 拖拽时获取手指所在的位置对应的控件 * * @param x * @param y * @param rv * @return */ public View findChildViewUnder(float x, float y, RecyclerView rv) { View child; final int count = rv.getChildCount(); for (int i = 0; i < count; i++) { child = rv.getChildAt(i); if (child != null) { if (x >= child.getLeft() && x <= child.getRight() && y >= child.getTop() && y <= child.getBottom()) { return child; } } } return null; } /** * 拖拽时获取此时被拖拽的view的左上角的所在的位置对应的控件 * * @param x * @param y * @param rv * @return */ public View findChildViewUnder(float x, float y, RecyclerView rv, int tempExchangeDirection) { View child; final int count = rv.getChildCount(); for (int i = 0; i < count; i++) { child = rv.getChildAt(i); if (child != null) { if (tempExchangeDirection == 0) { if (x >= child.getLeft() && x <= child.getRight() && y >= child.getTop() && y < child.getBottom()) { return child; } } else { if (x >= child.getLeft() && x <= child.getRight() && y > child.getTop() && y <= child.getBottom()) { return child; } } } } return null; } public interface OnItemTouchCallBack { /** * 当拖拽释放后 * * @param vew 被拖拽的控件 */ void onDragFinish(View vew); /** * 当侧滑展开后 * * @param view */ void onSwipe(View view); /** * 是否支持长按 * * @return true 可长按 false不看不可以长按 */ boolean isLongPressEnable(); /** * 当拖拽移动交换的时候 * * @param needExchangePosition 被交换的位置 * @param targetPosition 被拖拽的控件所在的位置 */ void onMove(int needExchangePosition, int targetPosition); /** * 当长按或者侧滑的控件被选择时 * * @param view 被选择的控件 * @return */ boolean onSelectedChanged(View view); /** * 手松开后的一些操作 * * @param view * @return */ boolean clearView(View view); } }