自定义像素适配

一、简述

自定义像素适配,就是以一个特定宽度尺寸的设备为基准,在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方法会被多次调用,所以需要加入标志位来确保只会被计算一次。

扫描二维码关注公众号,回复: 9922461 查看本文章

四、完整代码

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!

发布了201 篇原创文章 · 获赞 249 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_36299025/article/details/104920509