android自定義View(2):實現百分比自適應佈局

Dusan_杜小菜發表於2016-05-09

android介面適配難是歷史原因,我們只能想辦法解決。github上面已有一些佈局自適應的解決方案,今天我分享的是自定義控制元件:RelativieLayout自適應百分比寬高。直接上菜。

一,實現的效果圖

寬高都是50%自適應
眼見為實,截圖所示,寬高都是50%,實現了自適應

二,實現的原理

其實很簡單,就是自定義兩個屬性:寬和高的百分比,讓自定義的view繼承 RelativeLayout。取出這兩個屬性的值,測量父佈局的寬高,乘百分比就是實際的寬高,然後確定在父控制元件中的位置。

三,自定義樣式屬性

在values資料夾中新建attrs.xml,內容如下:
layout_widthPercent和layout_heightPercent都是浮點型,0-1之間的值,代表百分百。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="percentRelativeLayout">
        <attr name="layout_widthPercent" format="float"></attr>
        <attr name="layout_heightPercent" format="float"></attr>
    </declare-styleable>
</resources>

四,自定義percentRelativeLayout

簡單粗暴,根據xml佈局中的子view的LayoutParams獲取實際寬高。

public class PercentRelativeLayout extends RelativeLayout{
    public PercentRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
    }
    public PercentRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }
    public PercentRelativeLayout(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }   
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        // TODO Auto-generated method stub
        return new LayoutParams(getContext(), attrs);
    }
    //測量自己
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //獲取自身的寬高
        int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
        int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
        for(int i = 0;i<this.getChildCount();i++){
            View child = this.getChildAt(i);
            //獲取孩子view的佈局屬性
            ViewGroup.LayoutParams params = child.getLayoutParams();
            float widthPercent = 0;
            float heightPercent = 0;
            //含有自定義的屬性,則獲取百分百
            if(params instanceof PercentRelativeLayout.LayoutParams){
                widthPercent = ((PercentRelativeLayout.LayoutParams) params).getWidthPercent();
                heightPercent = ((PercentRelativeLayout.LayoutParams) params).getHeightPercent();
            }
            if(widthPercent == 0|| heightPercent == 0){
                continue;//百分百為0,跳出此次迴圈
            }
            //真實的寬高
            params.width = (int) (widthPercent*widthHint);
            params.height = (int) (heightPercent*heightHint);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // TODO Auto-generated method stub
        super.onLayout(changed, l, t, r, b);
    }
    public static class LayoutParams extends RelativeLayout.LayoutParams{
        private float widthPercent;
        private float heightPercent;
        public float getWidthPercent() {
            return widthPercent;
        }
        public void setWidthPercent(float widthPercent) {
            this.widthPercent = widthPercent;
        }
        public float getHeightPercent() {
            return heightPercent;
        }
        public void setHeightPercent(float heightPercent) {
            this.heightPercent = heightPercent;
        }
        //建構函式裡面獲取自定義樣式屬性的值
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray array = c.obtainStyledAttributes(attrs, R.styleable.percentRelativeLayout);
            widthPercent = array.getFloat(R.styleable.percentRelativeLayout_layout_widthPercent, widthPercent);
            heightPercent = array.getFloat(R.styleable.percentRelativeLayout_layout_heightPercent,heightPercent);
            array.recycle();
        }
        public LayoutParams(int w, int h) {
            super(w, h);
            // TODO Auto-generated constructor stub
        }
        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
            super(source);
            // TODO Auto-generated constructor stub
        }
        public LayoutParams(MarginLayoutParams source) {
            super(source);
            // TODO Auto-generated constructor stub
        }
    }
}

五,佈局中引用自定義View和屬性

上菜了。不用 系統控制元件,用我們們自己的。

<com.example.view.PercentRelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.example.percent_relativelayout_dn"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="測試百分比佈局" 
        android:layout_centerInParent="true"
        app:layout_widthPercent = "0.5"
        app:layout_heightPercent = "0.5"
        android:background="#00ff00"
        android:id="@+id/textview"
        />
</com.example.view.PercentRelativeLayout>

六,實現與總結

直接在activity中執行測試,是不是很完美了。寬高半分比佈局OK了。

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

五大布局都可以實現,今天只是分享了RelativieLayout的中控制元件的百分百自適應。之前在github上面看了一個很全面的百分百佈局方案,其實原理就這樣。
歡迎交流,杜乾,Dusan,Q 291902259。

相關文章