Android 百分比布局揭秘

来源:互联网 发布:win10网络受限怎么办 编辑:程序博客网 时间:2024/05/16 13:43
这是一个百分比布局实例,github 地址是  android-percent-support-lib-sample

下面是自己参考其代码,实现的一个简易百分比布局,没有什么实际作用,只是在理解google官方如何实现。


步骤如下(下面源码版本是2.3):

1、任意继承一个容器如LinearLayout,ReleativeLayout或FrameLayout。

2、重写generateLayoutParams方法,布局被解析时会被调用,需要返回一个LayoutParams对象。

话说此方法是在LayoutInflater类的inflate方法中调用,也就是通过setContentView传进去的布局,最终调用PhoneWindow的installDecor方法,继而调用LayoutInflater类的inflate方法。

private LayoutInflater mLayoutInflater;private void installDecor() {if (mDecor == null) {mDecor = generateDecor();mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);}if (mContentParent == null) {mContentParent = generateLayout(mDecor);}}protected ViewGroup generateLayout(DecorView decor) {int layoutResource;View in = mLayoutInflater.inflate(layoutResource, null);decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//id为content的viewViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);return contentParent;}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {        synchronized (mConstructorArgs) {            View result = root;            try {                int type;                final String name = parser.getName();                if (TAG_MERGE.equals(name)) {                    if (root == null || !attachToRoot) {                        throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true");                    }                    rInflate(parser, root, attrs, false);                } else {                                        View temp;                    if (TAG_1995.equals(name)) {                        temp = new BlinkLayout(mContext, attrs);                    } else {                        temp = createViewFromTag(root, name, attrs);                    }                    ViewGroup.LayoutParams params = null;                    if (root != null) {                                               // Create layout params that match root, if supplied                        params = root.generateLayoutParams(attrs);                        if (!attachToRoot) {                            temp.setLayoutParams(params);                        }                    }                    // Inflate all children under temp                    rInflate(parser, temp, attrs, true);                                        // We are supposed to attach all the views we found (int temp)to root. Do that now.                    if (root != null && attachToRoot) {                        root.addView(temp, params);                    }                    if (root == null || !attachToRoot) {                        result = temp;                    }                }                         } finally {            }            return result;        }    }


3、自定义LayoutParams类继承自LinearLayout.LayoutParams,通过AttributeSet类获取布局里面定义的属性值并解析。

 <declare-styleable name="ParcentLayout">        <attr name="parcentWidth" format="float" />        <attr name="parcentHeight" format="float" />        <attr name="parcentTextSize" format="string" />    </declare-styleable>


4、重写onMeasure计算布局的尺寸,循环view获取自定义的LayoutParams对象,重新给view设置高度和宽度。

5、如果是TextView,适配字体大小。


public class PercentLinearLayout extends LinearLayout {private static final String REGEX_PERCENT = "^(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)%([s]?[wh]?)$";public PercentLinearLayout(Context context) {super(context);}public PercentLinearLayout(Context context, AttributeSet attrs) {super(context, attrs);}private static final String TAG = "PercentLinearLayout";@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int heightSize = View.MeasureSpec.getSize(heightMeasureSpec);int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);int tmpHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,heightMode);int widthSize = View.MeasureSpec.getSize(widthMeasureSpec);int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);int tmpWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize,widthMode);// 处理ScrollViewif (heightMode == MeasureSpec.UNSPECIFIED && getParent() != null&& (getParent() instanceof ScrollView)) {int baseHeight = 0;Context context = getContext();if (context instanceof Activity) {Activity act = (Activity) context;//获取 PhoneWindow类中DecorView(继承FrameLayout)的根View的高度int measuredHeight = act.findViewById(android.R.id.content).getMeasuredHeight();baseHeight = measuredHeight;} else {baseHeight = getScreenHeight();}tmpHeightMeasureSpec = MeasureSpec.makeMeasureSpec(baseHeight,heightMode);}int width = View.MeasureSpec.getSize(tmpWidthMeasureSpec);int height = View.MeasureSpec.getSize(tmpHeightMeasureSpec); Log.d(TAG, "width = " + width + " , height = " + height);//获取子View并设置其宽度和高度int childCount = getChildCount();for (int i = 0; i < childCount; i++) {View view = getChildAt(i);LayoutParams params = (LayoutParams) view.getLayoutParams();float widthp = 0;float heightp = 0;if (params instanceof PercentLinearLayout.LayoutParams) {widthp = params.w;heightp = params.h;}if (widthp != 0) {params.width = (int) (width * widthp);}if (heightp != 0) {params.height = (int) (height * heightp);}//设置文字大小if (params.hasParcentTextSize) {supportTextSize(width,height,view,params.parcentTextSize);}} super.onMeasure(widthMeasureSpec, heightMeasureSpec);}/** * 该方法在LayoutInflater类的inflate方法中调用 */@Overridepublic android.widget.LinearLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {Log.i(TAG, "generateLayoutParams method execute ... ");return new PercentLinearLayout.LayoutParams(getContext(), attrs);}public static class LayoutParams extends LinearLayout.LayoutParams {public float h;public float w;public String parcentTextSize ;public boolean hasParcentTextSize=false;public LayoutParams(Context context, AttributeSet attrs) {super(context, attrs);TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ParcentLayout);w = a.getFloat(R.styleable.ParcentLayout_parcentWidth, -1);h = a.getFloat(R.styleable.ParcentLayout_parcentHeight, -1);parcentTextSize = a.getString(R.styleable.ParcentLayout_parcentTextSize);if (w < 0) {w = 0;}if (w > 1) {w = 1;}h = h < 0 ? 0 : h;h = h > 1 ? 1 : h;if (!TextUtils.isEmpty(parcentTextSize)) {hasParcentTextSize = true;}a.recycle();}}/** * 设置文字大小 * @param widthHint 宽度 * @param heightHint 高度 * @param view * @param percentStr 百分比字符串(20%w) */private void supportTextSize(int widthHint, int heightHint, View view,String percentStr) {Pattern p = Pattern.compile(REGEX_PERCENT);Matcher matcher = p.matcher(percentStr);if (!matcher.matches()) {throw new RuntimeException("the value of layout_xxxPercent invalid! ==>" + percentStr);}int len = percentStr.length();// extract the float valueString floatVal = matcher.group(1);float percent = Float.parseFloat(floatVal) / 100f;int base = 0;if (percentStr.endsWith("w")) {base = view.getMeasuredWidth();} else if (percentStr.endsWith("h")) {base = view.getMeasuredHeight();}float textSize = (int) (base * percent);System.out.println("ss "+textSize);// Button 和 EditText 是TextView的子类if (view instanceof TextView) {((TextView) view).setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);}}private int getScreenHeight() {WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.heightPixels;}}

