浅析Android View内部工作原理及其实战

本文详细解析了Android中Activity窗口机制,包括UI界面架构和View树结构。接着深入探讨了View的测量、布局和绘制流程,重点介绍了测量模式。最后,通过实现CircleProgressView控件,阐述了自定义View的基本思路,包括构造方法、onMeasure、onSizeChanged、onDraw和onTouchEvent的重写。
摘要由CSDN通过智能技术生成

转载请声明出处:http://blog.csdn.net/andrexpert/article/details/77511996

     在Android开发中,当我们需要显示用户交互界面时,通常的做法是创建一个继承Activity的类并重写它的onCreate()方法,再在该方法中调用setContentView()方法将布局界面显示出来。那么问题来了,setContentView方法具体做了些什么呢?基于此,本文将详细讲解Activity窗口机制原理、View的绘制流程及其源码分析,然后实现一个CircleProgressView控件以剖析自定义view的基本思路。

一、Activity窗口机制原理
1. UI界面架构

     Activity是Android四大组件之一,是与用户交互的窗口。Activity类负责创建一个窗口,即Window对象,每个Activity都包含一个Windows对象,然后在该窗口中使用setContentView方法来放置需要显示的UI。Window类是一个抽象类,它封装了与顶层可见窗口和行为策略相关方法接口,其具体的实现交给PhoneWindow类来完成。PhoneWindow类是Window具体实现类,它内部包含了一个DecorView对象并且将该对象设置为整个应用窗口的根View。DecorView是PhoneWindow的内部类,继承于FrameLayout,它作为窗口界面的顶层视图,封装了一些窗口操作的通用方法,并将要显示的具体内容呈现在PhoneWindow上。

2. View树结构

 

     在Android中,所有的视图控件都是View或ViewGroup的子类,ViewGroup是View的子类。每个ViewGroup作为父控件,可以包含多个View,但是View不能包含View或ViewGroup。在布局中,View和ViewGroup之间的关系可以用数据结构中的树来描述,即ViewGroup通常作为父结点存在,而View作为叶子节点存在,它们以树的形式构成最终的布局界面,并由上层控件负责下层子控件的测量和绘制,然后传递交互事件。在每棵树的顶部,都有一个ViewParent对象,这是整棵树的控制核心,所有的交互管理事件都由它来统一调度和分配,从而可以对整个视图进行整体控制。

二、View绘制流程分析
     View的绘制过程主要经历三个阶段,即测量(Measure)、布局(Layout)、绘制(draw),其中,Measure的作用是测量要绘制View的大小;Layout的作用是明确要绘制View的具体位置;draw的作用就是绘制View。
1. measure流程
由View的源码可知,View的测量过程通过onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法实现的,并在该方法中调用setMeasuredDimension()方法来最终确定View的具体大小。View的测量包括两部分内容,即测量模式和具体大小的确定,不同的测量模式,其数值的设置方式是不同的,这可以借助MeasureSpec类从widthMeasureSpec和heightMeasureSpec来提取测量模式和具体数值。widthMeasureSpec、heightMeasureSpec本身是被MeasureSpec类处理过的,是一个32位的int值,它的高2位为测量模式,低30位为测量的大小。

 

 

int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);

View测量模式:
     (1) EXACTLY,精确模式
     当控件的layout_width属性或layout_height属性指定为具体值时,系统使用的就是精确模式。在自定义View时,如果不重写onMeasure方法,系统默认使用的就是EXACTLY模式,如果我们将layout_width属性或layout_height属性设置值为wrap_content,那么系统就不知道到底该绘制多大。
     (2) AT_MOST,最大模式
     当View的layout_width属性或layout_height属性指定为wrap_content时,对于View来说,View的大小随着其内容的变化而变化,对于ViewGroup来说,ViewGroup的大小随着其子控件变化而变化。
     (3) UNSPECIFIED
    这个模式通常只有系统才会使用,可以无需理会。
2. layout流程
 View绘制的layout过程通过调用onLayout(boolean changed,int l, int t, int r, int b)方法实现,调用该方法需要传入放置View的矩形空间左上角left、top和右下角right、bottom,它们均是相对父控件而言的。需要注意的是,对于View来说,onLayout方法没有做任何事情,所以可以不用理会;对于ViewGroup来说,onLayout())是一个抽象方法,它将由继承于ViewGroup的子类实现,用来实现获取所有子View的实例,然后调用子View的layout(int l, int t, int r, int b)方法决定子View在父布局中的位置,其中l、r、r、b参数均是相对父控件而言的。自定义ViewGroup举例:

 

public class CustomLayout extends ViewGroup {
    // 子View的垂直间隔
    private final static int padding = 20;
     
    public CustomLayout (Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        for (int i = 0, size = getChildCount(); i < size; i++) {
            // 获取第i个子View实例
            View view = getChildAt(i);
            // 放置子View,宽高都是50
            // left=0 ; top=0 ; right=50 ; bottom=50
            view.layout(l, t, l + 50, t + 50);
            t += 50+ padding;
        }
    }    
}

3. draw流程

 

    View绘制经历测量、布局过程后,接下来就是在指定的位置绘制指定大小的图形了,这个过程由onDraw(Canvas canvas

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值