web-dev-qa-db-ja.com

getDimension()/ getDimensionPixelSize()-乗数の問題

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)。

14
Stan

サポートするさまざまな画面密度のトレーニング に従って、hdpiは1.5倍の通常(mdpi)サイズです。 getDimensionPixelSizeはピクセルに変換するときにこの違いを考慮するため、戻り値はspの値の1.5倍になります。

spはユーザーの優先テキストサイズにも依存するため、期待値の1.5倍よりも大きくなる可能性があることに注意してください。

14
ianhanniballake

明確にするために(Androidソースコードを検査して得られた情報):

Resources.getDimension()getDimensionPixelOffset()/getDimensionPixelSize()は、前者がfloatを返し、後者の2つはint適切に。それらすべての場合、戻り値は生のピクセル単位です。

3つの関数はすべてResources.getValue()を呼び出して実装し、こうして取得したTypedValueTypedValue.complexToDimension()TypedValue.complexToDimensionPixelOffset()およびTypedValue.complexToDimensionPixelSize()を呼び出して変換します。 、それぞれ。

したがって、XMLソースで指定された単位とともに「未加工」値を取得する場合は、Resources.getValue()を呼び出し、TypedValueクラスのメソッドを使用します。

24
Jaromír Adamec

メソッド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;

備考:

  • 通常、次元メソッド(setWidth()など)にはintが必要なので、たとえばMath.round()を使用して、floatの結果をintに変換する必要があります。
  • intに丸めると、より正確な結果が得られます(dimenPix-0.5f)/ scaleRatio
  • spの場合、テキストスケールに関するユーザー設定も考慮することができます。

Androidのディメンションの詳細: http://Android4beginners.com/2013/07/appendix-c-everything-about-sizes-and-dimensions-in-Android/

15

他の誰かがこれを必要とする場合:

TextView.setTextSizeでgetDimensionPixelSizeを使用するときにStanが示す二重スケーリングの問題に対処するには:

次のように単位を指定できるsetTextSizeの代替バージョンを使用できます。

title.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.title));
6
Antoine

なぜなら... 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です。

1
Phantômaxx