テキスト拡大鏡を実装する

Compose を試す
Jetpack Compose は Android で推奨される UI ツールキットです。Compose でテキストを使用する方法について学習します。

Android 9(API レベル 28)以降で利用可能な拡大鏡ウィジェットは、レンズを表すオーバーレイ ペインに View の拡大コピーを表示する仮想虫メガネです。この機能により、テキストの挿入と選択のユーザー エクスペリエンスが向上します。拡大鏡をテキストに適用する際、指を動かすペインで拡大テキストを確認することで、カーソルや選択ハンドルを正確に配置できます。

図 1 は、拡大鏡によってテキストの選択が容易になる様子を示しています。拡大鏡 API はテキストに結びつけられていないため、このウィジェットは、小さなテキストの読み取りや地図上の見えにくい場所名の拡大など、さまざまなユースケースで使用できます。

右側の選択ハンドルをつかんだ後に拡大鏡がどのように表示されるかを示す画像
図 1. テキストを拡大します。ユーザーが右側の選択ハンドルをドラッグすると、拡大鏡がポップアップ表示されるため、正確な位置に配置できます。

拡大鏡は、TextViewEditTextWebView などのプラットフォーム ウィジェットにすでに統合されています。アプリ間で一貫したテキスト操作を実現します。このウィジェットにはシンプルな API が付属しており、アプリのコンテキストに応じて View を拡大できます。

API の使用方法

拡大鏡は、次のように任意のビュー上でプログラムで使用できます。

Kotlin

val view: View = findViewById(R.id.view)
val magnifier = Magnifier.Builder(view).build()
magnifier.show(view.width / 2.0f, view.height / 2.0f)

Java

View view = findViewById(R.id.view);
Magnifier magnifier = new Magnifier.Builder(view).build();
magnifier.show(view.getWidth() / 2, view.getHeight() / 2);

ビュー階層に最初のレイアウトがあると仮定すると、拡大鏡は画面に表示され、ビュー内の指定された座標を中心とする領域を包含します。このペインは、コピーされるコンテンツの中心点の上に表示されます。拡大鏡は、ユーザーが閉じるまで無期限に維持されます。

次のコード スニペットは、拡大ビューの背景を変更する方法を示しています。

Kotlin

view.setBackgroundColor(...)

Java

view.setBackgroundColor(...);

拡大鏡内に背景色が表示されている場合、拡大鏡のコンテンツは古くなり、古い背景のビューの領域が引き続き表示されます。コンテンツを更新するには、次のように update() メソッドを使用します。

Kotlin

view.post { magnifier.update() }

Java

view.post(magnifier::update);

終了したら、dismiss() メソッドを呼び出して、拡大鏡を閉じます。

Kotlin

magnifier.dismiss()

Java

magnifier.dismiss();

ユーザーの操作に応じて拡大する

拡大鏡の一般的なユースケースは、図 2 に示すように、ユーザーがビュー領域をタップして拡大できるようにすることです。

図 2.拡大鏡はユーザーのタップに応じて移動します。これは、左に「ImageView」、右に TextView を含む ViewGroup に適用されます。

そのためには、次のように、ビューが受け取ったタッチイベントに応じて拡大鏡を更新します。

Kotlin

imageView.setOnTouchListener { v, event ->
  when (event.actionMasked) {
    MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
      val viewPosition = IntArray(2)
      v.getLocationOnScreen(viewPosition)
      magnifier.show(event.rawX - viewPosition[0], event.rawY - viewPosition[1])
    }
    MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
      magnifier.dismiss()
    }
  }
  true
}

Java

imageView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                // Fall through.
            case MotionEvent.ACTION_MOVE: {
                final int[] viewPosition = new int[2];
                v.getLocationOnScreen(viewPosition);
                magnifier.show(event.getRawX() - viewPosition[0],
                               event.getRawY() - viewPosition[1]);
                break;
            }
            case MotionEvent.ACTION_CANCEL:
                // Fall through.
            case MotionEvent.ACTION_UP: {
                magnifier.dismiss();
            }
        }
        return true;
    }
});

テキストを拡大する際のその他の注意事項

プラットフォームのテキスト ウィジェットの場合、Android プラットフォーム全体で拡大鏡の特定の動作を理解し、カスタム テキストビューの拡大鏡を一貫して有効にすることが重要です。以下の点を考慮してください。

  • 拡大鏡は、ユーザーが挿入ハンドルや選択ハンドルをつかむとすぐにトリガーされます。
  • 拡大鏡は、水平方向には常にユーザーの指の動きに合わせてスムーズに移動し、垂直方向は現在のテキスト行の中心に固定されます。
  • 水平方向に移動する場合、拡大鏡は現在の行の左右の境界の間のみを移動します。さらに、ユーザーがタップした範囲がこの境界を離れ、タップと最も近い境界の間の水平距離が拡大鏡コンテンツの元の幅の半分より大きい場合、カーソルが拡大鏡内に表示されなくなるため、拡大鏡が閉じます。
  • テキストのフォントが大きすぎる場合、拡大鏡はトリガーされません。フォントの下降と下降の差が拡大鏡に収まるコンテンツの高さよりも大きい場合、テキストは大きすぎるとみなされます。この場合、拡大鏡をトリガーしても効果はありません。