Android屏幕自适应1:https://developer.aliyun.com/article/1473627
3. Java代码中设置宽高
示例代码
activity_main.xml 文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#000000" android:text="按钮1"/> <Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ffffff" android:text="btn2"/> <Button android:id="@+id/btn3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ff0000" android:text="btn3"/> <Button android:id="@+id/btn4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ff00ff" android:text="btn4"/> </LinearLayout>
MainActivity.java 文件
// app启动时先获取当前屏幕的宽高 DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); phoneWidth = displayMetrics.widthPixels; phoneHeight = displayMetrics.heightPixels; // 设置控件大小 // 第一个按钮,宽度100%,高度10% LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT,(int) (phoneHeight * 0.1f + 0.5f)); btn1.setLayoutParams(params); // 第二个按钮,宽度100%,高度30% LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT,(int) (phoneHeight * 0.3f + 0.5f)); btn2.setLayoutParams(params2); // 第三个按钮,宽度50%,高度20% LinearLayout.LayoutParams params3 = new LinearLayout.LayoutParams( (int) (phoneWidth * 0.5f + 0.5f),(int) (phoneHeight * 0.2f + 0.5f)); btn3.setLayoutParams(params3); // 第三个按钮,宽度70%,高度填满剩下的空间 LinearLayout.LayoutParams params4 = new LinearLayout.LayoutParams( (int) (phoneWidth * 0.7f + 0.5f),LayoutParams.MATCH_PARENT); btn4.setLayoutParams(params4);
4. smallestWidth
sw限定符适配(需要安装 SmallestWidth Dimens 插件),依据最小宽度限定符,指的是 Android 会识别屏幕宽度最小尺寸的 dp 值(其实就是手机的宽度值),然后根据识别到的结果去资源文件中寻找对应限定符的文件夹下的资源文件。
这个可以使用 Android Studio 里的 SmallestWidth Dimens 插件来完成。
需要注意的是,如果没有 values-sw360dp 文件夹,系统会向下寻找,比如离 360dp 最近的只有 values-sw340dp,那么系统就会选择 values-sw340dp 文件夹下的资源文件;
5. 多layout适配
多layout适配主要是针对某个分辨率,新建一个layout文件夹
6. 今日头条适配方案
适配方案的核心原理在于根据dp和px的转换公式 :px = dp * density,不管我们设定的单位是什么, 最终我们都会将这些单位长度转化为px的。
density就是他们的转化比, 所以,动态改变这个转化比也是可以达到我们适配屏幕的目的。
通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值(在清单文件中定义),这样就解决了所有的适配问题;
Density = 当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) ;
例:分辨率1080x1920,dpi为480,正常情况下计算density=dpi/160=480/160=3,此时屏幕总宽度dp=px/density=1080/3=360;
一般的应用场景就是在BaseActivity的onCreate方法中调用,即可达成全局适配;
/// 在Activity中的onCreate方法中调用,必须在setContentView()之前 CustomDensityUtil.setCustomDensity(MainActivity.this, getApplication());
今日头条适配方案工具类
public class CustomDensityUtil { // 系统的Density private static float sNoncompatDensity; // 系统的ScaledDensity private static float sNoncompatScaledDensity; /** * 今日头条适配方案 * * @param activity * @param application */ public static void setCustomDensity(Activity activity, final Application application) { //通过资源文件getResources类获取DisplayMetrics DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (sNoncompatDensity == 0) { //保存之前density值 sNoncompatDensity = appDisplayMetrics.density; //保存之前scaledDensity值,scaledDensity为字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值 sNoncompatScaledDensity = appDisplayMetrics.scaledDensity; //监听设备系统字体切换 application.registerComponentCallbacks(new ComponentCallbacks() { public void onConfigurationChanged(Configuration newConfig) { if (newConfig != null && newConfig.fontScale > 0) { //调节系统字体大小后改变的值 sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } public void onLowMemory() { } }); } //获取以设计图总宽度360dp下的density值 float targetDensity = appDisplayMetrics.widthPixels / 360; //通过计算之前scaledDensity和density的比获得scaledDensity值 float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity); //获取以设计图总宽度360dp下的dpi值 int targetDensityDpi = (int) (160 * targetDensity); //设置系统density值 appDisplayMetrics.density = targetDensity; //设置系统scaledDensity值 appDisplayMetrics.scaledDensity = targetScaleDensity; //设置系统densityDpi值 appDisplayMetrics.densityDpi = targetDensityDpi; //获取当前activity的DisplayMetrics final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); //设置当前activity的density值 activityDisplayMetrics.density = targetDensity; //设置当前activity的scaledDensity值 activityDisplayMetrics.scaledDensity = targetScaleDensity; //设置当前activity的densityDpi值 activityDisplayMetrics.densityDpi = targetDensityDpi; } }
源码
/** * @param unit 要转换的单位 * @param value 单位对应的值 * @param metrics 显示指标 */ public static float applyDimension(int unit, float value,DisplayMetrics metrics){ switch (unit) { case COMPLEX_UNIT_PX://单位为px return value; case COMPLEX_UNIT_DIP://单位为dp return value * metrics.density; case COMPLEX_UNIT_SP://单位为sp return value * metrics.scaledDensity; case COMPLEX_UNIT_PT://单位为pt return value * metrics.xdpi * (1.0f/72); case COMPLEX_UNIT_IN://单位为in return value * metrics.xdpi; case COMPLEX_UNIT_MM://单位为mm return value * metrics.xdpi * (1.0f/25.4f); } return 0; }