每日一学——自定义View(源码及原理)(一)

先了解自定义View

1. 自定义view的基本方法:

  • 测量:onMeasure()函数决定View的大小,相关方法——measure(),setMeasuredDimension(),onMeasure();
  • 布局:onMeasure()函数决定View的大小,相关;
  • 绘制:onDraw()函数决定绘制这个View。

2. View分类:

  • 单一视图:一个view,不嵌套包含其他子view;
  • 视图组:多个View组成的ViewGroup;

3. 自定义控件分类:

  • 自定义View:只需要重写onMeasure()、onDraw()方法;

  • 自定义ViewGroup:只需要重写onMeasure()、onLayout()方法;

    借个图简单的诠释下自定义View
    每日一学——自定义View(源码及原理)(一)_第1张图片

4. View类:

  • 组件的基类:如View是ViewGroup基类;
  • Android中的UI组件都由View、ViewGroup组成
  • View的构造函数代码:
//如果View是Java代码里new的,则调用第一个构造函数
public CarsonView(Context context){
	super(context);
}

// 如果View是在.xml里声明的,则调用第二个构造函数 
// 自定义属性是从AttributeSet参数传进来的   
 public  CarsonView(Context context, AttributeSet attrs) {       
  super(context, attrs);    
  }

// 不会自动调用 
// 一般是在第二个构造函数里主动调用 
// 如View有style属性时    
public  CarsonView(Context context, AttributeSet attrs, int defStyleAttr) {    
    super(context, attrs, defStyleAttr);    
    }
    
    
 //API21之后才使用    
 // 不会自动调用   
 // 一般是在第二个构造函数里主动调用  
 // 如View有style属性时  
 public  CarsonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {     
       super(context, attrs, defStyleAttr, defStyleRes);   
    }


5. AttributeSet与自定义属性 :
系统自带的View可以在xml中配置属性,对于写的好的自定义View同样可以在xml中配置属性,为了使自定义的 View的属性可以在xml中配置,需要以下4个步骤:

  • 通过 为自定义View添加属性

  • 在xml中为相应的属性声明属性值

  • 在运行时(一般为构造函数)获取属性值

  • 将获取到的属性值应用到View

  • 自定义属性的声明文件—value/attrs.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="test">
            <attr name="text" format="string" />
            <attr name="testAttr" format="integer" />
        </declare-styleable>
    </resources>
  • 自定义View类:
public class NewTextView extends View {
    private static final String TAG = NewTextView.class.getSimpleName();

    //在View的构造方法中通过TypedArray获取
    public NewTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);
        String text = ta.getString(R.styleable.test_testAttr);
        int textAttr = ta.getInteger(R.styleable.test_text, -1);
        Log.e(TAG, "text = " + text + " , textAttr = " + textAttr);
        ta.recycle();
    }
}
  • 应用到布局View:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res/com.example.test"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.test.NewTextView
        android:layout_width="100dp"
        android:layout_height="200dp"
        app:testAttr="520"
        app:text="helloworld" />

</RelativeLayout>

6. View视图结构:

  • PhoneWindow是Android系统中最基本的窗口系统,继承自Windows类,负责管理界面显示以及事件响应。它
    是Activity与View系统交互的接口

  • DecorView是PhoneWindow中的起始节点View,继承于View类,作为整个视图容器来使用。用于设置窗口属
    性。它本质上是一个FrameLayout

  • ViewRoot在Activtiy启动时创建,负责管理、布局、渲染窗口UI等等

每日一学——自定义View(源码及原理)(一)_第2张图片
注意!!! :
无论是measure过程、layout过程还是draw过程,永远都是从View树的根节点开始测量或计算(即从 树的顶端开始),一层一层、一个分支一个分支地进行(即树形递归),最终计算整个View树中各个View,最终确定整个View树的相关属性

7 坐标系:
Android坐标系:
每日一学——自定义View(源码及原理)(一)_第3张图片
view坐标系:
每日一学——自定义View(源码及原理)(一)_第4张图片
View的位置

 getLeft();      //获取子View左上角距父View左侧的距离  
 getBottom();    //获取子View右下角距父View顶部的距离  
 getRight();     //获取子View右下角距父View左侧的距离
 getTop();       //获取子View右下角距父View顶部的距离

触点MotionEvent的位置:

//get() :触摸点相对于其所在组件坐标系的坐标 
 event.getX();       
 event.getY();
 
//getRaw() :触摸点相对于屏幕默认坐标系的坐标
 event.getRawX();     
 event.getRawY();

View树的绘制流程

view树的绘制流程是通过ViewRoot去负责绘制的,ViewRoot其实不是View的根节点,它连view节点都算不上,它的主要作用 是View树的管理者,负责将DecorView和PhoneWindow“组合”起来,而View树的根节点严格意义上来说只有 DecorView;每个DecorView都有一个ViewRoot与之关联,这种关联关系是由WindowManager去进行管理的

布局的绘制阶段:
每日一学——自定义View(源码及原理)(一)_第5张图片

具体的代码实现见下一篇博客:
每日一学——自定义View(具体实现代码)(二)

你可能感兴趣的:(Android自定义View)