View

来源:互联网 发布:在淘宝买狗狗安全吗 编辑:程序博客网 时间:2024/06/05 02:36

View的位置参数
view的位置由它的四个顶点决定,分别对应View的四个属性:top、left、right、bottom,其中top是左上角的纵坐标,left是左上角横坐标,right是右下角横坐标,bottom是右下角纵坐标。从3.0开始View增加了额外的几个参数:x、y、translationX、translationY,其中x、y是View左上角的坐标,translationX、translationY是View左上角相对容器的偏移量。需要注意的是:view在平移的过程中,top和left表示原始左上角的位置信息,它的值不会改变,发生改变的是x、y、translationX、translationY这四个参数。
## MotionEvent和TouchSlop ##
在手指接触屏幕后所产生的一系列事件可以理解为MotionEvent。MotionEvent对象可以得到我们点击发生的x和y坐标。提供了两组方法:getX/getY和getRawX/getRawY。getX/getY返回的是相对于当前View左上角的x和y,而getRawX/getRawY返回的是相对于手机屏幕左上角的x和y坐标。

TouchSlop
TouchSlop是系统所能识别出的被认为是滑动的最小距离。这是一个常量,在不同设备中这个常量不同。

VilocityTracker、GestureDetector和Scroller

1.VilocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。

  1. 首先在View的onTouchEvent方法中追踪当前的速度:
    VelocityTracker velocityTracker = VelocityTracker.obtain();
    velocityTracker.addMovement(event);
    2.通过下面方法获得速度,1000为时间间隔
    velocityTracker.computeCurrentVelocity(1000);
    int xVelocity = (int)velocityTracker.getXVelocity();
    int yVelocity = (int)velocityTracker.getYVelocity();

各种滑动方式对比

  • scrollTo/scrollBy这种方式,他是View提供的原生方法,其作用是专门用于View的滑动,它可以比较方便的实现滑动的效果并且不影响内部元素的单击事件。但是他的缺点也很明显,他只能滑动View的内容,并不能滑动View本身。
  • 动画。在3.0以上的系统中可以用属性动画,3.0一下就只能使用nineold了。如果该View不需要响应用户的交互,那么使用动画来做滑动是比较合适的。它还有一个优点就是,如果一些复杂的效果必须要通过动画才能实现。
  • 通过改变布局达到移动View的效果。这个没有明显的缺点,有点就是移动之后该View具有交互性。
    针对以上的总结:

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

  • 动画:操作简单,主要适用于没有交互的View和实现复杂的动画效果;
  • 改变布局参数:操作稍微复杂,适用于有交互的View

事件分发

事件分发由三个很重要的方法来共同完成:dispatchTouchEvent、onInterceptTouchEvent和ontouchEvent.
对于一个Viewgroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouckEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理。如果这个ViewGroup的onInterceptTouchEvent方法返回false,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会调用,如此反复直到事件被最终处理。
## 关于事件传递得出的一些结论 ##

  • 同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最终以up事件结束。
  • 正常情况下,一个事件序列只能被一个View拦截且消耗。一旦一个元素拦截了此次事件,那么同一个事件序列内的所有事件都会直接交给它,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段,比如一个View将本该自己处理的事件通过ontouchevent强行传递给其他View处理。
  • 某个View一旦决定拦截,那么这一个事件序列都只能由它来处理,并且它的onInterceptT
    ouchEvent不会在被调用。
  • 某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件,那么同一个事件序列的其他事件都不会再交给它来处理,并且事件将重新交由它的父元素去处理。
  • 如果View不消耗除ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的ontouchevent并不会被调用,并且当前View可以持续收到后续的事件,最终这些消失的点击事件会传递给Activity处理。
  • ViewGroup默认不拦截任何事件。android源码中ViewGroup的onInterceptTouchEvent方法默认返回false。
  • View没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它的ontouchevent方法就会被调用。
  • View的ontouchevent默认都会消耗事件,除非它是不可点击的。View的longClickable默认都是false,clickable要分情况。
  • View的enable属性不影响ontouchevent的默认返回值。哪怕一个View是disable状态的,只要它的clickable或者longClickable有一个为true,那么它的onTouchEvent就返回true。
  • onCick会发生的前提是当前View是不可点击的,并且它收到down和up的事件。
  • 事件传递过程是由外向内的,即事件总是先传递给父元素,然后再由父元素交给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。

