画面の表示サイズ(dpi)変更に耐えられるLayoutを定義する


はじめに

Android 7.0 Nougat(ヌガー) の新機能として画面の表示サイズ(dpi)を変更することができるようになった。
しかし、これにより開発側はLayoutをdpで指定していることが多い為、表示崩れが発生し問題となってしまうことがある。
この対策方法を記載した。

AutosizingTextView

AutosizingTextViewは、TextViewのテキストサイズを自動調節してくれるAPIで、API Level 26から追加された。
AutosizingTextViewを使用することで表示崩れ対策が可能である。
https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview

サンプルアプリ作成

とりあえず簡単な画面を実装して表示する。

MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:weightSum="4">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:minWidth="30dp"
            android:text="@string/button1" />

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:maxWidth="50dp"
            android:text="@string/just_do_it"
            android:textColor="@color/colorAccent"
            android:textSize="15sp" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:minWidth="30dp"
            android:text="@string/button2" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:minWidth="30dp"
            android:text="@string/button3" />
    </LinearLayout>

</android.support.constraint.ConstraintLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My Application</string>
    <string name="button1">Button1</string>
    <string name="button2">Button2</string>
    <string name="button3">Button3</string>

    <string name="just_do_it">Just do it!</string>
</resources>
strings.xml(ja)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="just_do_it">とにかく やってみろ!</string>
</resources>

レイアウト崩れ

1.画面の表示サイズ変更によるレイアウト崩れ

設定で表示サイズをDefaultからLargestに変更するとテキストが2行に改行されてしまう。

2.言語変更によるレイアウト崩れ

設定で日本語表示にするとテキストが3行に改行されてしまう。

AutosizingTextViewの使用

app:autoSizeTextType="uniform"
app:autoSizeMinTextSize="1dp"
app:autoSizeMaxTextSize="50dp"
を追記することでAutosizingTextViewが使用できる。
今回はテキストを1行にしたいので
android:maxLines="1"
も追記する

activity_main.xml
    <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:maxWidth="50dp"
            android:text="@string/just_do_it"
            android:textColor="@color/colorAccent"
            android:textSize="15sp"
            android:maxLines="1"
            app:autoSizeTextType="uniform"
            app:autoSizeMinTextSize="1dp"
            app:autoSizeMaxTextSize="50dp" />

これで表示するとmaxWidthの50dp内にテキストを1行で表示することができるようになる。

AutosizingTextView使用の注意点

autoSizeMinTextSize と autoSizeMaxTextSize をxmlに記載しないとAutosizingTextViewは適用されなかったので、定義が必須と考えられる。

AutosizingTextViewの利点

AutosizingTextViewを使用し、maxWidth、autoSizeMaxTextSizeを調整することでLayoutの微調整が可能である。
例えば、maxWidthを大きくして、autoSizeMaxTextSizeを小さくすれば、Widthを広げつつ文字だけ小さくすることも可能である。