Androidの画面適応スキーム

画面適応スキーム
転載元:https://www.jianshu.com/p/1302ad5a4b04

はじめに
昨年書いた記事[Androidの非常に使いやすい画面適応]にはフォントサイズの適応が含まれていましたが、その記事ではさまざまな画面サイズに応じてフォントサイズを適応させることについて説明しました。次に話したいです。フォントサイズには他にもいくつかのシナリオがあります。適応。

シナリオ1に
は、インターフェイスにタイトルテキストを表示する必要があるという要件がありますが、タイトルテキストの長さは固定されていません。タイトルのすべてのテキストを表示する必要があります。省略記号を付けて表示することはできません。タイトルの幅と高さは固定されています。たとえば、タイトルのコピーは、次の図に示すように、「これはタイトルであり、タイトルの名前は比較的長く、製品要件は折り返されずに表示されます」です。最初のタイトルは、満たされないタイトルです。要件、2番目は要件を満たすタイトルです。

つまり、TextViewコントロールの幅と高さを固定する必要があります。その後、フォントサイズは、上図の2番目のタイトルの効果であるタイトルのコピーの長さに応じて動的に変更されます。それはどのように達成されますか?

以前のアプローチは、通常、TextViewテキストの幅とTextViewコントロールの幅を測定し、TextViewのフォントサイズを動的に変更することです。これを書くのは面倒でパフォーマンスが高くなります。しかし、今はそれほど面倒なことはありません。Android8.0には、TextViewのフォントサイズを動的に変更するために使用される新機能のAutosizingTextViewsが追加されています。必要なのはプロパティを設定するだけです。

たとえば、上の図の要件を満たす効果は、次のように記述できます。

xmlの方法

<?xml version = "1.0" encoding = "utf-8"?>

<TextView
    android:layout_width="340dp"
    android:layout_height="50dp"
    android:background="@drawable/shape_bg_008577"
    android:gravity="center_vertical"
    android:maxLines="1"
    android:text="这是标题,该标题的名字比较长,产品要求不换行全部显示出来"
    android:textSize="18sp"
    android:autoSizeTextType="uniform"
    android:autoSizeMaxTextSize="18sp"
    android:autoSizeMinTextSize="10sp"
    android:autoSizeStepGranularity="1sp"/>
TextViewコントロールには次の属性があることがわかります。

autoSizeTextType:TextViewが自動フォントサイズ変更をサポートするかどうかを設定します。noneはサポートしないことを意味し、uniformはサポートすることを意味します。
autoSizeMinTextSize:たとえば、最小フォントサイズは10spに設定されています。これは、テキストを最大で10spにしか縮小できないことを意味します。
autoSizeMaxTextSize:たとえば、最大フォントサイズは18spに設定されています。これは、テキストを18spにしか拡大できないことを意味します。
autoSizeStepGranularity:ズームの粒度、つまり各フォントサイズの値が変化します。たとえば、1spに設定されている場合、各縮小または拡大の値は1spであることを意味します。
上記は8.0デバイスにのみ有効です。8.0未満のデバイスと互換性を持たせるには、TextViewの代わりにAppCompatTextViewを使用する必要があり、上記の属性の名前空間はapp名前空間を使用する必要があります。次のように:

<?xml version = "1.0" encoding = "utf-8"?>

<android.support.v7.widget.AppCompatTextView
    android:layout_width="340dp"
    android:layout_height="50dp"
    android:background="@drawable/shape_bg_008577"
    android:gravity="center_vertical"
    android:maxLines="1"
    android:text="这是标题,该标题的名字比较长,产品要求不换行全部显示出来"
    android:textSize="18sp"
    app:autoSizeTextType="uniform"
    app:autoSizeMaxTextSize="18sp"
    app:autoSizeMinTextSize="10sp"
    app:autoSizeStepGranularity="1sp"/>
確かに多くの人が「自分で書いたときにAppCompatTextViewを使用して8.0未満のデバイスと互換性を持たせられないのはなぜですか?」と言います。これは、現在のxmlファイルに対応するアクティビティがAppCompatActivityを継承するためです。ActivityまたはFragmentActivityを継承する場合、互換性はありません達成されました。実際、公式文書のAutosizing TextViewsはそれを明確にしておらず、多くの人が誤解を招きました。自分で確認することができます。

動的コーディングメソッド
TextViewCompatのsetAutoSizeTextTypeWithDefaults()メソッドを使用して、TextViewが自動フォントサイズ変更をサポートするかどうかを設定し、setAutoSizeTextTypeUniformWithConfiguration()メソッドを使用して、最小フォントサイズ、最大フォントサイズ、およびズーム粒度を設定します。次のように:

    TextView tvText = findViewById(R.id.tv_text);
    TextViewCompat.setAutoSizeTextTypeWithDefaults(tvText,TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM);
    TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(tvText,10,18,1, TypedValue.COMPLEX_UNIT_SP);

