LoginSignup
7
5

More than 3 years have passed since last update.

AndroidのTextViewの高さを考慮してフォントサイズを自動調整する

Posted at

今回はAndroidのTextViewのフォントサイズの自動調整に関するお話です。

スクリーンショット 2019-05-19 22.57.38.png

環境:Android Studio 3.3.1、Kotlin 1.3

AndroidでもAndroid 8.0(API Level 26)からAutoSizing TextViewsが追加されました。
しかしレイアウトの都合でTextViewのwidthを"wrap_content"にしなければならない場合はこのAutoSizing TextViewsでもフォントが自動調整されません。
そこで以下のサイトなどを参考に自分でフォントサイズを調整することが多いかと思うのですが、

【Android】横幅に合わせてテキストサイズを調整する

この方法の場合、TextViewが複数行表示できる高さを持っている時にも、テキストを1行で表示する大きさまでフォントサイズを小さくしてしまいます。
TextViewがテキストを複数行表示できる高さを持っている場合は、テキストを複数行にしてぎりぎり表示できるフォントサイズに留めておきたいですよね。
そこで上記のサイトのコードに少し手を加えて以下の様にしてみました。

コード

AutoFontTextView.kt
import android.content.Context
import android.graphics.Paint
import android.util.AttributeSet
import android.util.TypedValue
import android.widget.TextView

class AutoFontFitTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : TextView(context, attrs, defStyleAttr) {

    override fun onLayout(changed: Boolean, left:Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        resize()
    }

    private fun resize() {

        val viewHeight = this.height
        val viewWidth = this.width
        var textSize = this.textSize

        var textHeight = calcTextHeight(textSize,viewWidth)

        while (viewHeight <= textHeight) {
            if (1f >= textSize) {
                textSize = 1f
                break
            }

            textSize -= 1f
            textHeight = calcTextHeight(textSize,viewWidth)
        }

        setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
    }

    private fun calcTextHeight(textSize:Float,viewWidth:Int): Float {
        val paint = Paint()
        paint.textSize = textSize
        val textHeightPerRow = paint.getFontMetrics(null)
        val textPerLines = this.text.toString().split("\n")

        var rowCount = 0

        for (i in 0..textPerLines.size - 1) {
            val textWidth = paint.measureText(textPerLines[i])
            rowCount += Math.ceil(textWidth.toDouble() / viewWidth.toDouble()).toInt()
            if (i != textPerLines.size - 1) {
                rowCount += 1
            }
        }
        return textHeightPerRow * rowCount
    }
}

解説

Paintを利用してテキストのサイズを測るところは同じです。
テキストサイズをPaintに設定した後、以下のコードでテキストの1行あたりの高さが取れます。

val textHeightPerRow = paint.getFontMetrics(null)

次にテキストを表示するために必要な行数を割り出します。
今回はテキストに改行文字が入っているケースも想定しています。

val textPerLines = this.text.toString().split("\n")
var rowCount = 0

for (i in 0..textPerLines.size - 1) {
    val textWidth = paint.measureText(textPerLines[i])
    rowCount += Math.ceil(textWidth.toDouble() / viewWidth.toDouble()).toInt()
    if (i != textPerLines.size - 1) {
         rowCount += 1
    }
}

「1行あたりの高さ * 必要な行数」でテキストの高さが得られますので、それがTextViewの高さ以内に収まるまでフォントサイズを下げます。

GitHub

今回のサンプルコードは以下のGitHubで公開しています。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5