Androidの画面が合うのは面倒ですか?いや!簡単すぎます...(継続更新)

9423 ワード

転載は出典を明らかにしてください:juejin.im/post/5b3094…
前言
Android開発者として、さまざまなサイズのスクリーンに合わせることに悩んでいますか?あなたはまだ新しい機種を出すために数え切れないdimensとlayoutを修正していますか?UIが与える奇抜なサイズのデザイン図のために乳汁を絞って距離を計算していますか?もしあなたがこれらのことで悩んでいるなら、この文章を読んで、開発時間を減らして、生命の流れを遅らせることができることを望んでいます.の先日、今日トップテクノロジーチームが発表したAndroidスクリーンの適合に関する記事を見たことがありますか.極めて低コストのAndroidスクリーンの適合方式です.見たことのない友達はまず見て理解してから帰ってきて、もっとよく理解することができます.私は何気なくこの文章を注文したのですが、见た后に目の前が明るくなりました------Alndroidスクリーンが似合うのが本当にこんなに简単なら、苦労して日夜适合していない先辈たちは死んでしまったのではないでしょうか....
テストと思考
今日の頭条の大神たちの考えは本当にユニークで、コストが極めて安くて、とても使いやすいと言わざるを得ません.彼らが提示した最終案はこうです.
private static float sRoncompatDennsity;
private static float sRoncompatScaledDensity;
private void setCustomDensity(@NonNull Activity activity, final @NonNull Application application) {

    //application
    final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();

    if (sRoncompatDennsity == 0) {
        sRoncompatDennsity = appDisplayMetrics.density;
        sRoncompatScaledDensity = appDisplayMetrics.scaledDensity;
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                if (newConfig != null && newConfig.fontScale > 0) {
                    sRoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                }
            }

            @Override
            public void onLowMemory() {

            }
        });
    }

    //    360dp         640dp       
    final float targetDensity = appDisplayMetrics.widthPixels / 360;
    final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity / sRoncompatDennsity);
    final int targetDensityDpi = (int) (targetDensity * 160);

    appDisplayMetrics.density = targetDensity;
    appDisplayMetrics.densityDpi = targetDensityDpi;
    appDisplayMetrics.scaledDensity = targetScaledDensity;

    //activity
    final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();

    activityDisplayMetrics.density = targetDensity;
    activityDisplayMetrics.densityDpi = targetDensityDpi;
    activityDisplayMetrics.scaledDensity = targetScaledDensity;
}

この文章を見て、私は急いでdemoテストを書いて、小さな問題を見つけました.UIが提供する設計図のサイズは1334*720で、もし私が幅を適合基準とするならば、xhdpi 1 dp=2 pxの図に従って参照して、設計図幅720 pxの、スクリーンの幅は360 dpで、つまりこのようにします:
final float targetDensity = appDisplayMetrics.widthPixels / 360;

このようにすると幅が合う割合は何の問題もありませんが、あるページが高さで合う必要がある(つまり、内容が縦に全画面を埋めている)場合は、このように変更すればいいのではないかと思っています.
final float targetDensity = appDisplayMetrics.heightPixels / 667;

しかし、実行後、高さの差が大きく、解像度やサイズの異なる携帯電話で動作していることがわかり、ページの各部分の内容の縦方向の割合が異なり、適切な効果は得られなかった.長い間考えていた後、私の手元のテスト機の幅は2つの720と2つの1080で、高さは128014401780と1つの全面的なスクリーンの2160です.Androidの開原性はAndroidデバイスのサイズの断片化を招きすぎますが、テスターのサイズパラメータを見ると、この4つの携帯電話でテストすれば幅は直接削除できますが、高さはできません(しかも私の手元のテスターの幅も削除できますが、幅が削除できない携帯電話があれば?)しかし、今日のトップ記事で与えられた方法では、除算をした後に結果が整うのですが、縦で計算したdensityで整頓したことが精度に影響し、効果が不十分になったのではないでしょうか.
問題の修正
上記の問題を発見した後、私は修正に着手して、計算結果を余剰に取ってからtargetDesityに値を割り当てて、繰り返しのテストと実験を経て、私はtargetDesityの計算方法を再修正しました:
float targetDensity = 0;
try {
    Double division = Operation.division(appDisplayMetrics.heightPixels, 667);
    //           ,          ,    ,                       
    DecimalFormat df = new DecimalFormat("0.00");
    String s = df.format(division);
    targetDensity = Float.parseFloat(s);
} catch (NumberFormatException e) {
    e.printStackTrace();
}

しかし、热心なネットユーザーから、システムの言叶をポルトガル语に変更すると异常を报告すると、ページはまったく见るに堪えないという伝言がありました.の外国の歴史の友人に対する疑問を抱いてテストを続けたところ、このような問題を発見しました.
よく見て!!!小数点はなんと中国語のカンマ(現在発見されている言語の中で、ポルトガル語とインドネシア語はこのようにして、他の言語はテストされていません)!!!仕方なく、修正を続けるしかありません.その後、この熱心なネットユーザーの注意を得て、私はこのコードを修正しました.
float targetDensity = appDisplayMetrics.heightPixels / 667f;

