关于自定义Layout或者ViewGroup总结
先看一下代码,然后我会根据代码具体分析:
package com.yld.startvideodemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
* @author yld
* @create 2019-02-28 9:33
*/
public class CustomLayout extends ViewGroup {
public CustomLayout(Context context) {
super(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
*widthMeasureSpec 包含了了父view的width属性的模式和尺寸
*heightMeasureSpec 包含了了父view的height属性的模式和尺寸
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childWidthSpec = 0;
int childHeightSpec = 0;
//表示子view在父view中的可使用宽度
int usedWidth = 0;
//表示子view在父view中的可使用高度
int usedHeight = 0;
for (int i = 0 ; i < getChildCount() ; i ++){
View childView = getChildAt(i);
LayoutParams layoutParams = childView.getLayoutParams();
//widthMeasureSpec 是一个int类型的数据,取32位二进制数中前两位作为mode值
//后30位为size值
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int withSize = MeasureSpec.getSize(widthMeasureSpec);
//heightMeasureSpec 是一个int类型的数据,取32位二进制数中前两位作为mode值
//后30位为size值
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
switch (layoutParams.width){
case LayoutParams.MATCH_PARENT:
if(widthMode == MeasureSpec.EXACTLY&&widthMode==MeasureSpec.AT_MOST){
childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize - usedWidth,MeasureSpec.EXACTLY );
}else{
childWidthSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED );
}
break;
case LayoutParams.WRAP_CONTENT:
if(widthMode == MeasureSpec.EXACTLY&&widthMode==MeasureSpec.AT_MOST){
childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize - usedWidth,MeasureSpec.AT_MOST );
}else{
childWidthSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED );
}
break;
default:
childWidthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width,MeasureSpec.EXACTLY );
break;
}
switch (layoutParams.height){
case LayoutParams.MATCH_PARENT:
if(heightMode == MeasureSpec.EXACTLY&&heightMode==MeasureSpec.AT_MOST){
childHeightSpec = MeasureSpec.makeMeasureSpec(heightSize - usedHeight,MeasureSpec.EXACTLY );
}else{
childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED );
}
break;
case LayoutParams.WRAP_CONTENT:
if(heightMode == MeasureSpec.EXACTLY&&heightMode==MeasureSpec.AT_MOST){
childHeightSpec = MeasureSpec.makeMeasureSpec(heightSize - usedHeight,MeasureSpec.AT_MOST );
}else{
childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED );
}
break;
default:
childHeightSpec = MeasureSpec.makeMeasureSpec(layoutParams.width,MeasureSpec.EXACTLY );
break;
}
//下面的代码需要验证以后方可使用
usedWidth = MeasureSpec.getSize(childWidthSpec);
usedHeight = MeasureSpec.getSize(childHeightSpec);
setMeasuredDimension(childWidthSpec,childHeightSpec);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int top = 0;
for (int i = 0 ; i < getChildCount() ; i ++) {
View childView = getChildAt(i);
int width = childView.getMeasuredWidth();
int height = childView.getMeasuredHeight();
childView.layout(0,top,width,top+height);
top += height;
}
}
}
从代码中可以看到主要是重写了onMeasure()and onLayout()两个方法
1.其中在onMeasure()方法中通过遍历父view中所包含的子view,然后对其进行测量
2.对子view进行测量时通过以下方法:
MeasureSpec.makeMeasureSpec(int measureSize,int measureMode );
在方法中传入计算结果并为其指定测量模式。
3.最后将测量结果进行暂时保存。
4.在onLayout()方法中通过遍历父view中所包含的子view,通过以下代码:
childView.layout(int left,int top,int right,int bottom);
根据自己的需求指定子view的显示位置.