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

Попробуйте способ создания композиций.
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)

Java

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

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

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

Котлин

view.setBackgroundColor(...)

Java

view.setBackgroundColor(...);

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

Котлин

view.post { magnifier.update() }

Java

view.post(magnifier::update);

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

Котлин

magnifier.dismiss()

Java

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
}

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

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