Android屏幕适配方案详解

Android手机的百花齐放的态势下,种类繁多的手机屏幕,也是给开发者带来了很大的工作量,屏幕适配是众多开发者老生长谈的话题,我曾经也是被屏幕适配工作弄的头大,所以今天把自己在工作中的使用的一些方法做个小小的总结;

  什么是屏幕是适配?说白了就是屏幕分辨率的适配,其核心就在于两个字“缩放”

  有哪些地方需要做适配呢?

    1、布局适配

          比如使用  wrap_content和match_parent

          使用Relativelayout 和contarintlayout

          线性布局中的Weight

   2、图片资源适配

         使用.9格式的png图片或者SVG图片来进行缩放(优势:体积小,不失真)

         使用备用位图匹配不同分辨率

  3、限定符适配

         分辨率限定符 drawable-hdpi,drawable-xhdpi。。。。

         尺寸限定符     layout-small ,layout-large

         最小宽度限定符 values-sw360dp,values-sw384dp。。。

         屏幕方向限定符 layout-land,layout-port

    我们的适配基本上都离不开以上三点;

    其中第二点和第三点基本上都会用到,用法和原理也很简单,我就不多做介绍,下面我重点讲第一点,布局适配:

     相信布局尺寸适配的方案大家多多少少都有过接触,什么百分比适配啊,利用系统能自动识别的资源名进行适配等等

     下面我重点介绍我使用过的3中适配方案;

      第一种 自定义百分比布局适配:

       原理就是使用自定义的布局继承系统原声的布局,然后重写onMeasure方法,在measure中通过设定的百分比对尺寸进行换算

public class DisPlayUtils {

    private static DisPlayUtils disPlayUtils;
    private static final float WIDTH = 720; //单位px
    private static final float HEIGHT = 1080; //单位px
    private int widthPixels;
    private int heightPixels;

    private DisPlayUtils(Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        if (displayMetrics.widthPixels > displayMetrics.heightPixels) {
            //横屏
            widthPixels = displayMetrics.heightPixels;
            heightPixels = displayMetrics.widthPixels;
        } else {
            widthPixels = displayMetrics.widthPixels;
            heightPixels = displayMetrics.heightPixels - getStatusBarHeight(context);
        }

    }

    public static DisPlayUtils getDisPlayUtils(Context context) {
        if (null == disPlayUtils) {
            synchronized (DisPlayUtils.class) {
                if (null == disPlayUtils) {
                    disPlayUtils = new DisPlayUtils(context.getApplicationContext());
                }
            }
        }
        return disPlayUtils;
    }

    private int getStatusBarHeight(Context context) {
        int identifier = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (identifier > 0) {
            return context.getResources().getDimensionPixelSize(identifier);
        }
        return 0;
    }

    public float getScaleX() {
        return widthPixels / WIDTH;
    }

    public float getScaleY() {
        return heightPixels / HEIGHT;
    }
}
public class CustomLinearLayout extends LinearLayout {

    public static final float WIDTH = 720;
    public boolean flag;

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

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (!flag) {
            float scaleX = DisPlayUtils.getDisPlayUtils(getContext()).getScaleX();
            float scaleY = DisPlayUtils.getDisPlayUtils(getContext()).getScaleY();
            for (int i = 0; i < getChildCount(); i++) {
                //遍历子View
                View child = getChildAt(i);
                LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
                if (layoutParams.height != LayoutParams.MATCH_PARENT && layoutParams.height !=               LayoutParams.WRAP_CONTENT) {
                    layoutParams.height = (int) (layoutParams.height * scaleY);
                }
                if (LayoutParams.MATCH_PARENT != layoutParams.width && LayoutParams.WRAP_CONTENT != layoutParams.width) {
                    layoutParams.width = (int) (layoutParams.width * scaleX);
                }
                layoutParams.leftMargin = (int) (layoutParams.leftMargin * scaleX);
                layoutParams.rightMargin = (int) (layoutParams.rightMargin * scaleX);
                layoutParams.topMargin = (int) (layoutParams.topMargin * scaleY);
                layoutParams.bottomMargin = (int) (layoutParams.bottomMargin * scaleY);
            }
            flag = true;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

}

      第二种 自定义像素适配

       原理和百分比类似,也是需要自定义布局,然后重写onMeasure方法,然后通过计算当前屏幕宽度和目标屏幕宽度的比值换算 出目标设备应有的尺寸

public class CustomRelativeLayout extends RelativeLayout {

