package com.mingshan.linearlayout; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; public class MyLinearLayout extends ViewGroup { public static final int HORIZONTAL = 0; public static final int VERTICAL = 1; private int mOrientation = VERTICAL; private int mWidth; private int mHeight; private int mGravity; private int mTotalLength; public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context,AttributeSet attrs) { } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if(mOrientation==VERTICAL){ measureVertical(widthMeasureSpec,heightMeasureSpec); }else { measureHorizontal(widthMeasureSpec,heightMeasureSpec); } } private void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { } //https://blog.csdn.net/xmxkf/article/details/51490283 private void measureVertical(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); Log.i("measureVertical", "widthMode:"+widthMode); Log.i("measureVertical", "widthSize:"+widthSize); Log.i("measureVertical", "heightMode:"+heightMode); Log.i("measureVertical", "heightSize:"+heightSize); int maxWidth=0; int totalHeight=getPaddingTop(); int childCount = getChildCount(); mTotalLength = 0; for (int i=0;i<childCount;i++){ View child = getChildAt(i); if(child.getVisibility()==View.GONE){ continue; } final LayoutParams lp = (LayoutParams) child.getLayoutParams(); //获取子控件的宽高约束规则 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, lp.leftMargin+lp.rightMargin, lp. width); final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp. height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); final int measuredWidth = child.getMeasuredWidth(); if(measuredWidth>maxWidth){ maxWidth=measuredWidth; } final int measuredHeight = child.getMeasuredHeight(); totalHeight+=measuredHeight; mTotalLength+=measuredHeight; } if (widthMode == MeasureSpec.EXACTLY) { mWidth = widthSize; }else { mWidth = maxWidth+getPaddingLeft()+getPaddingRight(); } if(heightMode==MeasureSpec.EXACTLY){ mHeight=heightSize; }else { mHeight=totalHeight+getPaddingBottom(); } setMeasuredDimension(mWidth, mHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if(mOrientation==VERTICAL){ onLayoutVertical(changed, l, t, r, b); }else { onLayoutHorizontal(changed, l, t, r, b); } } private void onLayoutHorizontal(boolean changed, int l, int t, int r, int b) { } private void onLayoutVertical(boolean changed, int l, int t, int r, int b) { final int width = r-l; final int childCount = getChildCount(); final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int paddingTop = getPaddingTop(); Log.i("onLayoutVertical", "childCount:"+childCount); Log.i("onLayoutVertical", "paddingLeft:"+paddingLeft); Log.i("onLayoutVertical", "paddingRight:"+paddingRight); Log.i("onLayoutVertical", "paddingTop:"+paddingTop); int startY = paddingTop; for(int i=0;i<childCount;i++){ View child = getChildAt(i); if(child.getVisibility()==View.GONE){ continue; } final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight(); Log.i("onLayoutVertical", "childWidth:"+childWidth); Log.i("onLayoutVertical", "childHeight:"+childHeight); LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); Log.i("onLayoutVertical", "layoutParams.gravity:"+layoutParams.gravity); switch (layoutParams.gravity){ case Gravity.CENTER_HORIZONTAL: child.layout((width>>1)-(childWidth>>1),startY, (width>>1)+(childWidth>>1),startY+childHeight); break; case Gravity.RIGHT: child.layout(width-childWidth,startY, paddingRight, startY+childHeight); break; default: child.layout(paddingLeft,startY, paddingLeft+childWidth, startY+childHeight); break; } startY+=childHeight; } } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof MyLinearLayout.LayoutParams; } public static class LayoutParams extends ViewGroup.MarginLayoutParams { public float weight; public int gravity = -1; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); Log.i("LayoutParams","Context c, AttributeSet attrs"); TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.MyLinearLayout_Layout); // c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout); weight = a.getFloat(R.styleable.MyLinearLayout_Layout_layout_weight, 0); gravity = a.getInt(R.styleable.MyLinearLayout_Layout_layout_gravity, Gravity.LEFT); // weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0); // gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1); a.recycle(); } public LayoutParams(int width, int height) { super(width, height); Log.i("LayoutParams","int width, int height"); weight = 0; } public LayoutParams(int width, int height, float weight) { super(width, height); Log.i("LayoutParams","int width, int height, float weight"); this.weight = weight; } public LayoutParams(ViewGroup.LayoutParams p) { super(p); Log.i("LayoutParams","ViewGroup.LayoutParams p"); } public LayoutParams(ViewGroup.MarginLayoutParams source) { super(source); Log.i("LayoutParams","ViewGroup.MarginLayoutParams source"); } public LayoutParams(LinearLayout.LayoutParams source) { super(source); Log.i("LayoutParams","LinearLayout.LayoutParams source"); this.weight = source.weight; this.gravity = source.gravity; } }
}
<declare-styleable name="MyLinearLayout"> <attr name="orientation" format="integer"/> </declare-styleable> <declare-styleable name="MyLinearLayout_Layout"> <attr name="layout_weight" format="float"/> <attr name="layout_gravity" format="enum"> <enum name="top" value="48"/> <enum name="bottom" value="80"/> <enum name="left" value="3"/> <enum name="right" value="5"/> <enum name="start" value="8388611"/> <enum name="end" value="8388613"/> <enum name="center_vertical" value="16"/> <enum name="center_horizontal" value="1"/> <enum name="center" value="17"/> </attr> </declare-styleable>