Android控件架构
- ViewGroup控件可以包含多个view控件,并管理其包含的View 控件
上层控件负责下层控件的测量与绘制,并传递交互事件。 - DecorView 包括TitleView 和ContentView
- ContentView :一个id为content 的Framelayout,
activity_main.xml就是设置在这样的一个Framelayout里。 - 当程序在onCreat()方法中调用stContentView()方法后ActivityManagerService会回调onResume()方法,此时系统才会把整个DecorView添加到PhoneView中 并让其显示出来,从而完成界面绘制。
- ContentView :一个id为content 的Framelayout,
自定义View
view 的测量 onMeasure()
重写此方法的目的就是为了给view一个wrap_content属性 下的默认大小。
* 三种模式:
EXACTLY: 精确值模式 指定数值或者是match_parent。
AT_MOST: wrap_content 此时控件的尺寸只要不超过父控件允许的最大尺寸即可。
UNSPECIFIED: 不指定其大小测量模式,view想多大就多大。
- 重写onMeasuer的模板代码:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
/**
* 测量宽
* MeasureSpec 是一个32位int值,高2位是测量模式,低30位是测量的大小
* @param widthMeasureSpec
* @return
*/
private int measureWidth(int widthMeasureSpec ){
int result=0;
int specMode=MeasureSpec.getMode(widthMeasureSpec);//获取模式
int specSize=MeasureSpec.getSize(widthMeasureSpec);
if(specMode==MeasureSpec.EXACTLY){//精准模式
result=specSize;
}else {
result=200;
if(specMode==MeasureSpec.AT_MOST){
result=Math.min(result,specSize);//如果是最大值模式(最大不能超过多少) 取最小值
}
}
return result;
}
private int measureHeight(int heightMeasureSpec ){
int result;
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
if(mode==MeasureSpec.EXACTLY){
result=size;
}else {
result=200;
if(mode==MeasureSpec.AT_MOST){
result=Math.min(result,size);
}
}
return result;
}
view 的绘制 onDraw()
画一个简单的圆
@Override
protected void onDraw(Canvas canvas) {
Paint paint=new Paint();
paint.setColor(Color.YELLOW);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(getMeasuredWidth()/2,getMeasuredHeight()/2,Math.min(getMeasuredHeight()/2,getMeasuredWidth()/2),paint);
super.onDraw(canvas);
}
自定义ViewGroup
- viewgroup获取管理其子view,当属性为wrap_content时,viewgroup就需要对子view进行遍历,以便获得所有子view的大小(调用子view的measure方法获得每一个view的测量结果),从而决定自己的大小,而在其他模式下则会通过具体 的指定值来设置自身的大小。
@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);
}
}
onLayout()
方法,将子view 放到合适位置。同样是使用遍历来调用子view 的layout方法,并指定其显示的具体的位置,从而来决定其布局位置。
@Override
protected void onLayout(boolean changed,
int l, int t, int r, int b) {
int childCount = getChildCount();
// 设置ViewGroup的高度
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.height = mScreenHeight * childCount;
setLayoutParams(mlp);
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(l, i * mScreenHeight,
r, (i + 1) * mScreenHeight);
}
}
}
自定义属性
res/values/attrs.xml
<declare-styleable name="ProgressView">
<attr name="textContent" format="string"/>
</declare-styleable>
- 布局中使用
xmlns:app=”http://schemas.android.com/apk/res-auto”
app:textContent=”“ - 获取属性
// 通过这个方法,将你在atts.xml中定义的declare-styleable // 的所有属性的值存储到TypedArray中 TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.TopBar); //从TypedArray中取出对应的值来为要设置的属性赋值 mTitle = typedArray.getString(R.styleable.TopBar_mtitle); mTitleTextColor = typedArray.getColor(R.styleable.TopBar_mtitleTextColor,0); mTitleTextSize = typedArray.getDimension(R.styleable.TopBar_mtitleTextSize, 0);
示例代码
链接:http://pan.baidu.com/s/1qYGMwS8 密码:y4wr