package yifeiyuan.practice.practicedemos.customview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by alanchen on 15/10/15.
*/
public class MyViewGroup extends ViewGroup {
public static final String TAG = MyViewGroup.class.getSimpleName();
public MyViewGroup(Context context) {
this(context, null);
}
public MyViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
// int unspecified = MeasureSpec.UNSPECIFIED;//0
// int atMost = MeasureSpec.AT_MOST;//-2147483648
// int exactly = MeasureSpec.EXACTLY;//1073741824
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 0 0
// Log.d(TAG, "onMeasure: height" + getMeasuredHeight() + ";width:" + getMeasuredWidth());
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Log.d(TAG, "onMeasure() called with: " + "widthMeasureSpec = [" + widthMeasureSpec + "], heightMeasureSpec = [" + heightMeasureSpec + "]");
// logModeAndSize(widthMeasureSpec);
// logModeAndSize(heightMeasureSpec);
// Log.d(TAG, "onMeasure: height" + getMeasuredHeight() + ";width:" + getMeasuredWidth());
int height = 0;//group的计算高度
int width = 0;//宽度
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int childcount = getChildCount();
for (int i = 0; i < childcount; i++) {
View child = getChildAt(i);
//gone 的就无视掉
if (child.getVisibility() == GONE) {
continue;
}
LayoutParams lp = child.getLayoutParams();
int widthSpec = 0;
int heightSpec = 0;
//根据LayoutParams,给子View生成MeasureSpec规则
if (lp.width == LayoutParams.WRAP_CONTENT) {
widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
} else if (lp.width == LayoutParams.MATCH_PARENT) {
widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
} else {
//其实xml里不会出现这样的情况
widthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
}
if (lp.height == LayoutParams.WRAP_CONTENT) {
heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
} else if (lp.height == LayoutParams.MATCH_PARENT) {
heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
} else {
heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
}
child.measure(widthSpec, heightSpec);
//把所有的子View的高度加起来,就是高度
height += child.getMeasuredHeight();
// 拿子View中的最大宽度当自己的宽度,保证所有子View能够显示全
width = Math.max(width, child.getMeasuredWidth());
Log.d(TAG, "onMeasure: i:" + i + ",width:" + child.getMeasuredWidth() + ",height:" + child.getMeasuredHeight());
}
// 再根据父view给自己的spec,处理自己的宽高
if (MeasureSpec.EXACTLY == widthMode) {
width = widthSize;
}else if (MeasureSpec.AT_MOST == widthMode) {
width = Math.min(width, widthSize);
}
if (MeasureSpec.EXACTLY == heightMode) {
height = heightSize;
}else if (MeasureSpec.AT_MOST == heightMode) {
height = Math.min(height, heightSize);
}
//一定要记得调用
setMeasuredDimension(width, height);
Log.d(TAG, "onMeasure: height" + getMeasuredHeight() + ";width:" + getMeasuredWidth());
}
private void logModeAndSize(int measureSpec) {
switch (MeasureSpec.getMode(measureSpec)) {
case MeasureSpec.UNSPECIFIED:
Log.d(TAG, "UNSPECIFIED: " + MeasureSpec.getSize(measureSpec));
break;
case MeasureSpec.AT_MOST:
Log.d(TAG, "AT_MOST: " + MeasureSpec.getSize(measureSpec));
break;
case MeasureSpec.EXACTLY:
Log.d(TAG, "EXACTLY: " + MeasureSpec.getSize(measureSpec));
break;
}
}
private int measureHeight(int heightMeasureSpec) {
int result = 100;
int size = MeasureSpec.getSize(heightMeasureSpec);
int mode = MeasureSpec.getMode(heightMeasureSpec);
switch (mode) {
case MeasureSpec.EXACTLY:
result = size;
break;
case MeasureSpec.AT_MOST:
result = Math.min(result, size);
break;
case MeasureSpec.UNSPECIFIED:
//看情况而定
// 这个是从RecyclerView的onMeasure里看来的.
//result = ViewCompat.getMinimumHeight(this);
break;
}
return result;
}
private int measureWidth(int widthMeasureSpec) {
int result = 0;
int size = MeasureSpec.getSize(widthMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = 100;// 实际上需要自己计算
if (mode == MeasureSpec.AT_MOST) {
//至多模式,别超过了
result = Math.min(result, size);
}
}
return result;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childcount = getChildCount();
int height = 0;
for (int i = 0; i < childcount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.layout(l,t+height,l+child.getMeasuredWidth(),t+height+child.getMeasuredHeight());
height += child.getMeasuredHeight();
Log.d(TAG, "onLayout: i:" + i + ",width:" + child.getMeasuredWidth() + ",height:" + child.getMeasuredHeight());
}
}
private void init() {
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// Log.d(TAG, "onFinishInflate() called with: " + "");
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// Log.d(TAG, "onAttachedToWindow() called with: " + "");
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Log.d(TAG, "onDetachedFromWindow() called with: " + "");
}
}