Реализация текстовой лупы

Попробуйте способ создания
Jetpack Compose — рекомендуемый набор инструментов пользовательского интерфейса для Android. Узнайте, как использовать текст в Compose.

Виджет лупы, доступный в Android 9 (уровень API 28) и более поздних версиях, представляет собой виртуальное увеличительное стекло, которое отображает увеличенную копию View через панель наложения, представляющую линзу. Эта функция улучшает взаимодействие с пользователем при вставке и выборе текста. Применяя лупу к тексту, пользователь может точно расположить курсор или маркеры выделения, просматривая увеличенный текст на панели, которая следует за пальцем.

На рис. 1 показано, как лупа облегчает выделение текста. API-интерфейсы лупы не привязаны к тексту, и вы можете использовать этот виджет в различных случаях, например, для чтения небольшого текста или увеличения трудноразличимых названий мест на картах.

Изображение, показывающее, как появляется лупа после захвата правого маркера выбора.
Рисунок 1. Увеличение текста. Когда пользователь перетаскивает правый маркер выбора, появляется лупа, помогающая точно разместить объект.

Лупа уже интегрирована с виджетами платформы, такими как TextView , EditText и WebView . Он обеспечивает согласованное манипулирование текстом в приложениях. Виджет поставляется с простым API и может использоваться для увеличения любого View в зависимости от контекста вашего приложения.

Использование API

Вы можете использовать лупу программно в произвольном представлении следующим образом:

Котлин

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

Ява

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

Предполагая, что иерархия представлений имеет первый макет, лупа отображается на экране и содержит область, центрированную по заданным координатам в представлении. Панель появится над центральной точкой копируемого содержимого. Лупа сохраняется неопределенно долго, пока пользователь не закроет ее.

В следующем фрагменте кода показано, как изменить фон увеличенного изображения:

Котлин

view.setBackgroundColor(...)

Ява

view.setBackgroundColor(...);

Если предположить, что цвет фона виден внутри лупы, содержимое лупы устарело, поскольку область представления со старым фоном все еще отображается. Чтобы обновить содержимое, используйте метод update() следующим образом:

Котлин

view.post { magnifier.update() }

Ява

view.post(magnifier::update);

Закончив, закройте лупу, вызвав метод dismiss() :

Котлин

magnifier.dismiss()

Ява

magnifier.dismiss();

Увеличение взаимодействия с пользователем

Распространенный вариант использования лупы — позволить пользователю увеличить область просмотра, коснувшись ее, как показано на рисунке 2.

Рисунок 2. Лупа следует за прикосновением пользователя. Он применяется к ViewGroup , которая содержит ImageView слева и TextView справа.

Вы можете сделать это, обновив лупу в соответствии с событиями касания, полученными представлением, следующим образом:

Котлин

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
}

Ява

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. Учтите следующее:

  • Лупа срабатывает сразу, когда пользователь захватывает маркер вставки или выбора.
  • Лупа всегда плавно следует за пальцем пользователя по горизонтали, а по вертикали фиксируется к центру текущей текстовой строки.
  • При горизонтальном перемещении лупа перемещается только между левой и правой границами текущей строки. Более того, когда касание пользователя выходит за эти границы и расстояние по горизонтали между касанием и ближайшей границей превышает половину исходной ширины содержимого лупы, лупа закрывается, поскольку курсор больше не виден внутри лупы.
  • Лупа никогда не срабатывает, если шрифт текста слишком велик. Текст считается слишком большим, если разница между спуском и подъемом шрифта превышает высоту содержимого, помещающегося в увеличителе. Включение лупы в этом случае не добавляет ценности.