1.
一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。
一个MeasureSpec由大小和模式组成。它有三种模式:UNSPECIFIED(未指定),父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小;EXACTLY(完全),父元素决定自元素的确切大小,
子元素将被限定在给定的边界里而忽略它本身大小;AT_MOST(至多),子元素至多达到指定大小的值
2.
onMeasure()函数由包含这个View的具体的ViewGroup调用,因此值也是从这个ViewGroup中传入的。
这里我直接给出答案:子类View的这两个参数,由ViewGroup中的layout_width,layout_height
和padding以及View自身的layout_margin共同决定。权值weight也是尤其需要考虑的因素,
有它的存在情况可能会稍微复杂点
3. 如果该View还需要使用wrap_content属性,那么还必须重写onMeasure()方法
4.
系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结 果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:
重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
5. 不管是多么复杂、精美的控件都可以被拆分成一个个小的图形单元
6.ViewGroup:
(1)当ViewGroup的大小为wrap_content时 ,ViewGroup就需提对子View进
行遍历,以便获得所有子 View 的大小,从而来决定自己的大小。而在其他模式下会通过具
体的指定值来决定自身的大小。
(2)如果需要支持wrap_content,只需要对onmeause进行重写
7.View
1.对现有控件进行拓展
(1)获取控件大小
getMeasuredWidth的值是在setMeasuredDimension方法中设置的,
而getWidth的值是onLayout方法中我们传过去的四个参数
一般情况下getMeasuredWidth和getWidth方法的值是一致的,
这里只要记住一般情况下除了在onLayout方法中调用getMeasuredWidth方法外其它的地方用getWidth方法就行了。
①getMeasuredWidth方法获得的值是setMeasuredDimension方法设置的值,它的值在measure方法运行后就会确定
②getWidth方法获得是layout方法中传递的四个参数中的mRight-mLeft,它的值是在layout方法运行后确定的
③一般情况下在onLayout方法中使用getMeasuredWidth方法,而在除onLayout方法之外的地方用getWidth方法。
(2)使用 getPaint()方法获取当前绘制TextVicw的Paint对象,并给这个Paint
对象设置原生 TextView 没有的LinearGradient 属性。
(3)postInvalidate()是重绘的,也就是调用postInvalidate()后系统会重新调用onDraw方法画一次
invalidate()
postInvalidateDelayed(long i): 定时刷新界面 重绘
2.创建复合控件
(1)这种方法通常需要继承一个合适的ViewGroup,再给它添加指定功能的控件,从而组合成新的复合控件
(2)定义接口,暴露接口给调用者 *
3.重写View来实现全新的控件
(1)通常继承View类,并重写它的onDraw(),onMeasure()等方法来实现绘制逻辑,同时通过重写onTouchEvent()
等触控事件来实现交互逻辑。
(2)实现动态效果,只要在onDraw()方法中再去调用invalidate()方法通知View进行重绘就可以了,每一次绘制完新
矩形就通知View进行重绘,这样会因为刷新速度太快反而影响效果,因此,需要进行View的延迟重绘
postInvalidateDelayed(300);
3.7 自定义VeiwGroup
1.使用遍历的方式来通知子View对自身进行测量,见代码:onMeasure()
2.确定ViewGroup的宽高
3.onlayout
4.onTouchEvent()使ViewGroup可以滑动
3.8 事件拦截机制分析
1.View重写onTouchEvent(),dispatchTouchEvent(),
ViewGroup重写onlnterceptTouchEvent(),onTouchEvent(),dispatchTouchEvent()
2.事件处理者都是执行onTouchEvcnt()方法。
事件传递的返回值非常容易理解: True,拦截,不继续; False,不拦截,继续流程。
事件处理的返回值也类似: True,处理,不用审核了; False,给上级处理。
4.绘制2图形
1.DrawPoint 绘制点
2.DrawLine 绘制直线
3.DrawLines 绘制多条直线
4.DrawRect 绘制矩形
5.DrawRoundRect 绘制圆角矩形
6.DrawCircle 绘制圆
7.DrawArc 绘制弧形,扇形
8.DrawOval 绘制椭圆
9.DrawText 绘制文本
10.DrawPath 绘制路径
1.将画笔移动到原点
//画笔平移到指定paddingLeft,getHeight()/2位置,注意以后坐标都为以此为(0,0)
canvas.translate(getPaddingLeft(), getHeight() / 2);
getMeasuredHeight()返回的是原始测量高度,与屏幕无关,getHeight()返回的是在屏幕上显示的高度。
实际上在当屏幕可以包裹内容的时候,他们的值是相等的,只有当view超出屏幕后,才能看出他们的区别。
当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的高度
2.realWidth = getMeasuredWidth() - getPaddingLeft()-getPaddingRight(); //获取真正的高度
3.//计算出默认的高度------------------测量:onMeasure()
result =(int)(getPaddingTop()+getPaddingBottom()+Math.max(Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight), Math.abs(textHeight)));