相关知识:
1、View的onMeasure等的加载过程
ViewRootImpl 调用perfomTravsals中的performMeasure,再调用performLayout
//这里就是线性布局比相对布局性能好的原因
//相对布局会调用两次,线性布局会调用一次
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;
if (lp.horizontalWeight > 0.0f) {
width += (int) ((mWidth - width) * lp.horizontalWeight);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
MeasureSpec.EXACTLY);
measureAgain = true;
}
if (lp.verticalWeight > 0.0f) {
height += (int) ((mHeight - height) * lp.verticalWeight);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
measureAgain = true;
}
if (measureAgain) {
if (DEBUG_LAYOUT) Log.v(mTag,
"And hey let's measure once more: width=" + width
+ " height=" + height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
performMeasure再调用mView.measure(childWidthMeasureSpec, childHeightMeasureSpec)方法实现view的measure方法。
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
2、xml布局文件的加载流程
(1)使用LayoutInflater的Inflate方法,获得一个xml解析器
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
(2)使用xml解析器,解析xml文件
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
(3)为View创建Tag
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
//把所有属性进行传递
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
//设置属性
temp.setLayoutParams(params);
}
实现自定义百分比布局的思路,
(1)自定义实现ViewGroup的LayoutParams。
public static class LayoutParamsSelf extends RelativeLayout.LayoutParams{
private float widthPercent;
private float heightPercent;
public float getWidthPercent() {
return widthPercent;
}
public float getHeightPercent() {
return heightPercent;
}
public void setWidthPercent(float widthPercent) {
this.widthPercent = widthPercent;
}
public void setHeightPercent(float heightPercent) {
this.heightPercent = heightPercent;
}
public LayoutParamsSelf(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray array=c.obtainStyledAttributes(attrs,R.styleable.PercentLayout);
widthPercent=array.getFloat(R.styleable.PercentLayout_layout_widthPercent,widthPercent);
heightPercent=array.getFloat(R.styleable.PercentLayout_layout_heightPercent,heightPercent);
array.recycle();
}
public LayoutParamsSelf(int width, int height) {
super(width, height);
}
public LayoutParamsSelf(MarginLayoutParams source) {
super(source);
}
public LayoutParamsSelf(ViewGroup.LayoutParams source) {
super(source);
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParamsSelf(getContext(),attrs);
}
(2)在onMeasure测量出子控件的宽和高,进行改变
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.e("TAG","onMeasuer");
int width= View.MeasureSpec.getSize(widthMeasureSpec);
int height=View.MeasureSpec.getSize(heightMeasureSpec);
int count =getChildCount();
for (int i=0;i<count;i++){
View childAt=getChildAt(i);
ViewGroup.LayoutParams layoutParams=childAt.getLayoutParams();
float widthPercent=0;
float heightPercent=0;
if(layoutParams instanceof PercentLayout.LayoutParamsSelf){
widthPercent=((PercentLayout.LayoutParamsSelf)layoutParams).getWidthPercent();
heightPercent=((PercentLayout.LayoutParamsSelf)layoutParams).getHeightPercent();
}
if(widthPercent!=0){
layoutParams.width=(int)(width*widthPercent);
}
if(heightPercent!=0){
layoutParams.height=(int)(height*heightPercent);
}
}
Log.e("TAG","widthMeasureSpec "+widthMeasureSpec+" heightMeasureSpec"+heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
构造方法及继承Relativelayout
public PercentLayout(Context context) {
this(context,null);
}
public PercentLayout(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public PercentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
}