dimen适配在原生安卓开发中,仍然是兼容性最高的适配方案
核心就是 以你设计图最初的,比例换算成其他屏幕比例
简述原理
我们安装好ScreenMatch插件后,base_dp就是你设计图上的屏幕比如,比如48dp,在1080上面就是dimen,这里的533 是800屏幕hdpi的值 这里不发散基础使用了
screenMatch.properties
base_dp=1080
match_dp=533,800,1080
那么我们会得到
values-sw800dp/dimens.xml <dimen name="dp_48">48.0000dp</dimen>
values-sw1080dp/dimens.xml <dimen name="dp_48">48.0000dp</dimen>
values/dimens.xml <dimen name="dp_48">48.0000dp</dimen>
新项目就还好直接使用,不同屏幕就会去匹配不同的dimen,但如果是老项目呢?是不是还要全局改xdp —> @dimen/dp_x之类的东西
XML
<TextView
android:id="@+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_48"
android:layout_marginTop="@dimen/dp_45"
android:lineSpacingExtra="@dimen/dp_4"
android:textColor="@color/white"
android:textSize="@dimen/dp_48"
tools:text="2025 年 1 月 2 日 14:30" />
XML
<TextView
android:id="@+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginTop="45dp"
android:lineSpacingExtra="4dp"
android:textColor="@color/white"
android:textSize="48sp"
tools:text="2025 年 1 月 2 日 14:30" />
解决痛点
你就还差一步全局替换
xdp ---> @dimen/dp_x
xsp ---> @dimen/dp_x (统一用dp更好维护)
缺失未定义的 dimen 得去加上values /dimen 里面加上 重新adapter
这就是属于纯苦力活了,既然是重复劳动力 则我这里分享一个脚本,放到项目根目录(screenMatch.properties同级)
执行即可

脚本分享
python
#!/usr/bin/env python3
"""
批量将 layout XML 中的硬编码 dp/sp 值替换为 @dimen/ 引用
并自动补充缺失的 dimen 条目到 values/dimens.xml
运行后需重新执行 screenMatch 插件生成各分辨率的 dimens 文件
"""
import re
import os
from collections import OrderedDict
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
LAYOUT_DIR = os.path.join(PROJECT_DIR, "app", "src", "main", "res", "layout")
DIMENS_FILE = os.path.join(PROJECT_DIR, "app", "src", "main", "res", "values", "dimens.xml")
HARDCODED_PATTERN = re.compile(r'="(\d+\.?\d*)(dp|sp)"')
def num_to_dimen_name(num_str, unit):
clean = num_str.replace('.', '_')
return f"{unit}_{clean}"
def scan_file(filepath):
found = OrderedDict()
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
for match in HARDCODED_PATTERN.finditer(content):
num_str, unit = match.group(1), match.group(2)
dimen_name = num_to_dimen_name(num_str, unit)
val = float(num_str)
original = f"{int(val)}{unit}" if val == int(val) else f"{num_str}{unit}"
found[dimen_name] = original
return found
def replace_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
def replacer(match):
num_str, unit = match.group(1), match.group(2)
dimen_name = num_to_dimen_name(num_str, unit)
return f'="@dimen/{dimen_name}"'
new_content = HARDCODED_PATTERN.sub(replacer, content)
if new_content != content:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(new_content)
return True
return False
def parse_existing_dimens(filepath):
existing = set()
with open(filepath, 'r', encoding='utf-8') as f:
for line in f:
m = re.match(r'\s*<dimen name="([^"]+)">', line)
if m:
existing.add(m.group(1))
return existing
def add_missing_dimens(filepath, missing):
if not missing:
return
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
dp_items = sorted(
[(k, v) for k, v in missing.items() if k.startswith('dp_')],
key=lambda x: float(x[0].replace('dp_', '').replace('_', '.'))
)
sp_items = sorted(
[(k, v) for k, v in missing.items() if k.startswith('sp_')],
key=lambda x: float(x[0].replace('sp_', '').replace('_', '.'))
)
lines = []
for name, val in dp_items:
lines.append(f' <dimen name="{name}">{val}</dimen>')
if dp_items and sp_items:
lines.append('')
for name, val in sp_items:
lines.append(f' <dimen name="{name}">{val}</dimen>')
insert_str = '\n'.join(lines) + '\n'
content = content.replace('</resources>', insert_str + '\n</resources>')
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
def main():
all_dimens = OrderedDict()
xml_files = [f for f in os.listdir(LAYOUT_DIR) if f.endswith('.xml')]
modified_count = 0
print("=" * 50)
print(" 扫描 layout XML 中的硬编码 dp/sp 值")
print("=" * 50)
for xml_file in sorted(xml_files):
filepath = os.path.join(LAYOUT_DIR, xml_file)
found = scan_file(filepath)
if found:
print(f" {xml_file}: 发现 {len(found)} 个硬编码值")
for name, val in found.items():
all_dimens[name] = val
print(f"\n共发现 {len(all_dimens)} 个不同的 dimen 值")
print("\n" + "=" * 50)
print(" 替换为 @dimen/ 引用")
print("=" * 50)
for xml_file in sorted(xml_files):
filepath = os.path.join(LAYOUT_DIR, xml_file)
if replace_file(filepath):
modified_count += 1
print(f" ✓ {xml_file}")
print(f"\n共修改 {modified_count} 个文件")
print("\n" + "=" * 50)
print(" 检查 dimens.xml 缺失条目")
print("=" * 50)
existing = parse_existing_dimens(DIMENS_FILE)
missing = OrderedDict()
for name, val in all_dimens.items():
if name not in existing:
missing[name] = val
if missing:
print(f" 发现 {len(missing)} 个缺失的 dimen:")
for name, val in missing.items():
print(f" {name} -> {val}")
add_missing_dimens(DIMENS_FILE, missing)
print(" ✓ 已补充到 dimens.xml")
else:
print(" 所有 dimen 值已存在,无需补充")
print("\n" + "=" * 50)
print(" 完成!")
print("=" * 50)
print(" ⚠ 请重新运行 screenMatch 插件生成各分辨率 dimens 文件")
if __name__ == '__main__':
main()