阅读本章你将了解:
1.MotionEvent(运动事件) 2.TouchSlop(触摸坡;最小滑动距离,每个手机大小不一) 3.VelocityTracker (速度追踪) 4.GestureDetector(手势检测器) 5.Scroller(弹性滑动)
3.1 view的基础知识
什么是view view extends View ViewGroup extends View
3.1.2
View的4个属性:
top 左上角纵坐标 left 左上角横坐标 bottom 右下角纵坐标 right 右下角横坐标
View的宽高和坐标关系:
left = getLeft(); right= getRight(); top= getTop() bottom = getBottom();
width = right -left; height = bottom - top;
3.0新增参数:View平移的时候只有x,y,translationX,translationY改变
x = left + translationX; y = top + tanslationY;
3.1.3
MotionEvent(运动事件)和TouchSlop (最小滑动距离)
MotionEvent: MotionEvent.ACTION_DOWN 接触 MotionEvent.ACTION_MOVE 移动 MotionEvent.ACTION_UP 松开 getX/getY 当前view左上角x,y坐标 getRawX/getRawY 手机屏幕左上角x,y坐标 TouchSlop: ViewConfiguration.get(this).getScaledTouchSlop();常量
3.1.4
VelocityTracker (速度追踪)丶GestureDetector(手势检测器) 1.VelocityTracker (速度追踪): 速度 = (终点位置 - 起点位置)/时间段 手指逆着坐标系的正反向滑动,速度是负值
@Override public boolean onTouchEvent(MotionEvent event) { //在view的onTouchEvent追踪点击事件的速度 VelocityTracker velocityTracker = VelocityTracker.obtain(); velocityTracker.addMovement(event); //1s内划过的像素 velocityTracker.computeCurrentVelocity(1000); int xVelocity = (int) velocityTracker.getXVelocity(); int yVelocity = (int) velocityTracker.getYVelocity(); //用完了重置回收 velocityTracker.clear(); velocityTracker.recycle(); return super.onTouchEvent(event); }2.GestureDetector(手势检测器):
常用的方法:
onSingleTapUp(单击)onFling(快速滑动)onScroll(拖动)onLongPress(长按)onDoubleTap(双击)建议:滑动相关,直接在onTouchEvent实现;双击使用GestureDetector
3.2
View的滑动 三种方式:
1.使用scrollTo/scrollBy 2.动画平移 3.改变view的LayoutParams1.使用scrollTo/scrollBy
scrollTo/scrollBy方法只能改变view内容的位置,不能改变view位置 从上往下滑动:getScrollY < 0 反之:getScrollY > 0 从左往右滑动:getScrollX < 0 反之:getScrollX > 0
2.动画平移
使用属性动画(>3.0) View v = null ; ObjectAnimator.ofFloat(v,”translationX”,0,100).setDuration(1000).start(); 3.0以前上述代码会出现:view移动了,”真身”还在原地,点击原地触发onClick 3.0以后没有问题了
3.改变view的LayoutParams
View v = null; ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); layoutParams.width += 100; layoutParams.leftMargin += 100; v.requestLayout(); //或者 v.setLayoutParams(layoutParams);几种方式的比较:
scrollTo/scrollBy:操作简单,适合view内容滑动 动画:不交互的view(点击事件故障) 改变view的layoutParams:操作复杂,适用于有交互的view3.3 Scroller(弹性滑动)
1.使用Scroller实现弹性滑动 Scroller本身无法让View弹性滑动,它需要和View的computeScroll方法配合
package com.weiwei.zx.wp; import android.content.Context; import android.view.View; import android.widget.Scroller; /** * Created by zx on 2016/1/7. */ public class MyView extends View { private Scroller mScroller; public MyView(Context context) { super(context); mScroller = new Scroller(context); //缓慢滚动到指定位置 smoothScrollTo(2,2); } private void smoothScrollTo(int destX, int destY) { int scrollX = getScrollX(); int delta = destX - scrollX; //1s内滑向destX,效果就是慢慢滑动 //startScroll(滑动的起点) mScroller.startScroll(scrollX,0,delta,0,1000); invalidate();//view重绘 } @Override public void computeScroll() { if(mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); postInvalidate(); } } }原理:多次view重绘导致view多次小幅度滑动(弹性滑动)
1.调用invalidate()不断让view重绘 2.通过重绘距滑动起始时间间隔,得到view当前滑动位置 3.通过scrollTo滑动
2.使用动画实现弹性滑动(view的内容滑动)
动画天然就具有弹性效果,思想和scroller类似
3.使用延时策略
思想:不断的发送延时消息,实现弹性效果(handle.postDelayed)
3.4 View的事件分发机制
1.touchEvent传递到顶层view的dipatchTouchEvent
2.由dipatchTouchEvent分发;返回true,交给touchEvent处理;false交给onIntercepterTouchEvent处理
3、onIntercepterTouchEvent返回true交给它的touchEvent处理,返回false传递给子view 总结:onInterceptTouchEvent是自rootiew向下传递, onTouchEvent正好相反。
3.5 View的滑动冲突
场景: 1.外部滑动方向和内部滑动方向不一致(viewpager+fragment) 2.外部滑动方向和内部滑动方向一致(listview+listview) 3.上面2中情况的嵌套
解决方法:
1.外部拦截法(通过滑动距离差,符合view的事件分发机制) 重写onInterceptTouchEvent方法,在方法中做相应拦截 2.内部拦截法(配合requestDisallowInterceptTouchEvent,和事件分发机制不一致) 推荐使用: 外部拦截法(简单易用)