自定義像素適配

一、簡述

自定義像素適配,就是以一個特定寬度尺寸的設備爲基準,在view的加載過程中,根據當前設備的實際像素換算出目標像素,再作用於控件上。

二、實現

2.1 通過單例獲取當前設備的寬高

	// 獲取單例方法
    public static Utils getInstance(Context context){
        if (utils == null){
            utils = new Utils(context.getApplicationContext());
        }
        return utils;
    }

當然,單例模式的實現有很多種。這部分是靈活的。

2.2 獲取屏幕的寬高

首先得創建屏幕信息顯示對象DisplayMetrics,通過它來獲取屏幕的寬高,如:displayMetrics.widthPixels

    private Utils(Context context){
        //獲取屏幕的寬高
        if(mDisplayWidth == 0 || mDisplayHeight == 0){ //進行賦值操作
            WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            if (manager != null){
				//創建屏幕信息顯示對象
                DisplayMetrics displayMetrics = new DisplayMetrics();
                manager.getDefaultDisplay().getMetrics(displayMetrics);
				//屏幕的寬>屏幕的高
                if (displayMetrics.widthPixels > displayMetrics.heightPixels){
                    //橫屏
                    mDisplayWidth = displayMetrics.heightPixels;
                    mDisplayHeight = displayMetrics.widthPixels;
                }else{
                    mDisplayWidth = displayMetrics.widthPixels;
                    mDisplayHeight = displayMetrics.heightPixels - getStatusBarHeight(context);
                }
            }
        }

    }

當然,這裏還得注意橫豎屏的問題。需要在此進行判斷、處理。

2.3 獲取狀態欄高度

在計算高度時,需要對狀態欄的高度按需減去。

	//獲取狀態欄高度,計算高度時需減去狀態欄高度
    public int getStatusBarHeight(Context context){
		// 系統內部定義的獲取狀態欄高度的方法
        int resID = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resID > 0){//如果能取到資源id,就返回
            return context.getResources().getDimensionPixelSize(resID);
        }
        return 0;
    }

通過資源id獲取,這是系統內部定義的獲取狀態欄高度的方法。涉及到的幾個參數,分別表示獲取的狀態欄高度、類型、哪個包下

2.4 計算縮放比例

這裏還需要兼顧參考設備的寬高,計算縮放比例

    //獲取水平方向的縮放比例
    public float getHorizontalScale(){
        return mDisplayWidth / STANDARD_WIDTH;
    }

    //獲取垂直方向的縮放比例
    public float getVerticalScale(){
        return mDisplayHeight / STANDARD_HEIGHT;
    }

三、使用

在自定義view中的onMeasure方法中,重新換算目標值。在該方法中,會遍歷所有的子view,對子view的佈局屬性重新設置、賦值

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (!flag){
			//獲取橫、縱向縮放比
            float scaleX = Utils.getInstance(getContext()).getHorizontalScale();
            float scaleY = Utils.getInstance(getContext()).getVerticalScale();

            int count = getChildCount();
            for (int i = 0; i < count; i++) {
				//重新設置子view的佈局屬性,再進行view的測量
                View child = getChildAt(i);
                LayoutParams params = (LayoutParams) child.getLayoutParams();
				//換算成寬高目標值
                params.width = (int) (params.width * scaleX);
                params.height = (int) (params.height * scaleY);
				//換算四周間距的目標值
                params.leftMargin = (int)(params.leftMargin * scaleX);
                params.rightMargin = (int)(params.rightMargin * scaleX);
                params.topMargin = (int)(params.topMargin * scaleY);
                params.bottomMargin = (int)(params.bottomMargin * scaleY);
            }
            flag = true;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

這裏需要注意一點,由於onMeasure方法會被多次調用,所以需要加入標誌位來確保只會被計算一次。

四、完整代碼

Utils .java

public class Utils {

    private static Utils utils;

    //這裏是設計稿參考寬高
    private static final float STANDARD_WIDTH = 1080;
    private static final float STANDARD_HEIGHT = 1920;

    //這裏是屏幕顯示寬高
    private int mDisplayWidth;
    private int mDisplayHeight;

    private Utils(Context context){
        //獲取屏幕的寬高
        if(mDisplayWidth == 0 || mDisplayHeight == 0){ //進行賦值操作
            WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            if (manager != null){
				//創建屏幕信息顯示對象
                DisplayMetrics displayMetrics = new DisplayMetrics();
                manager.getDefaultDisplay().getMetrics(displayMetrics);
				//屏幕的寬>屏幕的高
                if (displayMetrics.widthPixels > displayMetrics.heightPixels){
                    //橫屏
                    mDisplayWidth = displayMetrics.heightPixels;
                    mDisplayHeight = displayMetrics.widthPixels;
                }else{
                    mDisplayWidth = displayMetrics.widthPixels;
                    mDisplayHeight = displayMetrics.heightPixels - getStatusBarHeight(context);
                }
            }
        }

    }

	//獲取狀態欄高度,計算高度時需減去狀態欄高度
    public int getStatusBarHeight(Context context){
		// 系統內部定義的獲取狀態欄高度的方法
        int resID = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resID > 0){//如果能取到資源id,就返回
            return context.getResources().getDimensionPixelSize(resID);
        }
        return 0;
    }
	
	// 獲取單例方法
    public static Utils getInstance(Context context){
        if (utils == null){
            utils = new Utils(context.getApplicationContext());
        }
        return utils;
    }

    //獲取水平方向的縮放比例
    public float getHorizontalScale(){
        return mDisplayWidth / STANDARD_WIDTH;
    }

    //獲取垂直方向的縮放比例
    public float getVerticalScale(){
        return mDisplayHeight / STANDARD_HEIGHT;
    }

}

ScreenAdapterLayout .java

public class ScreenAdapterLayout extends RelativeLayout {

    private boolean flag;

    public ScreenAdapterLayout(Context context) {
        super(context);
    }

    public ScreenAdapterLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ScreenAdapterLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (!flag){
			//獲取橫、縱向縮放比
            float scaleX = Utils.getInstance(getContext()).getHorizontalScale();
            float scaleY = Utils.getInstance(getContext()).getVerticalScale();

            int count = getChildCount();
            for (int i = 0; i < count; i++) {
				//重新設置子view的佈局屬性,再進行view的測量
                View child = getChildAt(i);
                LayoutParams params = (LayoutParams) child.getLayoutParams();
				//換算成寬高目標值
                params.width = (int) (params.width * scaleX);
                params.height = (int) (params.height * scaleY);
				//換算四周間距的目標值
                params.leftMargin = (int)(params.leftMargin * scaleX);
                params.rightMargin = (int)(params.rightMargin * scaleX);
                params.topMargin = (int)(params.topMargin * scaleY);
                params.bottomMargin = (int)(params.bottomMargin * scaleY);
            }
            flag = true;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

五、注意

單位都得是px!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章