Android 控件架构与自定义控件详解
Posted mb61b711907d5f4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 控件架构与自定义控件详解相关的知识,希望对你有一定的参考价值。
架构:
- PhoneWindow 将一个 DecorView 设置为整个应用窗口的根 View,这里面所有 View 的监听事件,都通过 WindowManagerService 来接收。DecorView 分为 TitleView 和 ContentView,ContentView 是一个 ID 为 content 的 FrameLayout
- 在 onCreate()
方法中调用 setContentView()
方法后,ActivityManagerService 会回调onResume()
方法,此时系统才会把整个 DecorView 添加到 PhoneWindow 中,并让其显示出来,从而完成最终的界面绘制。
View 的测量:
测量 View 的类:MeasureSpec 类,它是一个32位的 int 值,高两位为测量模式,低30位为测量大小,使用位运算提高并优化效率。
重写 onMeasure()
后,最终要做的是把测量后的宽高值作为参数设置给 setMeasureDimension()
方法。
[代码]java代码:
@Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) setMeasureDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
private int measureWidth( int measureSpec) int result = 0 ; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) result = specSize; else result = 200 ; if (specMode == MeasureSpec.AT_MOST) result = Math.min(result, specSize); return result; |
即,如果不重写 onMeasure()
方法,系统则会不知道该默认多大尺寸,就会默认填充整个父布局,所以,重写 onMeasure()
方法的目的,就是为了能够给 View 一个 wrap_content 属性下的默认大小。
View 的绘制
onDraw()
中的参数,就是 Canvas 对象,使用该对象进行绘图,而在其他地方,则需要 new 出该对象:
[代码]java代码:
1 | Canvas canvas = new Canvas(bitmap); |
传进去的 bitmap 是与这个 bitmap 创建的 Canvas 画布紧密联系的,这个过程称为装载画布。该 bitmap 用来存储所有绘制在 Canvas 上的像素信息。所有的 Canvas.drawXXX 方法都发生在这个 bitmap 上。
[代码]java代码:
@Override protected void onDraw(Canvas canvas) canvas.drawBitmap(bitmap1, 0 , 0 , null ); canvas.drawBitmap(bitmap2, 0 , 0 , null ); private void otherMethod() Canvas mCanvas = new Canvas(bitmap2); mCanvas.drawXXX |
通过 mCanvas 将绘制效果作用在了 bitmap2 上,再刷新 View 的时候,就会发现通过 onDraw()
方法画出来的 bitmap2 已经改变,因为 bitmap2 承载了在 mCanvas 上所进行的绘图操作。我们没有将图形直接绘制在 onDraw()
方法制定的那块画布上,而是通过改变 bitmap,让 View 重绘,从而显示改变之后的 bitmap。
ViewGroup 的测量
当 ViewGroup 的大小为 wrap_content 时,ViewGroup 需要对子 View 进行遍历,以便获得所有子 View 大小从而决定自己的大小,即调用子 View 的 Measure 方法来获得每一个子 View 的测量结果。
子 View 测量完毕后,ViewGroup 执行 Layout 过程时,同样是遍历调用子 View 的 Layout 方法,并指定其具体显示的位置,从而来决定其布局位置。
自定义 View
[代码]java代码:
@Override protected void onDraw(Canvas canvas) super .onDraw(canvas); |
在 attrs.xml 中通过使用<declar-styleable>
标签声明使用了自定义属性,使用如下代码获得在布局文件中自定义的那些属性
[代码]java代码:
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar); mLeftColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0 ); ta.recycle(); |
自定义 ViewGroup
重写 onMeasure()
来对子 View 进行测量,重写 onLayout()
确定子 View 位置,重写onTouchEvent()
增加响应事件。
实例需求:自定义 ViewGroup 实现类似 ScrollView 上下滑动,同时增加粘性效果。即,当一个子 View 向上滑动大于一定距离后,松开将自动上滑,显示下一个子 View,否则回到原始位置。
步骤一:先实现类似 ScrollView 功能:
[代码]java代码:
@override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) super .onMeasure(widthMeasureSpec, heightMeasureSpec); int count = getChildCount(); for ( int i = 0 ;i < count; ++i) View childView = getChildAt(i); measureChild(childView, widthMeasureSpec, heightMeasureSpec); |
步骤二:再对子 View 进行放置位置设定,让每个子 View 都显示完整的一屏。所以,本例中ViewGroup 的高度就是子 View 的个数乘以屏幕高度,然后遍历设定每个子 View 放置的位置
[代码]java代码:
@Override protected void onLayout( boolean changed, int l, int t, int r, int b) int childCount = getChildCount(); MarginLayoutParams mlp = (MarginLayoutParams)getLayoutParams(); mlp.height = mScreenHeight.childCount; setLayoutParams(mlp); for ( int i= 0 ; i<childcount; i++)= "" view= "" child= "getChildAt(t);" if (child.getvisibility()= "" != "View.GONE)" child.layout(l,= "" i*mscreenheight,= "" r,= "" (i+ 1 )*mscreenheight);= "" = "" <= "" pre= "" ></childcount;> |
步骤三:
[代码]java代码:
@Override public boolean onTouchEvent(MotionEvent event) int y = ( int )event.getY(); switch (event.getAction()) case MotionEvent.ACTION_DOWN: mLastY = y; mStart = getScrollY(); break ; case MotionEvent.ACTION_MOVE: if (!mScroller.isFinished()) mScroller.abortAnimation(); int dy = mLastY - y; if (getScrollY() < 0 ) dy = 0 ; if (getScrollY() >getHeight - mScreenHeight) dy = 0 ; scrollBy( 0 , dy); mLastY = y; break ; case MotionEvent.ACTION_UP: mEnd = getScrollY(); int dScrollY = mEnd - mStart; Android控件架构与自定义控件详解——自定义View
Android群英传知识点回顾——第三章:Android控件架构与自定义控件详解
控件架构与自定义控件详解 + ListView使用技巧 + Scroll分析
Android开发学习之控件架构与自定义控件
Android开发学习之控件架构与自定义控件
Android开发之自定义控件---onMeasure详解
|