Day15-View

View From

View 分类

单一视图 如 TextView
视图组 如 ViewGroup, LinearLayout

ViewGroup 继承自 View

View 构造函数

分为两大类

//如果是在 Java 代码里面 new 的
private CarsonView(Context context){
  super(context);
}


// 如果是在.xml里声明的
// 自定义属性由 attrs 传递
private CarsonView(Context context, Attribute attrs){
  super(context, attrs);
}

// 在第二种情况下,
// 当 view 包含 style 属性
private CarsonView(Context context, Attribute attrs, int defStyleAttr){
  super(context, attrs, defStyleAttr);
}

// API21后
// 在第二种情况下,
// 当 view 包含 style 属性时
private CarsonView(Context context, Attribute attrs, int defStyleAttr, int defStyleRes){
  super(context, attrs, defStyleAttr, defStyleRes);
}

attrs XML中的属性
defStyleAttr 应用到 View 的默认风格(定义在主题中)
defStyleRes 如果没有使用 defStyleAttr , 应用到View的默认风格

View 视图结构

Day15-View_第1张图片

无论是 measure, layout 还是 draw, 永远都是从根View开始测量/计算, 最终确定整个View的属性

View 坐标系

top, left, right, bottom 属性都是相对父容器的


Day15-View_第2张图片

View 获取位置

  • view.getLeft() 获取view左上角到父容器左侧的距离

  • MotionEvent中
    触摸点相对于其所在坐标系中的距离

    e.getX()
    e.getY()
    
  • 触摸点相对于屏幕的距离

    e.getRawX();
    e.getRawY();
    
Day15-View_第3张图片

Android 中角度和弧度

Day15-View_第4张图片

角度的增大方向为顺时针

Day15-View_第5张图片

自定义View From

1. Measure

1.1 方法

  1. measure()
    final 类型, 无法重写, 最终会调用 onMeasure()
    • onMeasure()
      自己重写
      • setMeasureDimension()
        存储测量后的宽高

        • setMeasuredDimensionRaw()
          设置 mMeasuredWidth 和 mMeasuredHeight
      • getDefaultSize()
        根据测量规格的模式, 给出测量值

1.2 测量过程

一个view的值由 自身的LayoutParams 和 父布局的 MeasureSpec 决定 (DecorView除外, 它没有父布局, 由自身的 LayoutParams 和 窗口尺寸决定)

Day15-View_第6张图片

2. Layout

2.1方法

  1. layout();
    确定 View 本身的位置
  2. onLayout;
    单一 View 空实现,
    ViewGroup 调用 onLayout 遍历子View 并调用子View layout()确定自身子View 的位置
    ViewGroup中 因为子view的确定位置与布局有关, 需重写

2.2 layout 过程

Day15-View_第7张图片

2.3 getWidth/getHeight 和 getMeasureWidth/getMeasureHeight 差别

  1. 定义
  • getWidth/getHeight view最终的宽高
  • getMeasureWidth/getMeasureHeight view的测量的宽高
  1. 代码

    // View的测量的宽 / 高:
    public final int getMeasuredWidth() {  
        return mMeasuredWidth & MEASURED_SIZE_MASK;  
        // measure 过程中返回的 mMeasuredWidth
    }  
    
    public final int getMeasuredHeight() {  
        return mMeasuredHeight & MEASURED_SIZE_MASK;  
        // measure 过程中返回的 mMeasuredHeight
    }  
    
    
    // View最终的宽 / 高
    public final int getWidth() {  
        return mRight - mLeft;  
    // View最终的宽 = 子View的右边界 - 子view的左边界。
    }  
    
    public final int getHeight() {  
        return mBottom - mTop;  
    // View最终的高 = 子View的下边界 - 子view的上边界。
    }
    
    
  2. 时机

  • getMeasureWidth/getMeasureHeight
    在 measure 的 setMeasureDimension()中setMeasureDimensionRaw 赋值, 在 onLayout 用它来获取宽高
  • getWidth/getHeight
    在 layout 的 layout()中赋值, 可以用于除 onLayout() 之外的地方获取宽高
  1. 结论
    在onLayout中用getMeasureWidth/Height(), 在其他地方用getWidth/Height()
    一般情况下两者的值是永远相等的, 与View是否超出屏幕无关,
    除非人为设置
    通过重写View的layout()强行设置,
    @Override
    public void layout( int l , int t, int r , int b){
    
    // 改变传入的顶点位置参数
     super.layout(l,t,r+100,b+100)
    // 如此一来,在任何情况下,getWidth() ( getHeight())获得的宽 / 高总是比getMeasuredWidth() (getMeasuredHeight())获取的宽 (高)大100px
    // View的最终宽 / 高总是比测量宽 / 高大100px
    }
    

3. draw

3.1 方法

  • draw()
    绘制自身
    1. drawBackground()
      绘制自身View的背景
    2. onDraw()
      绘制自身View的内容, 自定义View中必须且只需要重写onDraw
    3. dispatchDraw()
      单一View空实现
    4. onDrawScrollBar()
      绘制装饰
3.2 draw 过程
Day15-View_第8张图片

setContentView

Activity 在 android 中的根布局被分为 标题栏 + ContentView(外面包着 FrameLayout), 所以我们平时操作的都是 ContentView, 布局都是 setContentView, 而不是setView


Day15-View_第9张图片

因为外部有父布局FrameLayout, 所以属性 layout_width 和 layout_height 里的layout都是有的, 设置能起作用的
而如果我们通过纯代码方式创建布局, 如下:

LinearLayout mainLayout = (LinearLayout)findViewById(R.layout.main_layout);
LayoutInflater layoutInflater = LayoutInflater.from(this);
View buttonView = layoutInflater.inflate(R.layout.button_layout, null);
mainLayout.addView(buttonView);

再给button_layout添加 layout_width 和 layout_height 属性

  

会发现无效, 因为button_layout没有父布局, 所以套一个布局就能让属性生效了

  

      

  

参考
Android LayoutInflater原理分析,带你一步步深入了解View(一)
深入理解Android View的构造函数
自定义View Measure过程 - 最易懂的自定义View原理系列(2)
自定义View Layout过程 - 最易懂的自定义View原理系列(3)
自定义View Draw过程- 最易懂的自定义View原理系列(4)
Android开发之getMeasuredWidth和getWidth区别从源码分析

你可能感兴趣的:(Day15-View)