これで全く問題なく、小数点を2桁残す必要もなくなりました(問題を発見した皆さん、学芸が下手であることを許してください...この熱心なネットユーザーの指摘にも感謝します)
テストを続けたところ、高度な適合結果が非常に満足していることが分かった.しかし、もう一つの問題は、私たちが一般的に適切にするのは携帯電話の幅を基準にしていますが、1つのappの中でたまに1、2つのページが高さを基準にして(つまり、コンテンツが縦に全画面に埋め込まれているページ)適切に配置されることは避けられません.しかし、上記の方法は一つの方向しか保証できないので、適当な基準方向を自由に切り替えることができればいいのではないでしょうか.
最終シナリオ
修正を続行した後、最終的なシナリオを得ました.修正した後、このクラスのすべての内容は以下の通りです.
private static float appDensity;
private static float appScaledDensity;
private static DisplayMetrics appDisplayMetrics;
private static int barHeight;

public static void setDensity(@NonNull Application application) {
    //  application DisplayMetrics
    appDisplayMetrics = application.getResources().getDisplayMetrics();
    //       
    barHeight = AppUtils.getStatusBarHeight(application);

    if (appDensity == 0) {
        //        
        appDensity = appDisplayMetrics.density;
        appScaledDensity = appDisplayMetrics.scaledDensity;

        //         
        application.registerComponentCallbacks(new ComponentCallbacks() {
            @Override
            public void onConfigurationChanged(Configuration newConfig) {
                //     , appScaledDensity    
                if (newConfig != null && newConfig.fontScale > 0) {
                    appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                }
            }

            @Override
            public void onLowMemory() {
            }
        });
    }
}

//    BaseActivity     (     BaseActivity  ,            )
public static void setDefault(Activity activity) {
    setAppOrientation(activity, AppUtils.WIDTH);
}

//         Activity         
public static void setOrientation(Activity activity, String orientation) {
    setAppOrientation(activity, orientation);
}

/**
 * targetDensity
 * targetScaledDensity
 * targetDensityDpi
 *               
 * 

* orientation: , width height */ private static void setAppOrientation(@Nullable Activity activity, String orientation) { float targetDensity; if (orientation.equals("height")) { targetDensity = (appDisplayMetrics.heightPixels - barHeight) / 667f; } else { targetDensity = appDisplayMetrics.widthPixels / 360f; } float targetScaledDensity = targetDensity * (appScaledDensity / appDensity); int targetDensityDpi = (int) (160 * targetDensity); /** * * * * Activity density */ DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.scaledDensity = targetScaledDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; }


このクラスの初期化方法では、デフォルトで幅を基準としています(これはActivityで設定された方法で、このActivityの下に存在するfragment、dialog、PopupWindowともにこの効果の影響を受けます.つまり、Activityで1回設定した後、Activityの下にある他のサブViewはもう1回設定する必要はありません).
使用方法
自分でクラスを作って、最終案のコードをコピーして貼り付けて使えます.
使用方法:アプリケーションのonCreate()メソッド:BaseActivity:
1つの方向を合わせるだけなら、この2つだけを設定すればいいです(utilsでは幅に合わせてデフォルトを設定していますが、自分のニーズに合わせてデフォルトの方向を変更することができます.下図を参照してください)
appに縦方向の適合が必要なページがある場合:
/**
 *
 *        ,       onCreate()  setContentView()    ,           
 */
@Override
public void setOrientation() {
    Density.setOrientation(this, AppUtils.HEIGHT);
}

最后に适切な効果図を贴り付けます(色はただ见るための直感的な点..)
横:縦:
黒板を叩く!!!
この方法では、dimensファイルが1つ、layoutファイルが1つで十分です.xmlレイアウトではdpだけでいいです(Android Pの劉海屏は単独でlayoutに適している必要があります)
締めくくり
自分で書いたdemoなので、まだ大面積のテストはありませんが、もし皆さんが条件の広い範囲のテストがあれば、どんな問題があったら私にフィードバックして、私たちは一緒にどのように修正して、一緒に進歩するかを議論することができます.これは私が入行してから書いた最初の文章で、書くのが悪いところがあれば指摘を歓迎して、これからも努力して多くの文章を書くことができて、良いものは分かち合う必要があります.
ここはgithubアドレスで、demoの中にはBaseRecyclerViewAdapterHelperとQMUIの使い方もあります
連絡先を残して、連絡しやすいQQ:850701071
この文章があなたの役に立つなら、好きなものを注文してから行きましょう.
転載先:https://juejin.im/post/5b3094fc6fb9a00e52398ae4