setAutoSizeTextTypeWithDefaults()の
パラメーター1は、フォントサイズを動的に変更する必要があるTextViewであり、パラメーター2は、フォントサイズを自動的に変更するタイプをサポートするかどうかです。AUTO_SIZE_TEXT_TYPE_UNIFORMはサポートを意味し、AUTO_SIZE_TEXT_TYPE_NONEはサポートしないことを意味します。
setAutoSizeTextTypeUniformWithConfiguration()
パラメーター1は、フォントサイズを動的に変更する必要があるTextViewであり、パラメーター2、3、および4は、それぞれ最小フォントサイズ、最大フォントサイズ、およびスケーリング粒度であり、パラメーター5はパラメーター2、3の単位です。 、および4、sp、dp、pxなど。
同様に、8.0未満のデバイスと互換性を持たせたい場合は、xmlでTextViewの代わりにAppCompatTextViewを使用するか、現在のアクティビティがAppCompatActivityを継承します。

まとめ
TextViewの自動サイズ変更はAndroid8.0の新機能であり、TextViewのフォントサイズを動的に変更するために使用できます。8.0未満のデバイスと互換性を持たせるには、次の2つの条件を満たす必要があります。

xmlでTextViewの代わりにAppCompatTextViewを使用し、上記の属性の名前空間にapp名前空間を使用します。
現在のアクティビティは、ActivityまたはFragmentActivityではなくAppCompatActivityを継承します。
TextViewsの自動サイズ設定のその他のプロパティについては、TextViewsの自動サイズ設定を参照してください。


多くの人が2番目のシーンでこの状況に遭遇したに違いありません。テストは写真を投げ、次に下のコンテンツがブロックされた後にテストマシンを実行する方法を言いました(下の右の写真、左の写真は正常です)、あなたは言いましたかあなたはそれをしましたか?画面は適切ですか?次に、テストした携帯電話を見て、実際に設定で特大フォントが選択されています。

うーん...このように見た後、あなたは基本的に問題が何であるかを知っています。その理由は、コントロールの高さをxmlファイルに書き留めており、TextViewのフォント単位がspであるためです。この場合、電話設定でフォントサイズを変更すると、インターフェイスのフォントサイズが変更されます。システムで。

では、この問題をどのように解決する必要がありますか?現時点では、WeChatの動作を確認できますが、調査の結果、システムのフォントサイズを変更してもWeChatのフォントは変わらず、WeChat自体にフォントサイズを変更する機能があることがわかりました。WeChatでフォントサイズを変更すると、フォントサイズだけでなく、コントロールの幅と高さも変更されます。したがって、WeChatのフォント適応は次のように実装されていると推測できます。

