自定义View解决滑动冲突
来源:互联网 发布:萌萌猪软件系统开发 编辑:程序博客网 时间:2024/05/16 10:53
最近在读Android开发艺术探索,本文作为自己对view的滑动冲突的理解和实践记录
而滑动冲突,需要了解Android的事件分发机制,如果这个还有些疑惑的地方,请参考这篇文章,以及其中的参考文章
还需要View的Measure和Layout的相关知识View的Measure流程总结
自定义view注意
1.如果直接继承view,此时wrap_content和使用match_parent效果一样.需要在onMeasure()
中处理AT_MOST
条件,处理wrap_content.
2.margin
要在onLayout中设定,padding
需要在 onDraw中设定
3.刷新回调,停止县城或者动画 在view.onDetachedFromWindow
4.在dispatchTouchEvent
和TouchEvent
中处理好滑动事件.
滑动冲突的种类
场景一:外部和内部俩层滑动方向不一致
场景二:外部和内部俩层滑动方向一致
场景三:主要是针对场景一和二的嵌套
滑动处理千篇一律, 只要你找到什么时候父控件滑动,什么时候子空间滑动.然后再父布局中,选择 是否自己处理onInterceptTouchEvent()
,就好了.
Android开发艺术探索中有两种方式,分别为外部拦截发,和内部拦截法.我上面说的是外部拦截法(感觉这个好用些).
具体的内容,大家可以看 Android开发艺术探索第三章第五节相关内容.
情形1的处理
先上效果图
下面是自定义的view,解决了上述情景1的问题.
/** 自定义滑动viewPager * Created by chenchangjun on 17/7/14. */public class HorizontalScrollView extends ViewGroup { private static final String TAG = HorizontalScrollView.class.getSimpleName(); private int mChildWidth = 1; private int mChildIndex = 1; private int mLastX; private int mLastY; private int mLastXIntercept = 0; private int mLastYIntercept = 0; /** * Scroller只是个计算器,处理滑动效果的,例如ViewPager,listview等的内部类 */ private Scroller mScroller; /** * 速度获取器 */ private VelocityTracker mVelocityTracker; private int mChildrenCount; private void init() { mScroller = new Scroller(getContext()); mVelocityTracker = VelocityTracker.obtain(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean intercept = false; int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: intercept = false; if (!mScroller.isFinished()) { mScroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastXIntercept; int deltaY = y - mLastYIntercept; if (Math.abs(deltaX) > Math.abs(deltaY)) { intercept = true; } else { intercept = false; } break; case MotionEvent.ACTION_UP: intercept = false; break; default: break; } Log.d(TAG, "intercept=" + intercept); mLastX = x; mLastY = y; mLastXIntercept = x; mLastYIntercept = y; return intercept; } @Override public boolean onTouchEvent(MotionEvent event) { mVelocityTracker.addMovement(event); int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (!mScroller.isFinished()) { mScroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastX; scrollBy(-deltaX, 0);//视觉上向右滑动,相对的,view横向向左移动. break; case MotionEvent.ACTION_UP: int scrollX = getScrollX();// int srcollToChildIndex=scrollX/mChildWidth; mVelocityTracker.computeCurrentVelocity(1000); float xVelocity = mVelocityTracker.getXVelocity(); if (Math.abs(xVelocity) >= 30) { //当一秒滑动像素大于30像素的时候, mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;//计算pager下标mChildIndex.如果手指从右向左,则xVelocity为负,mChildIndex+1;反之,易然. } else { mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth; } int dex=0; /* if (mChildIndex >= getChildCount()) { mChildIndex = 0; } else if (mChildIndex < 0) { mChildIndex = getChildCount() - 1; } else { dex = mChildIndex * mChildWidth - scrollX; }*/ mChildIndex=Math.max(0,Math.min(mChildIndex,mChildrenCount-1)); dex = mChildIndex * mChildWidth - scrollX; smoothScrollBy(dex, 0); mVelocityTracker.clear(); break; default: break; } mLastX = x; mLastY = y; return true; } private void smoothScrollBy(int dx, int dy) { mScroller.startScroll(getScrollX(), 0, dx, 0, 500); invalidate(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childLeft = 0; final int childCount = getChildCount(); mChildrenCount = childCount; for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { mChildWidth = child.getMeasuredWidth(); child.layout(childLeft, 0, childLeft + child.getMeasuredWidth(), child.getMeasuredHeight()); childLeft += mChildWidth; } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measuredWidth = 0; int measuredHeight = 0; final int childCount = getChildCount(); measureChildren(widthMeasureSpec, heightMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); if (childCount == 0) { setMeasuredDimension(0, 0); } else if (heightSpecMode == MeasureSpec.AT_MOST && widthSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0);//因为这里的child都是同类,所以偷懒~取第一个测量尺寸就够啦 measuredWidth = childView.getMeasuredWidth() * childCount; measuredHeight = childView.getMeasuredHeight() * childCount; setMeasuredDimension(measuredWidth, measuredHeight); } else if (heightSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0);//因为这里的child都是同类,所以偷懒~取第一个测量尺寸就够啦 measuredHeight = childView.getMeasuredHeight() * childCount; setMeasuredDimension(widthSpaceSize, measuredHeight); } else if (widthSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0);//因为这里的child都是同类,所以偷懒~取第一个测量尺寸就够啦 measuredWidth = childView.getMeasuredWidth() * childCount; setMeasuredDimension(measuredWidth, heightSpaceSize); } else { setMeasuredDimension(widthSpaceSize, heightSpaceSize); } } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } @Override protected void onDetachedFromWindow() { mVelocityTracker.recycle(); super.onDetachedFromWindow(); } public HorizontalScrollView(Context context) { super(context); init(); } public HorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public HorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public HorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); }}
总结
对于第一种,思路是在ACTION_MOVE
的时候,判断x偏移量是否大于y的偏移量.如果大于,就page++,.
对于第二种,需要判断子view是否滑动到了顶部,或者底部,如果是,让父控件滑动即可.
对于第三种,需要结合第一种,和第二种进行判断.
在判断滑动冲突的过程中,重点放在 InterceptTouchEvent()中,还有TouchEvent种进行处理.
- 自定义View解决滑动冲突
- 自定义View解决滑动冲突
- 自定义View---怎么解决View的滑动冲突
- 解决viewpager与自定义view滑动冲突的问题
- View的滑动冲突解决
- android View滑动冲突解决
- view的滑动冲突解决
- 自定义View事件拦截机制(自定义viewGroup和外部法解决滑动冲突)
- View滑动冲突解决的套路
- ViewPager子View滑动事件冲突解决
- [Android] 解决 View 滑动冲突法则
- ViewPager子View滑动事件冲突解决
- View的滑动冲突(通用解决方式)
- android View滑动冲突的解决方式
- ViewPager子View滑动事件冲突解决
- ViewPager子View滑动事件冲突解决
- 一文解决Android View滑动冲突
- 解决ListView与ScrollView的滑动冲突(非自定义View方案)
- MOOC清华《程序设计基础》第6章:橱窗插花问题(递推法)
- 【LeetCode】617. Merge Two Binary Trees
- 图像二值化----otsu(最大类间方差法、大津算法)
- glfw使用固定管线设置
- 华为mate8对flex的支持
- 自定义View解决滑动冲突
- C++操作mysql方法总结(1)
- Android Studio无法识别Java文件。红色J
- ISP、IAP、ICP烧写方式的区别
- CodeForces
- CODEGEN: 参数“GetDataResult”需要其他方案信息,使用参数模式无法捕获这些信息。特定特性为“System.Xml.Serialization.XmlElementAttribute
- 图片加载
- spyder 护眼背景
- 卸载CDH5