<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#ffffff" >    <com.example.zzl.viewgroup.PercentLinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical" >        <TextView            android:layout_width="0dp"            android:layout_height="0dp"            android:background="#ff44aacc"            android:gravity="center"            android:text="width:55%,height:5%,ts:60%h"            android:textColor="#ffffff"            app:parcentHeight="0.05"            app:parcentTextSize="60%h"            app:parcentWidth="0.55" />        <TextView            android:layout_width="0dp"            android:layout_height="0dp"            android:layout_marginTop="20dip"            android:background="#ff99aacc"            android:gravity="center"            android:text="width:75%,height:20%,ts:40%h"            android:textColor="#ffffff"            app:parcentHeight="0.1"            app:parcentTextSize="40%h"            app:parcentWidth="0.75" />        <TextView            android:layout_width="0dp"            android:layout_height="0dp"            android:layout_marginTop="20dip"            android:background="#ff4455cc"            android:gravity="center"            android:text="width:90%,height:30%,ts:20%h"            android:textColor="#ffffff"            app:parcentHeight="0.2"            app:parcentTextSize="20%h"            app:parcentWidth="0.9" />        <TextView            android:layout_width="0dp"            android:layout_height="0dp"            android:layout_marginTop="20dip"            android:background="#ff44aa77"            android:gravity="center"            android:text="width:100%,height:40%,ts:10%h"            android:textColor="#ffffff"            app:parcentHeight="0.4"            app:parcentTextSize="10%h"            app:parcentWidth="1" />    </com.example.zzl.viewgroup.PercentLinearLayout></ScrollView>


0 0
原创粉丝点击