自定义ViewGroup/View(2)(Measure,Layout,Draw)

> View绘制流程
View体系的绘制流程是从ViewRootImpl的performTraversals方法开始的;
View的测量大小流程:performMeasure –> measure –> onMeasure等方法;
View的测量位置流程:performLayout –> layout –> onLayout等方法;
View的绘制流程:performDraw-> draw-> onDraw等方法;

在View的测量流程里,View的测量宽高是由父控件的MeasureSpec和View自身的LayoutParams共同决定的。

-- View的绘制:测量、布局、绘制流程;
private void performTraversals() {
        final View host = mView;
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        performLayout(lp, mWidth, mHeight);
        performDraw();
    }

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

    private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
                               int desiredWindowHeight) {
        final View host = mView;
        host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
    }

    private void performDraw() {
        // draw(fullRedrawNeeded) --> drawSoftware
        mView.draw(canvas);
    }
 performTraversals方法巨长,这里只截取View绘制三大流程的起点。mView就是之前缓存的DecorView。之后便开始了View的measure、layout、draw、onMeasure、onLayout、ondraw。
-- View的绘制,从ViewRoot的performTraversals()方法开始依次调用perfromMeasure、performLayout和performDraw这三个方法。这三个方法分别完成顶级View的measure、layout和draw三大流程,其中perfromMeasure会调用measure,measure又会调用onMeasure,在onMeasure方法中则会对所有子元素进行measure,这个时候measure流程就从父容器传递到子元素中了,这样就完成了一次measure过程,接着子元素会重复父容器的measure,如此反复就完成了整个View树的遍历。同理,performLayout和performDraw也分别完成perfromMeasure类似的流程。通过这三大流程,分别遍历整棵View树,就实现了Measure,Layout,Draw这一过程,View就绘制出来了。

https://i-blog.csdnimg.cn/blog_migrate/b06e7d3a3aecd5e704db6d357e59be44.png
 自定义控件可能重写的方法:onMeasure(),onLayout(),onDraw()等。

-- 自定义View的分类
 1.对现有的View的子类进行扩展,例如复写onDraw方法、扩展新功能等。
 2.自定义组合控件,把常用一些控件组合起来以方便使用。
 3.直接继承View实现View的完全定制,需要完成View的测量以及绘制。
 4.自定义ViewGroup,需要复写onLayout完成子View位置的确定等工作。

-- View的工作流程主要是指measure、layout、drow这三大流程,即测量、布局和绘制,其中measure确定View的测量宽/高,layout确定View的最终宽/高和四个顶点的位置,而draw则将View绘制到屏幕上。
 View的整个绘制流程可以分为以下三个阶段: 
1.measure: 判断是否需要重新计算View的大小,需要则计算 ;
2.layout:判断是否需要重新计算View的位置,需要则计算 ;
3.draw:判断是否需要重新绘制View,需要则重绘;

> View控件树与ViewGroup控件容器
自定义ViewGroup:http://blog.csdn.net/lmj623565791/article/details/38339817/
自定义View与ViewGroup- https://blog.csdn.net/vfush/article/details/51613265  
https://blog.csdn.net/vfush/article/details/51790079
Android自定义View- http://blog.csdn.net/nugongahou110/article/category/5924281

