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

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 プラットフォーム全体で一貫した方法でカスタム テキストビューに対して拡大鏡を有効にすることをおすすめします。次の点を考慮してください。

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