Android 2.3.5デバイスはNORMAL/HDPIです。プロジェクトにdimens.xmlがあります:
...
<dimen name="gameresult_congrats_label_msg_textSize">20sp</dimen>
...
このファイルは、values-normal/values-hdpiなどのフォルダーでまったく同じです。私の最初のアクティビティアプリでは、以下を使用してその値を示しています。
Toast.makeText(this, "textSize is "+getResources().getDimensionPixelSize(R.dimen.gameresult_congrats_label_msg_textSize), Toast.LENGTH_SHORT).show();
そして、それは30を表示します。私も試してみました:
Toast.makeText(this, "textSize is "+getResources().getDimension(R.dimen.gameresult_congrats_label_msg_textSize), Toast.LENGTH_SHORT).show();
結果は同じです。しかし、私がこれを試したときだけ:
Toast.makeText(this, "textSize is "+getResources().getString(R.dimen.gameresult_congrats_label_msg_textSize), Toast.LENGTH_SHORT).show();
いよいよ「20sp」を手に入れました!しかし、それはなぜですか? 公式ドキュメントには、これらのメソッドと記載されている が返される
リソースディメンションの値に適切な指標を掛けた値。
私は自分の値を25に変更してこれをチェックし、38を得ました。これは、aosが1.5乗数を使用することを意味します。しかし、なぜ?すでに適切なフォルダから値を取得しているため、すぐに使用できる値を取得できます。 aosは1.5倍の乗数をどこから得るのですか? DisplayMetricsに依存することは知っています。しかし、それはどのように1.5xを計算しますか?
[〜#〜]更新[〜#〜]
私は乗数について理解していますが、ご覧のとおり、ここでの本当の問題は二重スケーリングについてです。そして、それが私がこの質問をした理由です。
したがって、次のように定義されたTexViewを含む(res\layoutフォルダーに)layout.xmlがある場合:
<TextView
Android:id="@+id/congratsLabel"
...
Android:textSize="@dimen/gameresult_congrats_label_msg_textSize" />
すべて問題ありません。つまり、textviewはImが期待しているようなものです。
今度はコードで同じことをしましょう:
TextView congratsLabel = fineViewById(R.id.congratsLabel);
textSize = getResources().getDimension(R.dimen.gameresult_congrats_label_msg_textSize)
congratsLabel.setTextSize(textSize)
そしてここに問題があります!!! getResources()。getDimension()は[〜#〜] scaled [〜#〜]値を返し、問題ありません。しかし、私のtextViewの結果のサイズは、予想される値より1.5大きくなります。setTextSizeはSPで動作し、2番目のスケールがここに来ます!そして、そのためAOSは結果のテキストサイズを45にスケーリングします(元は次のように定義されています) 20 sp)。
サポートするさまざまな画面密度のトレーニング に従って、hdpiは1.5倍の通常(mdpi)サイズです。 getDimensionPixelSize
はピクセルに変換するときにこの違いを考慮するため、戻り値はsp
の値の1.5倍になります。
sp
はユーザーの優先テキストサイズにも依存するため、期待値の1.5倍よりも大きくなる可能性があることに注意してください。
明確にするために(Androidソースコードを検査して得られた情報):
Resources.getDimension()
とgetDimensionPixelOffset()
/getDimensionPixelSize()
は、前者がfloat
を返し、後者の2つはint
適切に。それらすべての場合、戻り値は生のピクセル単位です。
3つの関数はすべてResources.getValue()
を呼び出して実装し、こうして取得したTypedValue
をTypedValue.complexToDimension()
、TypedValue.complexToDimensionPixelOffset()
およびTypedValue.complexToDimensionPixelSize()
を呼び出して変換します。 、それぞれ。
したがって、XMLソースで指定された単位とともに「未加工」値を取得する場合は、Resources.getValue()
を呼び出し、TypedValue
クラスのメソッドを使用します。
メソッドgetDimension()は、現在の画面密度に基づいて、dpまたはsp値をピクセルに変換します。 Java幅またはテキストサイズ(ピクセルのみを受け入れる)で設定する場合、これを自分で行う必要がないため、これは非常に便利です。
ただし、元のspまたはdpが必要な場合は、「リバースエンジニアリング」を実行できます。
ステップ1.現在の倍率(画面密度に基づく)を確認します:
float scaleRatio = getResources().getDisplayMetrics().density;
ステップ2. dimens.xmlからディメンションを取得します
float dimenPix = getResources().getDimension(R.dimen.your_dimen_name);
ステップ3.いくつかの計算を行います
float dimenOrginal = dimenPix/scaleRatio;
備考:
Androidのディメンションの詳細: http://Android4beginners.com/2013/07/appendix-c-everything-about-sizes-and-dimensions-in-Android/
他の誰かがこれを必要とする場合:
TextView.setTextSizeでgetDimensionPixelSizeを使用するときにStanが示す二重スケーリングの問題に対処するには:
次のように単位を指定できるsetTextSizeの代替バージョンを使用できます。
title.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.title));
なぜなら... NORMALはhdpiではないからです...
通常はmdpi(160dpi)= 1.0xです。
hdpi(240dpi)は1.5倍です。
xhdpi(320dpi)は2.0xです。
xxdpi(480dpi)は3.0xです。
xxxhdpi(640dpi)は4.0xです。
そして(最後ですが、重要なことですが)ldpi(120dpi)は0.75xです。