View与ViewGroup:一个用户的交互Android设备可能的例外是主要的视觉和触觉性质。
setContentView之后才为布局里的元素分配内存,在未分配内存前对元素进行访问时没有意义的!!!
WindowManager主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等。
-- 一般来说,开发Android应用程序的UI界面都不会直接使用View和ViewGroup,而是使用这两大基类的派生类。

 - View
   View派生出的直接子类有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView,TextView,ViewGroup,ViewStub
 View派生出的间接子类有:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView<T extends Adapter>,AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView, Chronometer, CompoundButton,

 - ViewGroup
 ViewGroup派生出的直接子类有:AbsoluteLayout,AdapterView<T extends Adapter>,FragmentBreadCrumbs,FrameLayout,LinearLayout,RelativeLayout,SlidingDrawer
    ViewGroup派生出的间接子类有:AbsListView,AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView,

  上述的所有基类、派生类都是Android framework层集成的标准系统类,开发者在应用开发中可直接引用SDK中这些系统类及其API。但事实上,在UI开发的很多场景下,直接使用这些系统类并不能满足应用开发的需要。比如说,我们想用ImageView在默认情况下加载一幅图片,但是希望在点击该View时View变换出各种图像处理效果,这个时候直接使用ImageView是不行的,此时我们可以重载ImageView,在新派生出的子控件中重载OnDraw等方法来实现我们的定制效果。这种派生出系统类的子类方法我们通常称之为自定义控件。
  protected void onDraw(Canvas canvas):View类中用于重绘的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,也是Android UI绘制最重要的方法。开发者可重载该方法,并在重载的方法内部基于参数canvas绘制自己的各种图形、图像效果。
  protected void onLayout(boolean changed, int left, int top, int right, int bottom):View类中布局发生改变时会调用的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,重载该类可以在布局发生改变时作定制处理,这在实现一些特效时非常有用。
  protected void dispatchDraw(Canvas canvas):ViewGroup类及其派生类具有的方法,这个方法主要用于控制子View的绘制分发,重载该方法可改变子View的绘制,进而实现一些复杂的视效,典型的例子可参见Launcher模块Workspace的dispatchDraw重载。
  protected boolean drawChild(Canvas canvas, View child, long drawingTime)):ViewGroup类及其派生类具有的方法,这个方法直接控制绘制某局具体的子view,重载该方法可控制具体某个具体子View。
 
 ViewGroup是View的子类,所以它也具有View的特性,但它主要用来充当View的容器,将其中的View视作自己的孩子,对它的子View进行管理,当然它的孩子也可以是ViewGroup类型。
 ViewGroup(树根)和它的孩子们(View和ViewGroup)以树形结构形成了一个层次结构,View类有接受和处理消息的功能,android系统所产生的消息会在这些ViewGroup和 View之间传递。

> 绘制流程:
  绘制按照视图树的顺序执行。视图绘制时会先绘制子控件。如果视图的背景可见,视图会在调用onDraw函数之前绘制背景。强制重绘,可以使用invalidate()。
 -- 事件的基本流程如下:
  1、事件分配给相应视图,视图处理它,并通知相关监听器。
  2、操作过程中如果发生视图的尺寸变化,则该视图用调用requestLayout()方法,向父控件请求再次布局。
  3、操作过程中如果发生视图的外观变化,则该视图用调用invalidate()方法,请求重绘。
  4、如果requestLayout()或invalidate()有一个被调用,框架会对视图树进行相关的测量、布局和绘制。
  注意,视图树是单线程操作,直接调用其它视图的方法必须要在UI线程里。跨线程的操作必须使用句柄Handler。

> Android实现的是C/S模式:Activity的创建
【1】ActivityManagerService创建Activity线程,激活一个activity
【2】系统调用Instrumentation.newActivity创建一个activity
【3】Activity创建后,attach到一个新创建的phonewindow中。这样Activity获取一个唯一的WindowManager服务的实例
【4】Activity创建过程中使用setContentView设置用用户UI,这些view被加入到PhoneWindow的ContentParent中。
【5】Activity线程继续执行,当执行到Activity.makeVisible是将根view DecoView加入到WindowManger中,WindowManger实全会为每个DecoView创建对应的ViewRoot
【6】每个ViewRoot拥有一个Surface,每个Surface将会调用底层库创建图形绘制的内存空间。这个底层库就是SurfaceFlinger。SurfaceFlinger同时也负责将个View绘制的图形合到一块(按照Z轴)显示到用户屏幕。
【7】如果用户直接在Canvas上绘制,实际上它直接操作Surface。但对每个View的变更,它是要通知到ViewRoot,然后 ViewRoot获取Canvas。如果绘制完成,surfaceFlinger得到通知,合并Surface成一个Surface到设备屏幕。

 真正显示图形的实际上跟Activity没有关系,完全由WindowManager来决定。 WindowManager是一个系统服务,因此可以直接调用这个服务来创建界面,并且更绝的是Dialog、Menu也是有WindowManager 来管理的。另外一个我们也可以看到,最底层都是Surface来,因此,常见开发游戏的人都推荐你使用SurfaceView来创建界面。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值