Andorid の画面適応
この記事へのリンク: https://blog.csdn.net/feather_wch/article/details/131672378
参考記事:Android適応概要
1. dpiとは何ですか?
- 画面のピクセル密度
- 1インチあたり160ピクセル、160dpi
- dpi = ピクセル/インチ
2. dpとpxの変換
- px = dp * (dpi / 160)
- 密度: dpi / 160
3. 適応戦略 (幅の割合、高さのアスペクト比)
- コントロールの幅は UI デザインのサイズに応じて決まります
- コントロールの高さはプルーフのパーセンテージに従って計算されます
Toutiao適応ソリューション
1. dp にパーセント効果を持たせる
- px = dp * 密度
- 密度の変更 (DisplayMetrics に保存)
- アクティビティが開始したら、関連するアダプテーション メソッドを呼び出し、アクティビティとアプリケーションを渡します (2 つの DisplayMetrics が異なる場合に対処するため)。
- 非常に軽量
2. DisplayMetrics の重要なプロパティとメソッドは何ですか?
- widthPixels : 表示デバイスの幅 (ピクセル単位)。
- heightPixels : デバイスの高さをピクセル単位で表示します。
- density : デバイスの論理密度を表示します。これは、1 インチあたりのドット数 (dpi) を 160 で割った比率です。
- densityDpi : デバイスの物理密度をインチあたりのドット数 (dpi) で表示します。
- scaledDensity : テキストのスケーリングに使用されるデバイスのスケーリング密度を表示します。ユーザーがフォント サイズを変更しない限り、通常は密度と同じです。
3. 濃度を再計算する必要があるため、プルーフは360dpを標準とします
- 密度、densityDpi、scaledDensityを計算する
- DisplayMetrics セットをアプリケーションとアクティビティに割り当てます
公式:px = dp * density, density = px / dp
新density = DisplayMetrics.widthPixels / 360
公式:density = dpi / 160,dpi = density * 160
新densityDpi = 160 * 新density
// 设置DisplayMetrics
displayDensity.density = 新density
displayDensity.densityDpi = 新densityDpi
4. フォントのスケーリングに大きすぎる、または小さすぎるという問題があります。どのように対処すればよいですか? スケーリングされた密度
- scaledDensity は、同じ比率に従って密度密度をスケーリングする必要があります
- システムがフォント サイズを変更すると、インターフェイスがトリガーされ、インターフェイスのトリガー後にフォントのscaledDensity を再計算する必要があります。
割合スキーム
5. 割合スキームはどのように実現されますか?
- XML ファイルを計算して生成します。異なる解像度の異なる XML ファイルを生成します。
- dp、px は、内部で変換される x1、y1 などのパラメータを使用します。
DisplayMetrics のソース コード
1. DisplayMetrics はいつ設定されますか?
- DisplayMetrics はWindowManagerServiceクラスで設定されます。
【SystemServer.java】
private void startOtherServices() {
final Context context = mSystemContext;
WindowManagerService wm = null;
InputManagerService inputManager = null;
...
//创建WindowManagerService对象
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
//添加到服务管理器
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
...
//调用displayReady方法
wm.displayReady();
...
}
【WMS】
public void displayReady() {
synchronized (mWindowMap) {
//初始化显示设备
for (Display display : mDisplays) {
DisplayContent displayContent = mRoot.getDisplayContentOrCreate(display.getDisplayId());
//配置显示策略
configureDisplayPolicyLocked(displayContent);
//设置布局标志
displayContent.layoutNeeded = true;
//更新方向
boolean configChanged = updateOrientationFromAppTokensLocked(false);
//设置临时配置
mTempConfiguration.setToDefaults();
mTempConfiguration.fontScale = 1;
//更新资源配置
if (configChanged) {
mWaitingForConfig = true;
startFreezingDisplayLocked(false, 0, 0, displayContent);
//发送配置变化广播
sendNewConfiguration(display.getDisplayId());
}
}
//初始化输入设备
mInputMonitor.setUpdateInputWindowsNeededLw();
performLayoutAndPlaceSurfacesLocked();
mInputMonitor.updateInputWindowsLw(false /*force*/);
}
}
【PhoneWindowManager】- WindowManagerPolicy的实现类
private void configureDisplayPolicyLocked(DisplayContent displayContent) {
//设置显示设备的初始尺寸和密度
mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight,
displayContent.mBaseDisplayDensity);
//设置显示设备的overscan区域
DisplayInfo displayInfo = displayContent.getDisplayInfo();
mPolicy.setDisplayOverscan(displayContent.getDisplay(),
displayInfo.overscanLeft, displayInfo.overscanTop,
displayInfo.overscanRight, displayInfo.overscanBottom);
}
【PhoneWindowManager】- WindowManagerPolicy的实现类
public void setInitialDisplaySize(Display display, int width, int height, int density) {
if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
synchronized (mLock) {
//初始化真实屏幕大小
mOverscanScreenWidth = mOverscanScreenHeight = 0;
mUnrestrictedScreenWidth = width;
mUnrestrictedScreenHeight = height;
//初始化DisplayMetrics
mDisplayWidth = width;
mDisplayHeight = height;
mDisplayDensity = density;
mSystemGestures.screenWidth = width;
mSystemGestures.screenHeight = height;
}
//更新显示区域
updateOrientationListenerLp();
updateRotation(true);
}
}