【Android】フォントサイズ自動調整TextViewの作り方

## はじめに

Androidアプリ開発において、様々な画面サイズやテキストの長さに対応するため、TextViewのフォントサイズを自動調整したい場面は多々あります。

Android 8.0（API 26）以降では`autoSizeTextType`属性が利用できます。
こちらは以前記事にしました。
[画面の表示サイズ(dpi)変更に耐えられるLayoutを定義する](https://qiita.com/HanaleiMoon/items/ae2c89294abfa69935b7)

この方法だと対応できないケースがあり微調整できません。より細かい制御が必要な場合やカスタマイズが必要な場合は、独自のTextViewを実装する必要があります。

本記事では、AppCompatTextViewを継承してフォントサイズを自動調整するカスタムTextViewをKotlinで実装する方法を紹介します。

## 要件

- AppCompatTextViewを継承
- onMeasure()内でフォントサイズを調整
- 最小フォントサイズをdp単位で指定可能
- シンプルで軽量な実装

## 実装

```kotlin
import android.content.Context
import android.graphics.Paint
import android.util.AttributeSet
import android.util.TypedValue
import androidx.appcompat.widget.AppCompatTextView

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

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        adjustTextSizeToFit()
    }

    /**
     * テキストサイズを利用可能なスペースに合わせて自動調整する
     * @param minSizeDp 縮小時の最小サイズ（dp）。nullの場合は現在のサイズを基準とする
     */
    fun adjustTextSizeToFit(minSizeDp: Int? = null) {
        val text = text?.toString() ?: return
        if (text.isEmpty()) return
        
        val availableWidth = measuredWidth - paddingLeft - paddingRight
        if (availableWidth <= 0) return
        
        val currentTextSize = textSize
        val minTextSize = minSizeDp?.let { dpToPx(it) } ?: currentTextSize
        
        val paint = Paint().apply { textSize = currentTextSize }
        var adjustedSize = currentTextSize
        
        while (paint.measureText(text) > availableWidth && adjustedSize > minTextSize) {
            adjustedSize--
            paint.textSize = adjustedSize
        }
        
        if (adjustedSize != currentTextSize) {
            setTextSize(TypedValue.COMPLEX_UNIT_PX, adjustedSize)
        }
    }

    private fun dpToPx(dp: Int): Float = dp * resources.displayMetrics.density
}
```

## 使用方法

### XMLレイアウトでの使用

```xml
<com.yourpackage.AutoResizeTextView
    android:layout_width="200dp"
    android:layout_height="50dp"
    android:text="自動調整されるテキスト"
    android:textSize="16sp"
    android:gravity="center" />
```

### コードでの使用

```kotlin
val autoTextView = findViewById<AutoResizeTextView>(R.id.autoTextView)

// デフォルトサイズで自動調整
autoTextView.text = "長いテキストが入ります"

// 最小10dpまで縮小を許可
autoTextView.adjustTextSizeToFit(10)

// テキスト変更後に再調整
autoTextView.text = "新しいテキスト"
autoTextView.adjustTextSizeToFit(8)
```

## 動作例

| 元のテキスト | 調整後 |
|---|---|
| ![スクリーンショット 2025-05-30 20.33.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264726/90b9a869-ca43-449e-859e-372155014b81.png) | ![スクリーンショット 2025-05-30 20.33.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264726/3c6a6cbb-4575-4b30-ad11-1e5dba29d23c.png) |

テキストが長い場合、自動的にフォントサイズが縮小されて、指定した領域内に収まります。

## カスタマイズのポイント

### 最大サイズの制限

現在の実装では縮小のみ対応していますが、拡大も対応したい場合は以下のような拡張が可能です：

```kotlin
fun adjustTextSizeToFit(minSizeDp: Int? = null, maxSizeDp: Int? = null) {
    // 最大サイズの処理を追加
    val maxTextSize = maxSizeDp?.let { dpToPx(it) } ?: currentTextSize * 2
    
    // 拡大処理のロジックを追加
}
```

## まとめ

この実装により、以下のメリットが得られます：

- **シンプル**: 必要最小限の機能に絞った軽量な実装
- **柔軟性**: 最小サイズを動的に指定可能
- **効率性**: 早期リターンと最適化されたアルゴリズム
- **拡張性**: 必要に応じてカスタマイズ可能

Androidでフォントサイズの自動調整が必要な場面で、ぜひ活用してみてください。

## 参考リンク

- [Android Developers - TextView](https://developer.android.com/reference/android/widget/TextView)
- [Android Developers - AppCompatTextView](https://developer.android.com/reference/androidx/appcompat/widget/AppCompatTextView)
- [Android Developers - AutoSizing TextViews](https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview)