前言 屏幕适配框架AndroidAutoSize是根据今日头条屏幕适配方案优化的。
这种方案无法在Jetpack Compose中使用。
Jetpack Compose可参考文章:
https://www.psvmc.cn/article/2024-04-07-jetpack-compose-ui-adaptation.html
Github地址
https://github.com/JessYanCoding/AndroidAutoSize
基本使用 添加依赖
1 implementation 'me.jessyan:autosize:1.2.1'
kts中
1 implementation("me.jessyan:autosize:1.2.1" )
AndroidAutoSize 在使用上非常简单,只需要填写设计图尺寸这一步即可接入项目;
假如我的设计图是横屏的,宽度是1920,高度是1128的2倍图。
我们可以按如下设置
1 2 3 4 5 6 7 8 9 10 <manifest > <application > <meta-data android:name ="design_width_in_dp" android:value ="960" /> <meta-data android:name ="design_height_in_dp" android:value ="564" /> </application > </manifest >
注意
默认是按照宽度适配的。
这里的宽度是效果图的宽度,不是是效果图窄边的DP值。
如果按短边适配
1 2 3 4 5 6 7 <manifest > <application > <meta-data android:name ="design_width_in_dp" android:value ="960" /> </application > </manifest >
有两种类型的布局单位可以选择,一个是 主单位 (dp、sp),一个是 副单位 (pt、in、mm)
主单位 : 使用 dp、sp 为单位进行布局,侵入性最低,会影响其他三方库页面、三方库控件以及系统控件的布局效果,但 AndroidAutoSize 也通过这个特性,使用 ExternalAdaptManager 实现了在不修改三方库源码的情况下适配三方库的功能
副单位 : 使用 pt、in、mm 为单位进行布局,侵入性高,对老项目的支持比较好,不会影响其他三方库页面、三方库控件以及系统控件的布局效果,可以彻底的屏蔽修改 density 所造成的所有未知和已知问题,但这样 AndroidAutoSize 也就无法对三方库进行适配
在使用主单位时,design_width_in_dp 和 design_height_in_dp 的单位必须是 dp,计算公式 dp = px / (DPI / 160) 将 px 尺寸转换为 dp 尺寸,如果实在找不到设备的 DPI 那就直接将 px 尺寸除以 3 或者 2 。
忽略适配 如果某个 Activity 想放弃适配,让这个 Activity 实现 CancelAdapt 接口即可,比如修改 density 影响到了老项目中的某些 Activity 页面的布局效果,这时就可以让这个 Activity 实现 CancelAdapt 接口
1 2 3 public class CancelAdaptActivity extends AppCompatActivity implements CancelAdapt {}
Fragment也是一样
实现 CancelAdapt
1 2 3 public class CancelAdaptFragment extends Fragment implements CancelAdapt {}
进阶使用 在 AndroidManifest.xml 中填写的设计尺寸,是整个项目的全局设计图尺寸。
但是如果某些 Activity 页面由于某些原因,这个页面的设计图尺寸和在 AndroidManifest.xml 中填写的设计图尺寸不一样该怎么办呢?
则可以让这个页面的 Activity 实现 CustomAdapt ,CustomAdapt 接口的第一个方法可以修改当前页面的设计尺寸。
自定义Activity 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CustomAdaptActivity extends AppCompatActivity implements CustomAdapt { @Override public boolean isBaseOnWidth () { return false ; } @Override public float getSizeInDp () { return 667 ; } }
自定义Fragment Fragment 的自定义方式和 Activity 是一样的,只不过在使用前需要先在 App 初始化时开启对 Fragment 的支持
1 AutoSizeConfig.getInstance().setCustomFragment(true );
实现 CustomAdapt
1 2 3 4 5 6 7 8 9 10 11 12 public class CustomAdaptFragment extends Fragment implements CustomAdapt { @Override public boolean isBaseOnWidth () { return false ; } @Override public float getSizeInDp () { return 667 ; } }
偶尔失效解决方案 在任何情况下本来适配正常的布局突然出现适配失效,适配异常等问题,只要重写 Activity 的 getResources() 方法即可,如果是 Dialog、PopupWindow 等控件出现适配失效或适配异常,同样在每次 show() 之前调用 autoConvertDensity() 即可。
方法参数
1 public static void autoConvertDensity (Resources resources, float sizeInDp, boolean isBaseOnWidth) {}
Java 1 2 3 4 5 6 @Override public Resources getResources () { AutoSizeCompat.autoConvertDensityOfGlobal((super .getResources()); return super .getResources(); }
如果有自定义需求就用这个方法
1 2 3 4 5 6 @Override public Resources getResources () { AutoSizeCompat.autoConvertDensity((super .getResources(), 960 , true ); return super .getResources(); }
Kotlin中 1 2 3 4 5 override fun getResources () : Resources { AutoSizeCompat.autoConvertDensityOfGlobal(super .getResources()) return super .getResources() }
或
1 2 3 4 5 override fun getResources () : Resources { AutoSizeCompat.autoConvertDensity(super .getResources(), 960f , true ) return super .getResources() }
屏幕宽高 要在Android应用中获取屏幕的宽度和高度,你可以使用DisplayMetrics类。
以下是获取屏幕宽度和高度的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import android.content.Context;import android.util.DisplayMetrics;import android.view.WindowManager;public class ZScreenUtils { public static int getScreenWidth (Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); if (windowManager != null ) { windowManager.getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.widthPixels; } return 0 ; } public static int getScreenHeight (Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); if (windowManager != null ) { windowManager.getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.heightPixels; } return 0 ; } public static int getScreenWidthInDP (Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); if (windowManager != null ) { windowManager.getDefaultDisplay().getMetrics(displayMetrics); float density = context.getResources().getDisplayMetrics().density; return (int ) (displayMetrics.widthPixels / density); } return 0 ; } public static int getScreenHeightInDP (Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); if (windowManager != null ) { windowManager.getDefaultDisplay().getMetrics(displayMetrics); float density = context.getResources().getDisplayMetrics().density; return (int ) (displayMetrics.heightPixels / density); } return 0 ; } }
你可以在任何Context对象可用的地方调用这两个方法,比如在Activity中:
1 2 3 4 5 6 7 8 val screenWidth: Int = ZScreenUtils.getScreenWidth(baseContext)val screenHeight: Int = ZScreenUtils.getScreenHeight(baseContext)Log.i(TAG, "onCreate: screenWidth:${screenWidth} " ) Log.i(TAG, "onCreate: screenHeight:${screenHeight} " ) val screenWidthDp: Int = ZScreenUtils.getScreenWidthInDP(baseContext)val screenHeightDp: Int = ZScreenUtils.getScreenHeightInDP(baseContext)Log.i(TAG, "onCreate: screenWidthDp:${screenWidthDp} " ) Log.i(TAG, "onCreate: screenHeightDp:${screenHeightDp} " )
记得在AndroidManifest.xml中添加必要的权限:
1 <uses-permission android:name ="android.permission.READ_EXTERNAL_STORAGE" />
这样你就可以获取到屏幕的宽度和高度了。