在编写xml的时候,我们直接指定一个固定一个控件的宽高,给一个固定的dp值,在不同的屏幕上显示差别很大,导致有的手机布局无法正常显示,所以需要适配屏幕,这里讲的适配方式都一样,不过方法不一样
首先古老的适配一般就是自己计算,然后生成文件,以前自己也这么干过,直接规定好自己需要的尺寸,然后代码去计算生成,然后复制到项目中使用,一般常用的尺寸如下
执行代码会根据定义的尺寸生成出对应的 dimens.xml 类,下面是代码
package com.example.myapplication; import android.util.Log; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigDecimal; public class MakeUtils { private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"; private static final String XML_RESOURCE_START = "<resources>\r\n"; private static final String XML_RESOURCE_END = "</resources>\r\n"; private static final String XML_DIMEN_TEMPLETE = "<dimen name=\"qb_%1$spx_%2$d\">%3$.2fdp</dimen>\r\n"; private static final String XML_BASE_DPI = "<dimen name=\"base_dpi\">%ddp</dimen>\r\n"; private static final int MAX_SIZE = 720; private static final String XML_NAME = "dimens.xml"; public static float px2dip(float pxValue, int sw,int designWidth) { float dpValue = (pxValue/(float)designWidth) * sw; BigDecimal bigDecimal = new BigDecimal(dpValue); float dp = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue(); return dp; } /** * 生成所有的尺寸数据 */ private static String createDimens(DimenTypes type, int designWidth) { float dpValue; String temp; StringBuilder sb = new StringBuilder(); try { sb.append(XML_HEADER); sb.append(XML_RESOURCE_START); //备份生成的相关信息 temp = String.format(XML_BASE_DPI, type.getSwWidthDp()); sb.append(temp); for (int i = 0; i <= MAX_SIZE; i++) { dpValue = px2dip((float) i,type.getSwWidthDp(),designWidth); temp = String.format(XML_DIMEN_TEMPLETE,"", i, dpValue); sb.append(temp); } sb.append(XML_RESOURCE_END); } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } /** * 生成的目标文件夹 */ public static void create(int designWidth, DimenTypes type, String buildDir) { try { //生成规则 final String folderName; if (type.getSwWidthDp() > 0) { //适配Android 3.2+ folderName = "values-sw" + type.getSwWidthDp() + "dp"; }else { return; } //生成目标目录 File file = new File(buildDir + File.separator + folderName); if (!file.exists()) { file.mkdirs(); } Log.e("===",file.getAbsolutePath()); //生成values文件 FileOutputStream fos = new FileOutputStream(file.getAbsolutePath() + File.separator + XML_NAME); fos.write(createDimens(type,designWidth).getBytes()); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } }
package com.example.myapplication; /** * created by YooJin. * date: 2021/2/3 13:50 * ldpi: 120 density:1dp=0.75px 代表尺寸 240*320 * mdpi: 160 density:1dp=1px 代表尺寸 320*480 * hdpi: 240 density:1dp=1.5px 代表尺寸 480*800 * xhdpi: 320 density:1dp=2px 代表尺寸720*1280 * xxhdpi: 480 density:1dp=3px 代表尺寸1080*1920 */ enum DimenTypes { DP_sw__160(160), DP_sw__240(240), DP_sw__280(280), DP_sw__320(320), DP_sw__360(360), DP_sw__400(400), DP_sw__420(420), DP_sw__440(440), DP_sw__480(480), DP_sw__560(560), DP_sw__640(640), DP_sw__720(720), DP_sw__800(800); /** * 屏幕最小宽度 */ private int swWidthDp; DimenTypes(int swWidthDp) { this.swWidthDp = swWidthDp; } public int getSwWidthDp() { return swWidthDp; } public void setSwWidthDp(int swWidthDp) { this.swWidthDp = swWidthDp; } }
package com.example.myapplication; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Environment; import android.widget.TextView; import java.io.File; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { /** * 设计稿尺寸,从零开始,生成的最大尺寸 */ private static final int DESIGN_WIDTH = 375; String[] permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; List<String> mPermissionList = new ArrayList<>(); private static final int PERMISSION_REQUEST = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkPermission(); String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + File.separator + "res"; TextView tvTag = findViewById(R.id.tv_tag); tvTag.setText(path); DimenTypes[] values = DimenTypes.values(); for (DimenTypes value : values) { MakeUtils.create(DESIGN_WIDTH, value, path); } } private void checkPermission() { mPermissionList.clear(); //判断哪些权限未授予 for (int i = 0; i < permissions.length; i++) { if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) { mPermissionList.add(permissions[i]); } } /** * 判断是否为空 */ if (mPermissionList.isEmpty()) {//未授予的权限为空,表示都授予了 } else {//请求权限方法 String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组 ActivityCompat.requestPermissions(MainActivity.this, permissions, PERMISSION_REQUEST); } } /** * 响应授权 * 这里不管用户是否拒绝,都进入首页,不再重复申请权限 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case PERMISSION_REQUEST: break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); break; } } }
执行代码后打印出路径,我这里是下载目录下的res文件,注意需要先申请权限,然后把生成的文件剪切出来
里面都把dimens文件生成好了
直接把文件复制到项目里就可以直接使用了,那么有没有什么便捷一点的开关呢,还真有
androidstudio上面有个插件 ScreenMatch,安装后可以直接生成这些文件,并且可以动态配置,很方便
安装好后直接右键会有一个ScreenMatch菜单,点它
然后会发现你项目里已经有两个配置文件了
一个dimens.xml文件,是例子,生成文件的基类,需要把里面的值复制到自己values下的dimens.xml文件中,如果你项目里没有这个文件就手动创建它
另外一个是生成的配置文件,配置一些你需要生成的尺寸,它默认会有一些尺寸,你可以把你需要没有的添加上,把不需要的过滤掉
然后在次右键选择 ScreenMatch,项目里会出现配置里的尺寸xml文件了
跟老的值对比一下,验证是否正确,同时打开sw240dp里的xml,对应里面的值
左边的是代码生成的,右边的是插件生成的,dp1=0.64,dp2=1.28,然后我们在打开sw800dp里的xml看看
dp1=2.13,dp2=4.27,说明两种方式都一样,但是有插件省去了我们的计算