android自定义View

相关的类:

------------------------------------------------------------------------------------------------------------------------------------------------------------------
View  

android中所有的可视组件都继承自View,View定义了很多callbacks来定义它的行为,如onDraw(),onMeasure()等。

ViewParent (interface)    

ViewParent为所有想扮演其他views的父亲的类定义了协议。

ViewGroup (extends View and implements ViewParent)    

所有Layout都继承自ViewGroup,如LinearLayout。它负责在XML中定义Layout,摆放controls(views)到正确的位置。

它还负责child views的背景和动画。

ViewRoot (implements ViewParent)     

ViewRoot相当于中央控制枢纽,他是activity中所有view的根父类。它的职责是:1.ViewRoot调度遍历所有的views为了把

views以正确的尺寸摆放到正确的位置,这一阶段叫做layout阶段;2.ViewRoot遍历view的层级,为了把views画出来,

这一阶段叫做drawing阶段


Layout 阶段: Measure + Layout

------------------------------------------------------------------------------------------------------------------------------------------------------------------

在Layout阶段ViewRoot只会遍历那些请求layout变化的views,这种条件遍历是为了节省资源,提高响应时间。想改变layout的

view只需callrequestLayout()方法。这个call会沿着view层级一直往上走,直到到达ViewRoot。然后ViewRoot在main线程队列里

调度布局遍历的消息。


layout阶段分两步走,measure + layout 。


measure由View Class的measure()函数实现。此函数的签名是:

public final void measure(int widthMeasureSpec, int heightMeasureSpec) 。

measure()做一些整理打扫之类的工作,然后call 衍生类(暂且叫它SubViews)的onMeasure()方法。SubViews通过call 

setMeasuredDimension() 方法来设置它的尺寸。这些被设置到SubViews 的尺寸会被layout利用。在此上下文中,你只需override 

View.onMeasure()方法( onMeasure()方法有缺省实现,缺省实现通过layout files 来决定你的view的尺寸)。大部分情况下你只需

关心onMeasure()方法就足够了,但如果你自定义ViewGroup,你就需要在你的onMeasure() 方法里call 每个child views 的measure()方法。

measure 之后每个view 都知道了自己的尺寸,然后控制权交到layout。


layout 由layout() 实现,它的方法签名是:

public void layout(int left, int top, int right, int bottom)  

layout() 会先后callonSizeChanged() onLayout() 方法。它们的签名如下:

protected void onSizeChanged(int w, int h, int oldw, int oldh);      

protected void onLayout(boolean changed, int left, int top, int right, int bottom)
layout() call onLayout() 来允许像ViewGroup 在它的子views 里call layout() 。至此Layout阶段完成。


Drawing 阶段

------------------------------------------------------------------------------------------------------------------------------------------------------------------

draw 的遍历由View.draw()实现,draw()方法要做的事情有:

  • Draw the background
  • Draw view's content by delegating to onDraw()
  • Draw children by delegating to dispatchDraw()
  • Draw decorations such as scroll bars
尽管draw() 是一个public 方法,你却不应该override 它,因为draw() 实现了base View定义的协议。你应该override是:
  • public void onDraw(...)
  • public void dispatchDraw(...)
正如layout 阶段由 requestLayout() 触发,draw 阶段由 invalidate()触发。当你invalidate 了一个view,它就沿视图层级链找到
ViewRoot ,由ViewRoot 负责遍历调度。如果view 没有请求invalidate 或它的位置和尺寸都没有变,onDraw() 也许不会被view 调用。
然而,如果view 的位置或尺寸改变,base view 会调用此view 的invalidate 。


总结:

------------------------------------------------------------------------------------------------------------------------------------------------------------------

自定义view 用到的方法如下:
  • onMeasure
  • onSizeChanged
  • onLayout
  • onDraw
  • dispatchDraw
所有这些方法都是回调函数。尤其是onMeasure(), onLayout(), and onDraw() 对应着“protocol” or “template” 方法: measure(), layout(), draw() 。

这种模式叫做template/hook ,例如draw() 是template 方法,它以某种方式固定了行为,然而又依赖hook onDraw() 来特殊化它自己。


当你自定义的view 没有children 时,需要overridden 的方法是:
  • onMeasure(...)
  • onDraw(...)
有时也会用到onSizeChanged() 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值