1
Help us understand the problem. What are the problem?

posted at

updated at

背景付きTextViewやEditTextでautoSizeTextTypeを使う方法

背景付きTextViewやEditTextでautoSizeTextTypeを使う方法

Android 8.0(API レベル 26)以上では、テキストサイズを自動的に拡大または縮小し、TextView の特性と境界に基づいてレイアウトを埋めるよう TextView に指示できます。このように設定すると、動的コンテンツを表示するさまざまな画面で、テキストサイズの最適化が容易になります。

TextViewに対して上下左右の制約を課したときに自動サイズ調節を行える機能があります。
こちら、xmlファイルにandroid:autoSizeTextType="uniform"を追加するだけで済むので非常に便利なのですが、
以下のような要件の時に問題が発生します。

  • ①TextViewに背景を設定したい場合
  • ②EditTextでtextのautosizingをやりたい場合

これらの状況でautosizingを設定したい場合の問題と対処法について説明します。
まず、TextViewに背景を設定したい場合は以下のように書くと思います。

backgrounded_text.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingVertical="2dp"
        android:paddingHorizontal="15dp"
        android:text="example"
        android:autoSizeTextType="uniform"
        android:textColor="@color/white"
        android:background="@drawable/black_edge_rounded"
        app:layout_constraintHeight_percent="0.1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

この書き方だと、結果は以下のようになります。

image.png

上下左右に絶対値の制約を課しているため文字だけに背景を設定することができません。
「じゃあ、android:layout_width="wrap_content"にすればいいじゃん」と思うと思いますが、そうすると

image.png

このようになってしまいます。

注: XML ファイルで自動サイズ調整を設定する場合、TextView の layout_width 属性または layout_height 属性に値「wrap_content」を使用することはおすすめしません。そのようにすると、予期しない結果が発生する可能性があります。

とある通りwrap_contentは使えません。

そこで、以下の解決法があります。

customed_backgrounded_text.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:paddingVertical="2dp"
        android:paddingHorizontal="15dp"
        android:text="example"
        android:textColor="@color/white"
        android:background="@drawable/black_edge_rounded_ripple"
        android:maxLines="1"
        android:gravity="center_vertical"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintHeight_percent="0.1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/dummy_text_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingVertical="2dp"
        android:paddingHorizontal="15dp"
        android:text="example"
        android:visibility="invisible"
        android:autoSizeTextType="uniform"
        android:textColor="@color/white"
        android:background="@drawable/black_edge_rounded_ripple"
        app:layout_constraintHeight_percent="0.1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

dummy_text_viewtext_viewを表示させたい大きさの制約と同じところに設定したうえで、
android:autoSizeTextType="uniform"と記載します。これで、text_viewwrap_contentのまま、
text_viewに表示させたい文字の大きさをdummy_text_viewに持たせることができます。

EditTextの場合はandroid:layout_width="0dp" android:layout_height="0dp"を設定してもautosizingが効きませんので以下のように記述します。

edit_text.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/edit_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:inputType="text"
        android:text="example"
        android:background="@null"
        android:textColor="@color/white"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintHeight_percent="0.1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/dummy_text_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingVertical="2dp"
        android:paddingHorizontal="15dp"
        android:text="example"
        android:visibility="invisible"
        android:autoSizeTextType="uniform"
        app:layout_constraintHeight_percent="0.1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

あとはJava/Kotlin codeの方で
textView.setTextSize(dummyTextView.getTextSize())
を呼んでやればOKです。

…とはなりません。
もう2点考慮しなければならないことがあります。
1つ目はViewのライフサイクルです。
どういうことかというと、Viewが実際に描画されるタイミングはonDraw()で、これは
ActivityのサイクルでいうところのonResume()よりも遅いです。
なので、Activity付随のcallback関数に実装してもautosizeの大きさが確定していない段階で
呼ばれるため思った動作にならないんですね。

こちらの記事を参考にさせていただきました。

さらに、2つ目にTextViewでsetTextSize()とgetTextView()で単位が違うため変換を施さなければなりません。

こちらの記事を参考にさせていただきました。

以下のように記述すれば、目的の動作が実現できるはずです。

MainActivity.java

public float convertPxToSp(float px) {
        return px / this.getResources().getDisplayMetrics().scaledDensity;
    }

editText.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
                @Override
                public void onDraw() {
                    editText.setTextSize(convertPxToSp(binding.dummyTextView.getTextSize()));
                }
            });

お疲れさまでした。

この記事で使っているレスポンシブUIに関する記述法はこちらをご参考ください。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
1
Help us understand the problem. What are the problem?