View的滑动方式及冲突处理
来源:互联网 发布:蘑菇街质量比淘宝好吗 编辑:程序博客网 时间:2024/05/16 03:44
实现滑动的方式:
实现view的滑动,本质上说都是改变view的坐标,不管是哪种方式实现滑动,实现的基本思想是一致的,当触摸View时,系统记下当前触摸点的坐标,当手指移动时,系统记下移动后的触摸点坐标,获取滑动的偏移量,并通过偏移量来修改View的坐标,不断重复,实现滑动过程.
- layout方法:
View绘制时,会调用onLayout()方法来设置显示的位置,同样,也可以修改View的left,top,right,bottom四个属性来控制View的坐标.
@override public boolean onTouchEvent(MotionEvent ev){ int rawX=(int)ev.getRawX(); int rawY= (int)ev.getRawY(); switch(ev.getAction()){ case MotionEvent.ACTION_DOWN: //记录触摸点坐标 lastX=rawX; lastY=rawY; break; case MotionEvent.ACTION_MOVE: //计算偏移量 int offsetX= rawX-lastX; int offsetY=rawY-lastY; //重新布局 layout(getLeft()+offsetX,getTop()+offsetY,getRight+offsetX,getBottom()+offsetY); //重置初始坐标点 lastX=rawX; lastY=rawY; break; } return true; }
- offsetLeftAndRight()与offsetTopAndBotton()方式
这两个方法其实就系统对上下左右移动API的封装,其本质还是完成View的重新布局,效果与layout()一样.
//同时对left和right进行偏移 offsetLeftAndRight(offsetX); //同时对top和bottom进行偏移 offsetTopAndBottom(offsetY);
- LayoutParams
LayoutParams保存了View的布局参数,通过改变LayoutParams来动态改变一个布局的位置参数,从而改变View的位置效果.通过LayoutParams方式改变View的布局,本质上是改变View的Margin属性,所以也可以通过改变MarginLayoutParams来实现.
LinnerLayout.LayoutParams params= (LinearLayout.LayoutParams)getLayoutParams(); params.leftMargin=getLeft()+offsetX; params.topMargin=getTop()+offsetY; setLayoutParams(params); //或者直接使用MarginLayoutParams ViewGroup.MarginLayoutParams params= (ViewGroup.MarginLayoutParam)getLayoutParams(); params.leftMargin=getLeft()+offsetX; params.topMargin=getTop()+offsetY; setLayoutParams(params);
scrollTo()与scrollBy()
scrollTo()是指View的绝对坐标的移动,而ScrollBy则是View的相对坐标的移动.另外scrollTo()与scollBy()方法移动的仅仅是View的内容,而不是View本身,这点要注意.- 如果要移动View,应该找到View所在ViewGroup,调用如下代码:
((View)getParent).scrollTo(x,y);
- scrollTo()与scrollBy()滑动都是一瞬间完成,显得太突兀,可以考虑和Scroller联合使用.
动画
使用动画应该注意Property Animation与View Animation的区别.
滑动冲突的处理
滑动冲突主要为三种场景:
- 外部滑动方向和内部滑动方向不一致
- 外部滑动方向和内部滑动方向一致
- 嵌套上面两种情况
处理冲突的规则:
- 对于外部滑动方向和内部滑动方向不一致情况,处理规则:当用户左右滑动时,需要让外部的View拦截点击事件,当用户上下滑动滑动时,需要让内部的View的拦截点击事件.具体点:谁需要滑动,谁就去拦截点击事件.
- 对于场景2,无法从滑动的角度,距离差,速度差来判断,一般都能在业务上找到突破点,比如当处于某种状态时需要外部View响应用户,而处于另一种状态时,需要内部View来响应View的滑动.
- 对于场景3,也是从业上寻找突破点,根据不同的情况实现不同的事件拦截即可.
处理滑动冲突的解决方式:
- 外部拦截法:
- 内部拦截法:
外部拦截法:
外部拦截法是指事件都先经过父容器的拦截处理,如果父容器需要此事件就去拦截,如果不需要就不拦截,外部拦截法需要重写父容器的
onInterceptTouchEvent()
方法,在内部做出相应的拦截即可.
public boolean onInterceptTouchEvent(MotionEvent ev){ boolean intercepted=false; int x= (int)event.getX(); int y= (int)event.getY(); switch(evnet.getAction){ case MotionEvent.ACTION_DOWN: //Action_down必须要返回false,一旦父容器拦截了ACTION_DOWN,那么后续的ACTION_MOVE和ACTION_UP事件都会交给父容器处理. intercepted=false; break; case MotionEvent.ACTION_MOVE: if(父容器需要当前点击事件){ intercepted=true; }else{ intercepted=false; } break; case MotionEvent.ACTION_UP: intercepted=false; break; } mLastXIntercept=x; mLastYIntercept=y; return intercepted; }
内部拦截法
内部拦截法,指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要就消费事件,否则交给父容器处理,这种方式需要配合
requestDiasllowInterceptTouchEvent()
才能正常进行,伪代码如下:
public boolean onInterceptTouchEvent(MotionEvent ev){ boolean intercepted=false; int x= (int)event.getX(); int y= (int)event.getY(); switch(evnet.getAction){ case MotionEvent.ACTION_DOWN: //请求父容器不拦截 parent.requestDiasllowInterceptTouchEvent(true) break; case MotionEvent.ACTION_MOVE: int deltaX=x-mLastX; int deltaY=y-mLastY; if(父容器需要当前点击事件){ //请求拦截 parent.requestDiasllowInterceptTouchEvent(false); }else{ } break; case MotionEvent.ACTION_UP: break; } mLastXIntercept=x; mLastYIntercept=y; return super.dispatchTouchEvent(event); }
除了子元素需要处理外,父元素也要做相应的处理,拦截除了ACTION_DOWN以外的其他事件,这样子元素才能调用requestDiasllowInterceptTouchEvent(false)
时,父元素才能拦截所需的事件:
public boolean onInterceptTouchEvent(MotionEvent ev){ if(evnet.getAction==MotionEvent.ACTION_DOWN){ return true; }else{ return false; } }
为什么父容器不能拦截ACTION_DOWN
事件呢?因为ACTION_DOWN
事件并不受FLAG_DISALLOW_INTERCEPT
这个标记控制,所以父容器拦截ACTION_DOWN
事件,那么所有的事件都无法传递到子元素中去.这样内部拦截就无法起作用了.
- View的滑动方式及冲突处理
- View滑动冲突的处理
- View的滑动冲突处理
- View滑动冲突处理
- View的滑动冲突(通用解决方式)
- android View滑动冲突的解决方式
- View的滑动方式及滑动冲突解决方法(事件分发)
- View 滑动冲突处理方法
- view 的滑动冲突
- View的滑动冲突
- View的滑动冲突
- View的滑动冲突
- View的滑动冲突
- View 的滑动冲突
- View的滑动冲突
- View 的滑动冲突
- View的滑动冲突
- View的滑动冲突
- iOS HTTPS安全请求 验证服务器返回的证书
- Datanode部分节点下线
- Thinkphp3.2.3 隐藏index.php
- 怎么才能做好一个软件销售
- 高并发web系统调优(五)数据缓存
- View的滑动方式及冲突处理
- JVM调优总结(六)-分代垃圾回收详述2
- GitHub常用优秀开源Android项目
- 安卓自定义状态栏颜色以与APP作风保持一致
- 【Hystrix权威指南一】Hystrix开发之旅
- linux分区和文件系统
- spring mvc出现java.lang.StackOverflowError错误
- 如何在本地搭建一个Android应用crashing跟踪系统-ACRA
- EAS F7 过滤 单头