view绘制流程是从ViewRoot的performTraversals()方法中开始的,在该方法中会执行view绘制的三部曲,即:measure(测量视图的大小),layout(确定视图的位置)draw(绘制视图的内容)。Android界面绘制流程:
从左图中我们可以看出Android界面绘制流程分为三个部分,第一部分是测量(Measure),View会先做一次测量,计算出自己需要占用多大的面积,我们可以重写 onMeasure() 方法来重新定义View的宽高。第二部分是布局(Layout),这个部分我们需要做的事情就是将整个View中所有的子View大小宽高设置好,可以通过复写 onLayout() 方法来实现,当然如果你的自定义View中没有子View,那就不需要设计这一部分了。第三部分是绘制(Draw),这个很好理解,就是在创建的画布(Canvas)上绘制出我们所需要的View样式,同样可以通过复写 onDraw() 方法来实现。这三个过程都是从上而下,从父到子的,即:先设置父视图,然后遍历子视图,并对其设置。
- 自定义view时,我们可以重写onMeasure(非必须)和onDraw方法,在onMeasure的实现里调用setMeasuredDimension或者super.onMeasure来设置视图大小。
- 自定义ViewGroup时,我们可以重写onLayout(必须)方法,在里面调用view的layout方法设置视图的位置。
自定义View的实现方式大概可以分为三种,自绘控件、组合控件、以及继承控件。
- 自绘控件的意思就是,这个View上所展现的内容全部都是写在onDraw()方法中绘制出来的。
- 组合控件的意思就是将几个系统原生的控件组合到一起,这样创建出的控件就被称为组合控件。
- 继承控件的意思就是去继承一个现有的控件,然后在这个控件上增加一些新的功能。
android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
View相关问题总结
1. getWidth()和getMeasuredWidth()的区别?
- getMeasuredWidth():只要一执行完 setMeasuredDimension() 方法,就有值了,并且不再改变。
即对View上的内容进行测量后得到的View内容占据的宽度。
- getWidth():必须执行完 onMeasure() 才有值,可能发生改变。如果 onLayout 没有对子 View 实际显示的宽高进行修改,那么 getWidth() 的值等于getMeasuredWidth() 的值,即 View在设定好布局后整个View的宽度
- getMesureHeight():指全部的长度,包括隐藏的。 getHeight():指显示出来的长度;
2. 什么是屏幕尺寸、屏幕分辨率、屏幕像素密度?
屏幕尺寸是指屏幕对角线的长度。单位是英寸,1英寸=2.54厘米 。屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1像素点,一般是纵向像素横向像素,如1280×720 。屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写,像素密度和屏幕尺寸和屏幕分辨率有关。
3. Android Drawable
Drawable属于轻量级的、使用也很简单,Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型, 在实际的开发过程中使用@drawable来使用drawable资源。
4. onLayout() 和Layout()的区别?
onLayout()是ViewGroup中子View的布局方法,用于放置子View的位置。放置子View很简单,只需在重写onLayout方法,然后获取子View的实例,调用子View的layout方法实现布局。在实际开发中,一般要配合onMeasure测量方法一起使用。该方法在ViewGroup中定义是抽象函数,继承该类必须实现onLayout方法,而ViewGroup的onMeasure并非必须重写的。View的放置都是根据一个矩形空间放置的,onLayout传下来的l,t,r,b分别是放置父控件的矩形可用空间(除去margin和padding的空间)的左上角的left、top以及右下角right、bottom值。
layout()是View本身的布局方法,在View类实现。调用该方法需要传入放置View的矩形空间左上角left、top值和右下角right、bottom值。这四个值是相对于父控件而言的。例如传入的是(10, 10, 100, 100),则该View在距离父控件的左上角位置(10, 10)处显示,显示的大小是宽高是90(参数r,b是相对左上角的),这有点像绝对布局。
可在ViewGroup的onLayout()中调整各个子view的位置时用view.layout(l,t,r,b)。
View 里面的 onSavedInstanceState和onRestoreInstanceState的作用?
View和Activity一样的,每个View都有onSavedInstanceState和onRestoreInstanceState这两个方法,可用于保存和恢复view的状态。
5. Android 5.0 新特性–SVG图片资源
SVG的全称是Scalable Vector Graphics,叫可缩放矢量图形。它和位图(Bitmap)相对,SVG不会像位图一样因为缩放而让图片质量下降。
6. 关于Android View控件的理解
Android中控件大致被分为两类ViewGroup,View。ViewGroup作为容器管理View。Android视图,是类似于Dom树的架构。父视图负责测量定位绘制等操作。我们经常在用的findViewById 方法代价昂贵的原因,就是因为他负责至上而下遍历整棵控件树,来寻找View实例,在重复操作中尽量少用。
7. Android View刷新机制?
在Android布局中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成
8. RelativeLayout和LinearLayout性能比较?
1) RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
2) RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding(内边距)代替margin。
3) 在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。