美文网首页
《Android开发艺术》读书笔记1-View事件体系

《Android开发艺术》读书笔记1-View事件体系

作者: sunbinqiang | 来源:发表于2016-04-11 12:06 被阅读100次

    《Android开发艺术》是今年上半年的读书计划之一, 本文是第三章”View的事件体系”的总结。

    View基础知识

    View是Android所有控件的基类,ViewGroup即是一组View。

    View的参数位置, 由四个顶点的坐标确定: top, left, right, bottom.(坐标是相对于View的父容器);Android3.0以后增加了x, y(左上角的坐标) translationX, translationY(左上角相对于父容器的偏移量)。

    MotionEvent, 手指接触屏幕后所产生的一系列事件: Action_Down–> Action_Move –> …(move) –> Action_UP; 点击时的坐标getX/getY(相对于父容器), getRawX/getRawY(相对于手机屏幕)。

    TouchSlop, 系统识别最小的滑动距离(当距离小于该值, 不认为是进行滑动): ViewConfiguration.get(getContext()).getScaledTouchSlop().

    VelocityTracker 追踪手指在滑动过程中的速度。

    VelocityTracker velocityTracker = VelocityTracker.obtion();

    velocityTracker.addMovement(event);

    velocityTracker.computeCurrentVelocity(1000) //1000表示1000ms

    获取的值表示1000ms View移动的像素值。 当不需要使用时,需要调用clear方法进行回收内存:

    velocityTracker.clear();

    velocityTracker.recycle();

    GestureDetector, 辅助检测用户的单机, 滑动,长按,双击等行为。用户的触摸行为是在onTouchEvent事件中处理, 所以,需要使用GestureDetector的话, 在onTouchEvent方法中添加如下实现:boolean consume = mGestureDetector.onTouchEvent(event);

    Scoller, 弹性滑动对象。 View的scrollTo/scrollBy的方法是瞬间完成移动, 用户体验不佳; 所以使用弹性滑动Scroll, 可以在制定事件完成滑动:scroller.startScroll(scrollX, 0, delta, 0, 1000); // 1000ms内水平滑向destX

    View的滑动

    scrollTo/scrollBy ,只能将view的内容进行移动, 并不能将view本身进行移动。mScrollX参数代表View左边缘和View内容左边缘的距离; mScrollY同理

    动画,使用translate方法。注意动画也不能改变View的位置, 所以,点击事件并不会在新位置触发。

    布局参数, 通过改变布局参数MarginLayoutParams。

    滑动方式对比:

    scrollTo/scrollBy: 操作简单,适合对View内容的滑动;

    动画: 操作简单,适用于没有交互的View和实现复杂的动画效果;

    改变布局参数:操作复杂, 适用于有交互的View。

    弹性滑动

    Scroller, 通过源码分析, Scroller通过invalidate方法实现View的弹性滑动,确切的说是computeScroll方法, 具体流程: View重绘–>draw()–>computeScroll()–>getScrollX()–>scrollTo()滑动;–>postInvalidate() 二次重绘制, 如此反复, 直到过程结束。

    延时策略, 使用Handler或View的postDelay方法, 或者线程的sleep方法。 同样在每次执行过程中实现scrollTo方法, 实现每次滑动一点, 然后整体出现弹性滑动的效果。

    View的事件分发机制

    事件分发过程的三个重要方法

    1, public boolean dispatchTouchEvent(MotionEvent ev)

    事件分发函数: 如果事件能够传递给当前view,那么此方法一定会被调用,返回结果由当前view的onTouchEvent和下级view的dispatchTouchEvent方法的决定,表示是否消耗当前事件。

    2, public boolean onInterceptTouchEvent(MotionEvent event)

    dispatchTouchEvent是否拦截某个事件:如果当前view拦截了某个事件,那么在同一个事件序列当中,此方法不会再被调用,返回结果表示是否拦截当前事件。

    若返回值为True事件会传递到自己的onTouchEvent();

    若返回值为False传递到子view的dispatchTouchEvent()。

    3, public boolean onTouchEvent(MotionEvent event)

    用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前view无法再次接收到事件。

    若返回值为True,事件由自己处理,后续事件序列让其处理;

    若返回值为False,自己不消耗事件,由父容器的onTouchEvent接受处理。

    view的滑动冲突

    1, 常见的滑动冲突的场景:

    1.1 外部滑动方向和内部滑动方向不一致,例如viewpager中包含listview;

    1.2 外部滑动方向和内部滑动方向一致,例如viewpager的单页中存在可以滑动的bannerview;

    1.3 上面两种情况的嵌套,例如viewpager的单个页面中包含了bannerview和listview。

    2, 滑动冲突处理规则

    可以根据滑动距离和水平方向形成的夹角;或者根绝水平和竖直方向滑动的距离差;或者两个方向上的速度差等

    3, 解决方式

    3.1. 外部拦截法:点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要就不拦截。该方法需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可,其他均不需要做修改。

    3.2. 内部拦截法:父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器来处理。这种方法和Android中的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作。

    以上滑动冲突的demo会后续更新

    相关文章

      网友评论

          本文标题:《Android开发艺术》读书笔记1-View事件体系

          本文链接:https://www.haomeiwen.com/subject/uucblttx.html