Android屏幕适配

2019-04-11  本文已影响0人  时间不可逆
  1. px适配;
  2. 百分比适配;
  3. 修改dp适配;

屏幕适配


自定义view中像素适配

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    if(!flag){
        float scaleX = Utils.getInstance(getContext()).getHorizontalScale();//获取横向的缩放比例
        float scaleY = Utils.getInstance(getContext()).getVerticalScale();//获取竖向的缩放比例
        for(int i = 0; i < getChildCount(); i++){
            View child = getChildAt(i);
            LayoutParams lp = (LayoutParams)child.getLayoutParams();
            lp.width = (int) (lp.width * scaleX);//换算宽度目标值
            lp.height = (int)(lp.height * scaleY);//换算高度的目标值
            lp.topMargin = (int)(lp.topMargin * scaleY);//换算四周间距的目标值
            ......
          }
        flag = true;
    }
    super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}

缩放比例 是当前设备的像素值和参考值比值的结果;布局中是px来写布局;

百分比布局适配

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    //获取父容器的宽高
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    ...
    for(int i = 0; i < getChildCount(); i++){
        View child = getChildAt(i);//重写设置子view的布局属性,再进行view的测量
        LayoutParams lp = (LayoutParams)child.getLayoutParams();
        float widthPercent = ((LayoutParams).lp).widthPercent;//自定义百分比属性
        if(widthPercent > 0){
            lp.width = (int) width * widthPercent;//设置当前view在父容器中的尺寸占比
        }
        ...
    }
    super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}

注意:需要参考RelativeLayout中的静态类LayoutParams实现自定义容器布局;
view的加载过程,view是通过容器view来进行加载;

  1. 创建自定义属性
  2. 继承 static LayoutParams,解析自定义属性;
  3. 必须重写generateLayoutParams(AttributeSet attrs)方法;
  4. 重写onMeasure,计算;

像素密度适配

px : 其实就是像素单位,比如我们通常说的手机分辨列表800*400都是px的单位
sp : 同dp相似,还会根据用户的字体大小偏好来缩放
dp : 虚拟像素,在不同的像素密度的设备上会自动适配
dip: 同dp
要理解dp,首先要先引入dpi这个概念,dpi全称是dots per inch,对角线每英寸的像素点的个数,
而dp也叫dip,是device independent pixels。设备不依赖像素的一个单位。在不同的像素密度的设备上会自动适配,比如:
在320x480分辨率,像素密度为160,1dp=1px
在480x800分辨率,像素密度为240,1dp=1.5px
计算公式:px = dp * (dpi/160)

private static final float WIDTH = 360;//参考像素密度
protected void setDensity(final Application application,Activity activity){
    DisplayMetics appDisplayMetrics = application.getResources().getDisplayMetrics();
    //获取目标density值
    ...
    float targetDensity = appDisplayMetrics.widthPixels / WIDTH;
    float targetScaleDensity = targetDensity * (appScaledDensity / appDensity);
    int targetDensityDpi = (int)(targetDensity * 160);
    //替换Activity的density,scaleDensity等值
    DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
    displayMetrics.density = targetDensity;
    displayMetrics.scaledDensity = targetScaleDensity;
    displayMetrics.densityDpi = targetDensityDpi;
}
//可运行代码
 private static final float WIDTH = 360;//参考屏幕的宽,单位是dp  设计稿的大小
 private static float appDensity;//表示屏幕的密度
 private static float appScaledDensity;//表示字体缩放比例 默认是density
public static void setDensity(final Application application, Activity activity){
        final DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
        if (appDensity == 0){
            appDensity = displayMetrics.density;
            appScaledDensity = displayMetrics.scaledDensity;
            //监听系统 字体变化
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    if (newConfig != null && newConfig.fontScale > 0){
                        appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }
                @Override
                public void onLowMemory() {
                }
            });
        }
        //目标的值
        float targetDensity = displayMetrics.widthPixels / WIDTH;// 1080 / 360 = 3.0  --- 类比 160 /160 = 1
        float targetScaledDensity = targetDensity * (appScaledDensity / appDensity);
        int targetDensityDpi = (int) (targetDensity * 160);
        //需要修改的 值
        DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        metrics.density = targetDensity;
        metrics.scaledDensity = targetScaledDensity;
        metrics.densityDpi = targetDensityDpi;
    }

刘海屏适配

//获取刘海高度,通常情况刘海的高度不会超过状态栏高度
int height = getStatusBarHeight();
//设置控件的margin
//设置父容器的padding

部分代码参考

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //1 设置全屏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        Window window = getWindow();
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        if (hasCutout(window)) {
            //2 内容可以延伸进刘海
            WindowManager.LayoutParams attributes = window.getAttributes();
            /*
             * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 默认
             * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES  可以扩展
             * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 不允许
             */
            attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
            //3.沉浸式设置
            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;//虚拟导航栏
            int visibility = window.getDecorView().getSystemUiVisibility();//系统的显示类型
            visibility |= flags;
            window.getDecorView().setSystemUiVisibility(visibility);
        }
        setContentView(R.layout.activity_cutout);
        //1.判断手机厂商  2.判断是否有刘海  3.是否内容延伸进刘海  4.是否内容 避开刘海  5、获取刘海高
    }

    @TargetApi(Build.VERSION_CODES.P)
    boolean hasCutout(Window window) {
        View decorView = window.getDecorView();
        WindowInsets rootWindowInsets = decorView.getRootWindowInsets();
        DisplayCutout displayCutout = rootWindowInsets.getDisplayCutout();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && displayCutout != null) {
            if (displayCutout.getBoundingRects() != null && displayCutout.getBoundingRects().size() > 0 && displayCutout.getSafeInsetTop() > 0) {
                return true;
            }
        }
        return false;
    }

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

猜你喜欢

热点阅读