概述
工具 AndroidStudio3.0.1
1 明确几个概念
- 平时称呼的 1920*1080 是指的分辨率 px,既 1920*1280px
- 相同的分辨率在不同尺寸的设备上会产生不同的像素密度 dpi
- 谷歌目前(2018.05.25)规定的像素密度,以及对应的 dp 转换比例下
| ldpi | mdpi | tvdpi | hdpi | xhdpi | xxhdpi |
1dp转换为px | 0.75 | 1 | 1.33 | 1.5 | 2 | 3 |
2 分析
根据 1 中第三条可以知道 dp 的出现是谷歌提供给开发者的一种适配方案,并且 Android 系统会把形形色色的屏幕像素密度归并到上面提到的几种。如果屏幕的尺寸和分辨率不是特别奇葩的话,dp 能很好的实现自己的设计目的。利用 dp 可以保障: 同一dp长度的控件在不同设备上物理尺寸是相同的。
设想一种情景:希望一个控件占据整个屏幕宽度的一半。这种场景可以用代码设置,但是实现起来比较麻烦。更何况我们希望方便快捷。我们希望只给控件在 xml 文件中标记尺寸,令其自动完成占据一半的逻辑。这时可以用到今天要讲的 dimens 适配。
3 dimens 适配的原理
令控件占据屏幕的一半,必定是控件根据不同的屏幕来变化尺寸(dp值),这里的思路是在 xml 文件中填写一个占位符,系统运行的时候会根据不同的屏幕尺寸把占位符替换成不同的dp值。
为了实现上面的逻辑需要: 1 定义一个基准屏幕,例如 分辨率是760*1280 密度是 xhdpi 的屏幕,这样屏幕的宽度就是 760/2 = 380dp 。 2 创建不同的 dimes 文件,以便适应不同的屏幕。
例如在 stuido 开发中 利用Nexus4 来开发 xml。也可以创建一个自定义屏幕完全和基准屏幕相同。 在xml 只需要设置 android:layout_width="@dimen/dp190" 即可。这样在基准屏幕上 dp190 会转换为 190dp 正好是 380dp 的一半。至于在其他屏幕上的转换就需要进行下一步 dimes 文件的配置了。
4 生成 dimens 文件
1. 首先在 res 目录下新建各种尺寸的 values 文件
其中 sw320dp 代表屏幕的最小宽度是320dp,下面是获取屏幕最下宽度的代码
Configuration config = getResources().getConfiguration();
int
smallestScreenWidth = config.smallestScreenWidthDp;
2. 在每个values** 目录下创建 dimens.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>
3. 先生成标准尺寸 sw380 下的dimens 文件
3.1 首先创建 java 类 GenerateDimen
package com.example.hepan.adaptation;
/**
* Created by hepan on 2018/5/25.
*/
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
public class GenerateDimen {
public static void genDimen() {
StringBuilder swdef = new StringBuilder();
PrintWriter out;
try {
swdef.append("<?xml version="1.0" encoding="utf-8"?>n" +
"<resources>");
double value;
for (int i = 0; i < 500; i++) {
//这里控制对应转换的值,如果是标准尺寸就一对一转换
value = (i + 1) * 1;
value = Math.round(value * 100) / 100;
swdef.append("<dimen name="dp" + (i + 1) + "">" + value + "dp</dimen>rn");
}
swdef.append("</resources>");
//这里是文件名,1 注意修改 sw 后面的值,和转换值一一对应
2 文件夹和文件要先创建好否则要代码创建
String filedef = "./app/src/main/res/values-sw380dp/dimens.xml";
out = new PrintWriter(new BufferedWriter(new FileWriter(filedef)));
out.println(swdef.toString());
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
public static void main(String[] args) {
genDimen();
}
}
3.2 右键运行上面的类
结果如下:
...
<dimen name="dp379">379.0dp</dimen>
<dimen name="dp380">380.0dp</dimen>
<dimen name="dp381">381.0dp</dimen>
<dimen name="dp382">382.0dp</dimen>
<dimen name="dp383">383.0dp</dimen>
<dimen name="dp384">384.0dp</dimen>
<dimen name="dp385">385.0dp</dimen>
....
3.3 同理 修改 GenerateDime 类生成 sw420 文件
for (int i = 0; i < 500; i++) {
//这里控制对应转换的值,如果是标准尺寸就一对一转换
value = (i + 1) * 420/380;
value = Math.round(value * 100) / 100;
swdef.append("<dimen name="dp" + (i + 1) + "">" + value + "dp</dimen>rn");
}
swdef.append("</resources>");
//这里是文件名,注意修改 sw 后面的值,和转换值一一对应
String filedef = "./app/src/main/res/values-sw420dp/dimens.xml";
....
<dimen name="dp380">420.0dp</dimen>
<dimen name="dp381">421.0dp</dimen>
<dimen name="dp382">422.0dp</dimen>
<dimen name="dp383">423.0dp</dimen>
<dimen name="dp384">424.0dp</dimen>
<dimen name="dp385">425.0dp</dimen>
<dimen name="dp386">426.0dp</dimen>
<dimen name="dp387">427.0dp</dimen>
<dimen name="dp388">428.0dp</dimen>
<dimen name="dp389">429.0dp</dimen>
<dimen name="dp390">431.0dp</dimen>
....
我们会发现,相对于 sw380 基准,sw420的值都会扩大 420/380 =1.10526 倍
3.4 同理我们生成其他 sw** 的文件,当设计的sw**文件越多,屏幕适配的越全面。
4 看看效果
设置如下布局,令 TextView占据宽度一半
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hepan.adaptation.MainActivity">
<!--因为基准是sw380,所以dp190代表一半-->
<TextView
android:layout_width="@dimen/dp190"
android:layout_height="30dp"
android:background="#ff0000"
android:gravity="center"
android:text="我占据了一半"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.469" />
<!--中间线,在design模式下可确认textview占一半位置-->
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</android.support.constraint.ConstraintLayout>
4.1 直接在 AndroidStudio 上查看效果
选取了如下的布局显示
分别选取了 hdpi xhdpi xxhdpi 的三个屏幕,控件都很好的占据了一半。
4.2 特殊的bug
当我选取上图对应参数 1080*1920 ,420dpi (Pixel 2)作为设计模板时出现了特殊情况
在 AndroidStudio 上显示的并不是一半,这里我们计算一下
补充知识: 基础 mdpi 对应密度是160dpi 比例是 1, hdpi 代表的密度其实是 240dpi 对应转换比例为 1.5(文章第一部分第三条)。
那么 420dpi 对应的转换比例应该是 420/160 = 2.625 也就是说 1dp=2.625px。 那么我们选取的屏幕 1080*1920px 对应的最小宽度 sw 就是 1080/2.625 = 411.2dp。 但是我们创建的文件夹并没有 values-sw411,这时系统会遵循向下兼容原则,找到比411小且最近的文件夹,也就是sw380,而sw380里面 dp190 = 190dp 比411.2/2 要小,理所当然的不会显示一半。
如何解决上述问题呢?
答案就是尽可能的多建文件夹,特别是比较集中的范围,可把间隔缩小 。这里我们再建一个 sw410 文件夹,按照上面生成dimens.xml 文件,发现 dp190 = 205dp,正好占据一半。
增加文件夹之后的效果
最后
以上就是勤劳飞机为你收集整理的利用不同 values 文件下的 dimens.xml 适配安卓屏幕的全部内容,希望文章能够帮你解决利用不同 values 文件下的 dimens.xml 适配安卓屏幕所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复