    public CustomRelativeLayout(Context context) {
        this(context, null);
    }

    public CustomRelativeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);
        int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);
        //遍历子View
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
            if (checkLayoutParams(layoutParams)) {
                LayoutParams lp = (LayoutParams) layoutParams;
                float widthPercent = lp.widthPercent;
                float heightPercent = lp.heightPercent;
                float marginLeftPercent = lp.marginLeftPercent;
                float marginRightPercent = lp.marginRightPercent;
                float marginBottomPercent = lp.marginBottomPercent;
                float marginTopPercent = lp.marginTopPercent;

                if (widthPercent > 0) {
                    layoutParams.width = (int) (widthMeasure * widthPercent);
                }

                if (heightPercent > 0) {
                    layoutParams.height = (int) (heightMeasure * heightPercent);
                }

                if (marginLeftPercent > 0) {
                    ((LayoutParams) layoutParams).leftMargin = (int) (widthMeasure * marginLeftPercent);
                }

                if (marginRightPercent > 0) {
                    ((LayoutParams) layoutParams).rightMargin = (int) (widthMeasure * marginRightPercent);
                }

                if (marginBottomPercent > 0) {
                    ((LayoutParams) layoutParams).bottomMargin = (int) (heightMeasure * marginBottomPercent);
                }
                if (marginTopPercent > 0) {
                    ((LayoutParams) layoutParams).topMargin = (int) (heightMeasure * marginTopPercent);
                }
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LayoutParams;
    }

    public LayoutParams generateLayoutParams(AttributeSet attributeSet) {
        return new LayoutParams(getContext(), attributeSet);
    }

    public static class LayoutParams extends RelativeLayout.LayoutParams {
        private float widthPercent;
        private float heightPercent;
        private float marginLeftPercent;
        private float marginRightPercent;
        private float marginTopPercent;
        private float marginBottomPercent;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray typedArray = c.obtainStyledAttributes(attrs, R.styleable.CustomRelativeLayout);
            widthPercent = typedArray.getFloat(R.styleable.CustomRelativeLayout_widthPercent, 0);
            heightPercent = typedArray.getFloat(R.styleable.CustomRelativeLayout_heightPercent, 0);
            marginLeftPercent = typedArray.getFloat(R.styleable.CustomRelativeLayout_marginLeftPercent, 0);
            marginRightPercent = typedArray.getFloat(R.styleable.CustomRelativeLayout_marginRightPercent, 0);
            marginTopPercent = typedArray.getFloat(R.styleable.CustomRelativeLayout_marginTopPercent, 0);
            marginBottomPercent = typedArray.getFloat(R.styleable.CustomRelativeLayout_marginBottomPercent, 0);
            typedArray.recycle();
        }

    }
}

 

     第三种 就是大家耳熟能详的,修改系统的density值;

      这中适配方式就是通过公式  density = px/dp, 通过换算出目标设备的px和当前设备dp的比值,然后把这个新的比值重新赋值给系统的density,达到修改系统分辨率目的进行适配

public class DensityUtil {
    private static float appDensity;//设备默认的density值
    private static float scaleDensity;  //设备默认的字体缩放比例
    private static float mTargetAppDensity;//目标设备的density
    private static final float width = 360;    //设计图的尺寸 dp

    public static void setDensityUtil(final Application application) {
        DisplayMetrics metrics = application.getResources().getDisplayMetrics();
        if (appDensity == 0) {
            appDensity = metrics.density;
            scaleDensity = metrics.scaledDensity;
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    if (newConfig != null && newConfig.fontScale > 0) {
                        scaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {

                }
            });
        }
        mTargetAppDensity = metrics.widthPixels / width;
    }

    public static int getStatusBarHeight(Context context) {
        int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resId > 0) {
            return context.getResources().getDimensionPixelSize(resId);
        }
        return 45;
    }

    public static void setAppDensity(Activity activity) {
        //目标设备的字体缩放比例
        float mTargetScaleDensity = mTargetAppDensity * (scaleDensity / appDensity);
        //目标设备的像素密度;
        int targetDensityDpi = (int) (mTargetAppDensity * 160);
        DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
        displayMetrics.scaledDensity = mTargetScaleDensity;
        displayMetrics.density = mTargetAppDensity;
        displayMetrics.densityDpi = targetDensityDpi;
    }

}

   

  

你可能感兴趣的:(Android屏幕适配方案详解)