在ScrollView中放入自定义可拖动的控件时,当拖动可拖动子控件时,MotionEvent先被根控件接收并依此传递给子控件,由于ScrollView是父控件,并他会检测事件是否滑动一段距离,所有当他使用事件时会造成可拖动控件拖动异常。
解决该问题的好办法是在自定义控件中的onTouchEvent方法中在ACTION_DOWN,ACTION_MOVE调用requestDisallowInterceptTouchEvent(true)(如下),在ACTION_UP时调用requestDisallowInterceptTouchEvent(false)
getParent().requestDisallowInterceptTouchEvent(true)
上面代码的意思就是禁止父控件或者祖先控件拦截点击事件。
参看文章
https://www.jianshu.com/p/8c635cb59fdf
https://www.jianshu.com/p/ff3b55441444
/** * 可拖拽FrameLayout * * @author Jiangli * @see <a href="https://www.jianshu.com/p/19cd34e957e7">https://www.jianshu.com/p/19cd34e957e7</a> */ public class DragFrameLayout extends FrameLayout { private float mDownX; private float mDownY; private int mRootTopY = 0; private int mRootMeasuredWidth = 0; private int mRootMeasuredHeight = 0; private int minTouchSlop;//系统可以辨别的最小滑动距离 private boolean mHasMeasuredParent;//测量一次(如果父类动态改变,去掉此判断) private Context mContext; public DragFrameLayout(@NonNull Context context) { this(context, null); } public DragFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public DragFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; minTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } @Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { super.requestDisallowInterceptTouchEvent(disallowIntercept); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { boolean interceptd = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: interceptd = false; //测量按下位置 mDownX = event.getX(); mDownY = event.getY(); //测量父类的位置和宽高 if (!mHasMeasuredParent) { ViewGroup mViewGroup = (ViewGroup) getParent(); if (mViewGroup != null) { //获取父布局的高度 mRootMeasuredHeight = mViewGroup.getMeasuredHeight(); mRootMeasuredWidth = mViewGroup.getMeasuredWidth(); int top = mViewGroup.getTop(); //获取父布局顶点的坐标 mRootTopY = mViewGroup.getTop(); ; mHasMeasuredParent = true; } } break; case MotionEvent.ACTION_MOVE: //计算移动距离 判定是否滑动 float dx = event.getX() - mDownX; float dy = event.getY() - mDownY; if (Math.abs(dx) > minTouchSlop || Math.abs(dy) > minTouchSlop) { interceptd = true; } else { interceptd = false; } break; case MotionEvent.ACTION_UP: interceptd = false; break; } return interceptd; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //解决parentView或者ancestorsView为ScrollView时,当前View不能自动滑动的问题 getParent().requestDisallowInterceptTouchEvent(true); Log.e("TAG", "yhhhhhhhh"); break; case MotionEvent.ACTION_MOVE: getParent().requestDisallowInterceptTouchEvent(true); if (mDownX >= 0 && mDownY >= mRootTopY && mDownX <= mRootMeasuredWidth && mDownY <= (mRootMeasuredHeight + mRootTopY)) { float dx = event.getX() - mDownX; float dy = event.getY() - mDownY; float ownX = getX(); //获取手指按下的距离与控件本身Y轴的距离 float ownY = getY(); //理论中X轴拖动的距离 float endX = ownX + dx; //理论中Y轴拖动的距离 float endY = ownY + dy; //X轴可以拖动的最大距离 float maxX = mRootMeasuredWidth - getWidth(); //Y轴可以拖动的最大距离 float maxY = mRootMeasuredHeight - getHeight(); //X轴边界限制 endX = endX < 0 ? 0 : endX > maxX ? maxX : endX; //Y轴边界限制 endY = endY < 0 ? 0 : endY > maxY ? maxY : endY; //开始移动 setX(endX); setY(endY); } break; case MotionEvent.ACTION_UP: getParent().requestDisallowInterceptTouchEvent(false); break; } super.onTouchEvent(event); return true; } }
解决在ScrollView中放入自定义可拖动的控件时,子控件滑动异常的问题
原文:https://www.cnblogs.com/jianglijs/p/14655056.html