フォントサイズは
システムによって変更されませんフォントサイズがシステムによって変更されないことを実現するには、次の2つの方法があります。

  1. xmlモード
    のTextViewのフォント単位は、spではなくdpを使用します。spユニットのフォントサイズはシステムのフォントサイズの変更に伴って変更されますが、dpユニットのフォントサイズは変更されないためです。

  2. 動的エンコーディング方法
    フォントサイズがシステムによって変化するかどうかは、ConfigurationクラスのfontScale変数によって制御できます。fontScale変数のデフォルトは1です。つまり、フォントサイズはシステムのフォントサイズによって変化しません。 fontScaleが常に1であることを確認してください。具体的なコードは次のとおりで、通常は基本クラスBaseActivity ofActivityに配置されます。

    @Override
    public void onConfigurationChanged(Configuration newConfig){ super.onConfigurationChanged(newConfig); if(newConfig.fontScale!= 1){// fontScaleは1ではないため、強制的に1にする必要がありますgetResources(); } }




    @Override
    public Resources getResources(){ Resources resources = super.getResources(); if(resources.getConfiguration()。fontScale!= 1){// fontScaleは1ではないため、1に強制する必要がありますConfiguration newConfig = new Configuration (); newConfig.setToDefaults(); //デフォルト値に設定します。つまり、fontScaleは1ですresources.updateConfiguration(newConfig、resources.getDisplayMetrics()); } return resources; }どちらの方法でも、シナリオの問題を解決できます。 2つですが、通常はすべて、次の理由で動的エンコーディングを使用します。








アプリケーションがフォントサイズを変更できるWeChatと同様の関数を追加する必要がある場合、XMLでdpユニットが使用されていると、この関数は実現されません。
システムのフォントサイズに合わせてフォントサイズを変更する必要がある場合は、コードを削除するだけで済みます。
公式の推奨事項は、フォント単位としてspを使用することです。
コントロールの幅と高さはできるだけ固定しないでください。その
理由は、アプリケーションがフォントサイズを変更するためにWeChatのような関数を追加する必要がある場合、コントロールの幅と高さが固定されていると、フォントが増加するためです。サイズを指定すると、コントロールが表示されなくなりますが、これは必要な効果ではありません。

シーン3に
状況があります。設計図に従ってTextViewコントロールを作成する場合、幅と高さはwrap_contentを使用し、パディングは設定されませんが、携帯電話で実行されているTextViewは幅と高さの比率を占めます。設計図は大きくする必要があります。下の図に示すように、フォントの周囲には多くの空白があります。

これは、TextView自体に内側の余白が含まれているためです。それで、内側の余白を削除するTextViewの属性はありますか?答えは「はい」です。属性はincludeFontPaddingです。falseに設定すると、フォントのパディングが含まれないことを意味します。具体的なコードは次のとおりです。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:text="Hello"
    android:textSize="50sp"
    android:includeFontPadding="false"/>

実行中の効果は、下の図の2番目の「Hello」です(最初の「Hello」は通常のTextViewです)。問題ないように見えますが、注意深く見ると、まだ少し内側の余白があります。

一般的なアプリケーションは内側の余白を気にしないかもしれませんが、TVアプリケーションを実行している場合、TVインターフェイスは一般に上下左右のスクロールをサポートしていないため、要件はより厳しくなります。画面がいっぱいになると、これらの内側の余白が個々のコントロールの表示を不完全にします。したがって、この場合は解決する必要があります。TextView自体のプロパティは解決できないため、カスタマイズすることしかできません。具体的なコードは次のとおりです。

android.content.Contextをインポートします。
import android.content.res.TypedArray;
android.graphics.Canvasをインポートします。
android.graphics.Paintをインポートします。
android.graphics.Rectをインポートします。
import android.support.v7.widget.AppCompatTextView;
android.util.AttributeSetをインポートします。

public class NoPaddingTextView extends AppCompatTextView { private Paint mPaint = getPaint(); private Rect mBounds = new Rect(); private Boolean mRemoveFontPadding = false; //フォントの内側の余白を削除するかどうか、true:削除false:削除しない


public NoPaddingTextView(Context context) {
    super(context);
}

public NoPaddingTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initAttributes(context, attrs);
}

public NoPaddingTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initAttributes(context, attrs);
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (mRemoveFontPadding) {
        calculateTextParams();
        setMeasuredDimension(mBounds.right - mBounds.left, -mBounds.top + mBounds.bottom);
    }
}

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}

protected void onDraw(Canvas canvas) {
    drawText(canvas);
}

/**
 * 初始化属性
 */
private void initAttributes(Context context, AttributeSet attrs) {
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NoPaddingTextView);
    mRemoveFontPadding = typedArray.getBoolean(R.styleable.NoPaddingTextView_removeDefaultPadding, false);
    typedArray.recycle();
}

/**
 * 计算文本参数
 */
private String calculateTextParams() {
    String text = getText().toString();
    int textLength = text.length();
    mPaint.getTextBounds(text, 0, textLength, mBounds);
    if (textLength == 0) {
        mBounds.right = mBounds.left;
    }
    return text;
}

/**
 * 绘制文本
 */
private void drawText(Canvas canvas) {
    String text = calculateTextParams();
    int left = mBounds.left;
    int bottom = mBounds.bottom;
    mBounds.offset(-mBounds.left, -mBounds.top);
    mPaint.setAntiAlias(true);
    mPaint.setColor(getCurrentTextColor());
    canvas.drawText(text, (float) (-left), (float) (mBounds.bottom - bottom), mPaint);
}

}
次のように、attr.xmlファイルにNoPaddingTextViewで必要な属性を定義します。

<?xml version = "1.0" encoding = "utf-8"?>
<declare-styleable name="NoPaddingTextView">
    <attr name="removeDefaultPadding" format="boolean"/>
</declare-styleable>
次のように、レイアウトファイルで使用されます。<?xml version = "1.0" encoding = "utf-8"?>

<com.wildma.fontadaptation.NoPaddingTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:text="Hello"
    android:textSize="50sp"
    app:removeDefaultPadding="true"/>
実行中の効果は、下の図の3番目の「Hello」です(最初は通常のTextViewで、2番目はincludeFontPadding属性を持つTextViewです)。これは完璧なソリューションです。

OK!フォントサイズの適応で最も一般的に使用される3つのシナリオについて説明します。他のシナリオがある場合は、それらを追加してください〜

プロジェクトアドレス:FontAdaptation

著者:wildma
リンク:https://www.jianshu.com/p/2fdc97ae74a8
出典:ジェーンの本
は著者が著作権を所有しています。商用の再版については、著者に連絡して許可を求め、非商用の再版については、出典を示してください。

おすすめ

転載: blog.csdn.net/qq_41915623/article/details/102776517