View的工作原理

DecorView作为顶层的View,一般情况下它内部会包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下两个部分,上面是标题栏,下面是内容栏。这个内容栏其实是一个FragmeLayout,View层的事件都是先经过DecorView,然后才传递给我们的View。

MeasureSpec
MeasureSpec代表一个32位int值,高2位代表SpecMode,低30位代表SpecSize,specMode是指测量模式,而SpecSize是指在某种测量模式下的规格大小。SpecMode有三类,每一类都表示特殊的含义,如下所示:

  1. UNSPECIFIED:父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。
  2. EXACTLY:父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值,它对应LayoutParams中的match_parent和具体的数值这两种模式
  3. AT_MOST:父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么值要看不同View的具体实现,它对应于LayoutParams中的wrap_content.

    对于一个普通的View,其MeasureSpec由父容器的MeasureSpec和自己的LayoutParas来共同决定,那么针对不同的父容器和View本身不同的LayoutParams,View就可以有多种MeasureSpec。

View的工作流程

View的工作流程主要是指measure、layout、draw这三大流程,即测量、布局和绘制,其中measure确定View的测量宽/高,layout确定View的最终宽/高和四个顶点的位置,而draw则将View绘制到屏幕上。
1,measure过程
如果是一个ViewGroup,那么通过measure方法就完成了其测量过程之外,还要遍历调用所有的子元素的measure方法,各个子元素再递归去执行这个流程。如果是一个View,那么通过measure方法就完成了其测量过程。
View的measure过程和activity的生命周期不同步,因此无法保证在onCreate、onStart、onResume时某个时期View已经测量完毕了,如果View还没有测量完毕,那么获得的宽、高就是0.
## layout过程 ##
Layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,他在OnLayout中会遍历所有的子元素并调用layout方法。layout方法确定View本身的位置,而onLayout方法则会确定所有子元素的位置。
## draw过程 ##
Draw的作用是将View绘制到屏幕上面。View的绘制过程遵循如下几步:
绘制背景background.draw(canvas);
绘制自己(onDraw)
绘制children(dispatchDraw)
绘制装饰(onDrawScrollBars)

自定义View

自定义View须知
1,让View支持wrap_content
这是因为直接继承View或者ViewGroup的控件,如果不再onMeasure中对wrap_content做特殊处理,那么当外界在布局中使用wrap_content时就无法达到预期的效果。
2,如果有必要,让你的View支持padding
这是因为直接继承View的控件,如果不再draw方法中处理padding,那么padding属性是无法起作用的。另外,直接继承ViewGroup的控件需要在onMeasure和onLayout中考虑padding和子元素的margin对其造成的影响,不然将导致padding和子元素的margin失效。
3,尽量不要在View中使用Handler,没必要
这是因为View内部本身就提供了post系列的方法,完全可以替代Handler的作用,当然除非你很明确要使用Handler来发消息。
4,View中如果有线程或者动画,需要及时停止。调用onDetachedFromWindow
如果有线程或者动画需要及时停止,那么onDetachedFromWindow是一个很好的时机。当包含此View的activity退出或者当前View被remove时,View的onDetachedFromWindow方法会被调用,和此方法对应的是onAttachedToWindow,放包含此View的Activity启动时,View的onAttachedToWindow方法会被调用。
5,View带有滑动嵌套情形时,需要处理好滑动冲突

0 0
原创粉丝点击