美文网首页Android开发自定义控件,viewAndroid技术知识
Android View相关总结与View绘制原理解析

Android View相关总结与View绘制原理解析

作者: Yink_Liu | 来源:发表于2017-06-28 12:53 被阅读0次

    一 view基础

    位置参数、MotionEvent、TouchSlop、VelocityTracker、GestureDetector和滑动

    1.1 位置参数

    相对于父容器
    left:左上角横坐标 right:右下角横坐标 top:左上角纵坐标 bottom:右下角纵坐标
    x:左上角横坐标 y:左上角纵坐标 translationX:左上角想对于父容器的横向偏移量 translationY:左上角想对于父容器的纵向偏移量 偏移量默认为0;
    八个参数都有get/set方法:e.g:setLeft(); getLeft();
    width = right - left;
    height = bottom - top;
    view平移时:left、right、top、bottom原始信息,值不变,对应改变的是x、y、translationX、translationY;

    1.2 MotionEvent && TouchSlop

    1.2.1 MotionEvent:

    事件:ACTION_DOWN、ACTION_UP、ACTION_MOVE、ACTION_CANCEL等
    点击事件坐标:
    getX/getY,当前view左上角坐标;
    getRawX/getRawY,想对于手机屏幕左上角坐标;

    1.2.2 TouchSlop:

    被系统认定为滑动的最小距离
    获取这个值:ViewConfiguration.get(Context).getScaledTouchSlop();
    ViewConfiguration中还定义了很多其他值

    1.3 VelocityTracker、GestureDetector、滑动

    1.3.1 velocityTracker速度追踪

    //追踪当前速度
    VelocityTracker velocityTracker = VelocityTracker.obtain();
    velocityTracker.addMovement(event);
    //获取1000ms时间的速度
    velocityTracker.computeCurrentVelocity(1000);
    int xVelocity = (int) velocityTracker.getXVelocity();
    int yVelocity = (int) velocityTracker.getYVelocity();
    //回收
    velocityTracker.clear();
    velocityTracker.recycle();
    

    1.3.2 GestureDetector

    检测单击、滑动、长按、双击等行为。

    //创建对象,实现OnGestureListener或者OnDoubleTapListener接口。this代表实现的接口
    GestureDetector mGestureDetector = new GestureDetector(this);
    //解决长安无法拖动
    mGestureDetector.setIsLongpressEnabled(false);
    //在onTouchEvent中接管监听view
    boolean onsume = mGestureDetector.onTouchEvent(event);
    return onsume;
    ```javascript
    然后在OnGestureListener和OnDoubleTapListener监听
    OnGestureListener:
    

    onDown:即ACTION_DOWN
    onShowPress:手指按下,未松开未拖动
    onSingleTapUp:单击行为的ACTION_UP
    onScroll:按下并拖动
    onLongPress:长按
    onFling:按下,快速滑动后松开

    onDoubleTapListener:
    onSingleTapConfirmed:单击行为 (不会是双击中的一次)
    onDoubleTap:双击
    onDoubleTapEvent:双击行为中的ACTION_DOWN ACTION_MOVE ACTION_UP都会触发

    ###1.3.3 滑动
    scrollTo/scrollBy
    只滑动内容,不改变view在布局中的位置
    mScrollX、mScrollY,view内容位置和布局位置的距离
    从左向右滑动100,mSrollX = -100; 其他类似
    
    #二 view的事件分发
    ##2.1 事件传递规则
    用一张图就可以掌握
    
    ![](https://img.haomeiwen.com/i3633065/46e707cef0d7f2a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    箭头代表代码会这样走,会如何去调用
    onInterceptTouchEvent事件拦截,只有viewgroup才有
    除了onInterceptTouchEvent其他的返回true都是消费。
    理清这个图,在脑海里有个U型概念,记住onInterceptTouchEvent,其它规则都相似
    ##2.2 滑动冲突
    理解了事件的分发,滑动冲突就很好解决了。方法通常有两种
    外部拦截:父视图需要就拦截,不需要就分发下去。
    内部拦截:父视图都不拦截,子视图需要就消费,不需要就传递给父视图消费。
    这里推荐使用外部拦截:即onInterceptTouchEvent
    ```javascript
    case MotionEvent.ACTION_DOWN:
        intercepted = false;
        break;
    case MotionEvent.ACTION_MOVE:
        if (需要父视图消费){
            intercepted = true;
        } else {
            intercepted = false;
        }
        break;
    case MotionEvent.ACTION_UP:
        intercepted = false;
        break;
    

    三 View的工作原理

    3.1 绘制过程

    三大过程:onMeasure测量、onLayout布局、onDraw画

    3.1.1

    如何绘制出来:
    DecorView:顶级view
    Viewroot:即viewrootImpl,WindowManager创建ViewRoot来管理DecorView

    DecorView一般为一个竖直方向的LinearLayout,LinearLayout分为上下两个部分(主要跟设置主题有关)
    上面是标题栏,下面是内容栏。例:activity中setContentView而不是setView

    3.1.2三大流程

    viewrootImpl中performTraversals函数开始绘制DecorView
    performTraversals中依次调用performMeasure、performLayout、performDraw

    Measure

    (viewrootImpl)performTraversals -> (viewrootImpl)performMeasure -> (DecorViwe)measure -> (DecorViwe)onMeasure
    DecorViwe的onMeasure中调用super.onMeasure即 (FrameLayout)onMeasure
    在(FrameLayout)onMeasure中:

    int count = getChildCount();
    ...
    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        ...
        measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
        ...
    

    如此遍历所有view树,layout过程类似

    onDraw

    (viewrootImpl)performTraversals -> (viewrootImpl)performDraw -> (viewrootImpl)Draw -> (viewrootImpl)drawSoftware
    看下drawSoftware有这样一句话

    mView.draw(canvas);
    

    这个draw方法就是view.java中的draw
    在View中draw有如下代码:

    ...
    drawBackground(canvas);
    ...
    onDraw(canvas);
    ...
    dispatchDraw(canvas);
    ...
    

    最后调用到ViewGroup的dispatchDraw,遍历子view

    for (int i = disappearingCount; i >= 0; i--) {
       final View child = disappearingChildren.get(i);
       more |= drawChild(canvas, child, drawingTime);
    }
    

    看下drawChild

    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
            return child.draw(canvas, this, drawingTime);
        }
    

    相关文章

      网友评论

        本文标题:Android View相关总结与View绘制原理解析

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