自定义控件经验录

Android 控件的绘画过程?影响绘画的因素有哪些?

Android将控件的绘画过程按照顺序依次分成了几个过程:测量大小,布局,绘画内容。自定义控件时对应的是onMeasure(..),onLayout(..),onDraw(..)。在自定义控件过程中,需要确定控件的位置、大小。影响位置和大小的参数是内外边距跟内容。

UI的本质又是什么?######

UI的本质是Window(实现类PhoneWindow)。Activity、Dialog显示的本质都是一个Window。Activity显示的内容就就放在了Window里面。在Window里面有一个DecorView(FrameLayout),我们调用Activity.setContentView()就是将内容放置在DecorView里面。

控件的绘画从什么时候开始的呢?######

控件的绘画从Activity打开的时候开始,调用栈是:
1.ActivityThread.handleLaunchActivity(..)
2.ActivityThread.performLaunchActivity(..)
3.ActivityThread.handleResumeActivity(..)
4.ViewManager.updateViewLayout(..)(实现类WindowManagerImpl)
5.ViewRoot.setLayoutParams(..)
6.ViewRoot.scheduleTraversals(..)
7.ViewRoot.performTraversals(..)
...
真正开始执行绘画从ViewRoot(实现类ViewRootImpl)开始。主要的绘画过程都在ViewRootImpl.performTraversals()里:
1.measureHierarchy()调用了performMeasure()方法测量控件,容器会去测量子控件.直到所有控件测量完毕。
2.performLayout(),在这里执行控件的布局,这里同样需要循环调用子控件的布局方法,直到所有控件均布局完毕
3.performDraw() ,这里执行绘画过程,这里同父容器调用dispatchDraw()去绘画子控件。

自定义容器过程中,测量大小(onMeasure(int,int))时应该注意什么?######

控件的测量模式有三种,"UNSPECIFIED"、“EXACTLY”、“AT_MOST”。当我们自定义容器大小(onMeasure(..)),我们需要根据测量模式去确定子控件的大小,然后再确定容器的大小。影响子控件的大小的参数有:容器的测量模式和容器的间距、子控件的外间距。如果子控件的测量模式不是"EXACTLY",那么容器给予子控件onMeasure(int,int)的参数值应该=容器测量模式得出的大小-容器内间距-子控件外间距。

自定义容器过程中,布局(onLayout(int,int,int,int))时应该注意什么?

当容器布局的时候,我们需要去确定子控件的位置。子控件的布局位置应该是减去容器内间距,子控件的外间距后的位置。例如容器的左内间距为10px,子控件的左外间距为10px.那么子控件的左位置应该是容器左边位置-容器左内间距-子控件左外间距。注意,布局时候的坐标都是屏幕的绝对坐标。即子控件onLayout方法中传入的坐标不是相对于父容器的坐标。

自定义控件过程中,测量大小(onMeasure(int,int))时应该注意什么?######

绘制控件的时候不需要考虑外间距,需要考虑内间距。同样,也要根据测量模式确定控件的大小。当测量模式为AT_MOST的时候,我们要根据控件内容测量控件大小。

自定义控件常用方法######

1、Context.getTheme().obtainStyledAttributes(int[]res)
说明:一般在控件构造方法中获取属性值。
2、Layout.getDesiredWidth(CharSequence source, TextPaint paint)
说明:可以获取文字的宽度,包括大小写,回车键等特殊字符都可以通过这个方法获取。
3、Paint.getTextBounds(String text, int start, int end, Rect bounds)
说明:获取文字的高度和位置。
4、ViewGroup.getChildMeasureSpec(int spec, int padding, int childDimension)
说明:根据容器的测量模式、容器的外间距、子控件的内间距、控件的测量模式获取传给子控件测量方法的参数值。注意,padding参数一般是容器的内间距和子控件的外间距之和。
5、ViewGroup.measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec)
说明:测量子控件的大小。调用了ViewGroup.getChildMeasureSpec方法。
6、ViewGroup. measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,int parentHeightMeasureSpec, int heightUsed)
说明:测量子控件的大小,这里把容器的外间距也算上了。
7、View.requestLayout()。
说明:强制更新整个绘画流程。
8、View.invaildate()
说明:更新绘制区域(不会更新整个绘画流程)。

posted @ 2017-12-15 11:14  Zhouztashin  阅读(137)  评论(0编辑  收藏  举报