Android 屏幕适配的 "魔法尺子":dp、sp 与 px 的故事

66 阅读4分钟

一、像素王国的度量单位战争

在 Android 像素王国里,住着一群特殊的居民:px、dp、sp 和 dpi,它们每天都在为屏幕布局的事情忙碌着。

1.1 居民介绍

  • px(像素) :王国的基本居民,是屏幕上一个个真实存在的物理小点,就像画布上的格子。
  • dp(设备独立像素) :又称 dip,是王国里的 "智能尺子",能根据屏幕密度自动调整长度。
  • sp(缩放像素) :专门负责文字的 "魔法尺子",不仅能适应屏幕密度,还能随用户字体设置变化。
  • dpi(像素密度) :每英寸的像素数量,相当于屏幕的 "拥挤程度",dpi 越高屏幕越清晰。
  • 分辨率:屏幕横纵方向的像素数,如 1920*1080,相当于画布的格子总数。
  • 屏幕尺寸:屏幕对角线长度,单位英寸,相当于画布的实际大小。

1.2 尺子的魔法公式

像素王国的魔法师们发明了一套换算公式,让不同尺子之间可以互相转换:

java

// Android中的魔法换算工具
public class PixelMagic {
    // dp转px的魔法咒语
    public static int dp2px(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
    
    // sp转px的魔法咒语
    public static int sp2px(Context context, float spValue) {
        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }
    
    // 计算dpi的魔法公式
    public static float calculateDpi(int widthPx, int heightPx, float screenSize) {
        double diagonalPx = Math.sqrt(widthPx * widthPx + heightPx * heightPx);
        return (float) (diagonalPx / screenSize);
    }
}

二、屏幕密度的奇幻世界

像素王国有不同密度的区域,每个区域的 dpi 不同,就像不同城市的建筑密度:

区域等级dpi(像素 / 英寸)密度比例 (scale)代表性分辨率
ldpi1200.75320*240
mdpi160 (基准)1.0480*320
hdpi2401.5800*480
xhdpi3202.01280*720
xxhdpi4803.01920*1080
xxxhdpi6404.02560*1440

2.1 密度比例的秘密

密度比例 (scale) 是相对于基准 mdpi (160dpi) 的倍数,就像不同城市的比例尺:

  • 在 mdpi (160dpi) 的城市,1dp = 1px(1 把 dp 尺子 = 1 个 px 格子)

  • 在 xhdpi (320dpi) 的城市,1dp = 2px(dp 尺子自动伸长为 2 个 px 格子)

  • 在 xxhdpi (480dpi) 的城市,1dp = 3px(dp 尺子变成 3 个 px 格子)

java

// 查看当前设备的密度比例
DisplayMetrics metrics = getResources().getDisplayMetrics();
Log.d("PixelWorld", "dpi: " + metrics.densityDpi);
Log.d("PixelWorld", "scale: " + metrics.density);
// 输出示例:xhdpi设备 -> dpi: 320, scale: 2.0

2.2 1dp 的真实长度

在 dpi=320 的设备上:

  • 320px = 1 英寸 → 1px = 1/320 英寸

  • 1dp = (320/160) px = 2px → 1dp = 2*(1/320) 英寸 = 1/160 英寸

结论:无论设备 dpi 如何,1dp 大约等于 1/160 英寸,这就是 dp 作为设备独立单位的秘密!

三、UI 设计师的装修指南

3.1 布局装修的最佳实践

xml

<!-- 推荐的布局文件写法 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"  <!-- 自适应宽度 -->
    android:layout_height="wrap_content" <!-- 自适应高度 -->
    android:padding="16dp"              <!-- 使用dp作为间距单位 -->
    android:orientation="vertical">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textSize="18sp"             <!-- 使用sp作为文字单位 -->
        android:gravity="center"/>
        
    <ImageView
        android:layout_width="50dp"         <!-- 使用dp作为图片宽度 -->
        android:layout_height="50dp"        <!-- 使用dp作为图片高度 -->
        android:src="@drawable/ic_launcher"
        android:scaleType="centerCrop"/>
</LinearLayout>

3.2 代码中的像素魔法禁忌

java

// 错误示范:硬编码px值
// btn.setLayoutParams(new LinearLayout.LayoutParams(200, 80));

// 正确做法:使用dp转px
int dp200 = PixelMagic.dp2px(this, 200);
int dp80 = PixelMagic.dp2px(this, 80);
btn.setLayoutParams(new LinearLayout.LayoutParams(dp200, dp80));

// 更优做法:使用Dimension资源
int width = getResources().getDimensionPixelSize(R.dimen.btn_width);
int height = getResources().getDimensionPixelSize(R.dimen.btn_height);
btn.setLayoutParams(new LinearLayout.LayoutParams(width, height));

3.3 图片资源的魔法适配

像素王国的设计师们会为不同密度的城市准备不同的图片:

  • mdpi 城市:放在 drawable-mdpi 文件夹

  • hdpi 城市:放在 drawable-hdpi 文件夹

  • xhdpi 城市:放在 drawable-xhdpi 文件夹

plaintext

res/
├── drawable-mdpi/
│   └── icon.png    // 1x 图片
├── drawable-hdpi/
│   └── icon.png    // 1.5x 图片
├── drawable-xhdpi/
│   └── icon.png    // 2x 图片
└── drawable-xxhdpi/
    └── icon.png    // 3x 图片

四、屏幕侦探的市场调查

像素王国的探险家们会通过以下工具调查不同屏幕的分布:

java

// 获取当前设备的屏幕信息
DisplayMetrics metrics = getResources().getDisplayMetrics();
Log.d("ScreenInfo", "Width: " + metrics.widthPixels + "px");
Log.d("ScreenInfo", "Height: " + metrics.heightPixels + "px");
Log.d("ScreenInfo", "Density: " + metrics.density);
Log.d("ScreenInfo", "DensityDpi: " + metrics.densityDpi);
Log.d("ScreenInfo", "ScaledDensity: " + metrics.scaledDensity);

五、魔法口诀总结

  • px:真实像素点,硬件物理单位

  • dp:智能尺子,= dpi/160 * px,适配屏幕密度

  • sp:文字专用尺子,= dp * 字体缩放系数,适配字体设置

  • 适配口诀

    plaintext

    布局请用dp/sp,代码别写死px;
    图片分密度放置,.9.png是神器;
    百分比布局好,多尺寸layout要;
    市场数据参考,适配更精准妙。
    

通过这些魔法工具和技巧,Android 开发者可以在不同密度的屏幕上构建出一致、美观的用户界面,让像素王国的居民们在各种设备上都能舒适生活。