Доступность клавиатуры в Flutter: Готова ли ваша приложение?

Доступность клавиатуры в Flutter: Готова ли ваша приложение?

FlutterPulse

Эта статья переведена специально для канала FlutterPulse. В этом канале вы найдёте много интересных вещей, связанных с Flutter. Не забывайте подписываться! 🚀

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

Доступность — это не функция; это право.

Даже небольшие изменения, такие как правильная навигация по клавиатуре, могут существенно повлиять на пользователей с ограниченными возможностями или особыми потребностями. Flutter предлагает средства, такие как FocusTraversalGroup, FocusTraversalOrder, ExcludeFocus и FocusNode, для навигации с помощью клавиатуры, которая является детерминированной и удобной в использовании.

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

Почему важна доступность

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

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

Преимущества доступности клавиатуры

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

Если управление фокусировкой не управляется должным образом, пользователь может потеряться в интерфейсе, фокусировка может казаться случайной, и в худшем случае — полностью заблокироваться в недоступных частях приложения.

Flutter's focus system allows you to:

  • Группировать и упорядочивать виджеты с фокусировкой.
  • Исключать виджеты из дерева фокусировки.
  • Настраивать способ перемещения фокусировки между виджетами.

Обзор системы фокусировки Flutter

Flutter предоставляет иерархическое дерево фокусировки, где FocusNode и связанные виджеты управляют состоянием фокусировки каждого виджета. Вот как работают основные компоненты

1. FocusNode

FocusNode — это низкоуровневый объект, который отвечает за мониторинг и управление фокусировкой одного виджета.

Use cases:

  • Управление вводом с клавиатуры для TextField.
  • Ручное управление фокусировкой (например, перемещение фокусировки при нажатии пользователем "Tab").
  • Обнаружение, когда виджет получает или теряет фокусировку.

Example:

final FocusNode focusNode = FocusNode();

@override
Widget build(BuildContext context) {
  return TextField(
    focusNode: focusNode,
    decoration: InputDecoration(labelText: 'Enter your name'),
  );
}

2. FocusTraversalGroup

FocusTraversalGroup объединяет виджеты в область прохождения фокуса и управляет тем, как фокус перемещается между виджетами. Это обеспечивает логический и настраиваемый порядок фокусировки внутри этой группы.

Политики Для определения способа перемещения фокуса необходимо реализовать политику:

  • WidgetOrderTraversalPolicy (По умолчанию). Порядок фокусировки следует иерархии дерева виджетов. Отлично подходит для большинства интерфейсов, где виджеты расположены логически.
  • ReadingOrderTraversalPolicy. Следует визуальному порядку (слева направо, сверху вниз). Идеален для интерфейсов, напоминающих документ или макет формы.
  • OrderedTraversalPolicy. Этот использует FocusTraversalOrder для определения пользовательской последовательности фокусировки. Наиболее адаптивен в сложных макетах, где порядок по умолчанию нелогичен.

Пример:

FocusTraversalGroup(
  policy: WidgetOrderTraversalPolicy(),
  child: Column(
    children: [
      TextField(decoration: InputDecoration(labelText: 'Username')),
      TextField(decoration: InputDecoration(labelText: 'Password')),
      ElevatedButton(onPressed: () {}, child: Text('Login')),
    ],
  ),
);

Здесь FocusTraversalGroup сохраняет фокус в порядке, в котором определены виджеты.

3. FocusTraversalOrder

FocusTraversalOrder настраивает последовательность фокусировки внутри FocusTraversalGroup. Это особенно актуально, если вы хотите, чтобы фокус направлялся в порядке, который не соответствует иерархии виджетов.

Существуют различные типы порядка:

  • NumericFocusOrder. Фокусирует виджеты в порядке возрастания числового значения.
  • LexicalFocusOrder. Фокусирует виджеты в алфавитном порядке (по порядку строк).

Пример:

FocusTraversalGroup(
  policy: OrderedTraversalPolicy(),  // Использует NumericFocusOrder
  child: Column(
    children: [
      FocusTraversalOrder(
        order: NumericFocusOrder(2),
        child: TextField(decoration: InputDecoration(labelText: 'Password')),
      ),
      FocusTraversalOrder(
        order: NumericFocusOrder(1),
        child: TextField(decoration: InputDecoration(labelText: 'Username')),
      ),
      FocusTraversalOrder(
        order: NumericFocusOrder(3),
        child: ElevatedButton(onPressed: () {}, child: Text('Login')),
      ),
    ],
  ),
);

В этом примере порядок фокусировки будет: Username > Password > Login Button

Если FocusTraversalOrder не используется, фокус будет определяться последовательностью дерева виджетов, что может противоречить предполагаемому потоку навигации.

4. ExcludeFocus

ExcludeFocus временно "поднимает" виджет и его потомков из дерева фокусировки. Это полезно, например, для скрытия или отключения частей интерфейса без нарушения навигации с клавиатуры.

ExcludeFocus(
  excluding: true,
  child: ElevatedButton(onPressed: () {}, child: Text('Disabled Button')),
);

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

Реальный пример: доступная форма входа

Давайте соберём все части и создадим полностью доступную страницу входа с использованием FocusTraversalGroup, FocusTraversalOrder, и FocusNode.

class AccessibleLoginForm extends StatelessWidget {
  final FocusNode usernameFocus = FocusNode();
  final FocusNode passwordFocus = FocusNode();
  final FocusNode loginButtonFocus = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Accessible Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: FocusTraversalGroup(
          policy: OrderedTraversalPolicy(),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              FocusTraversalOrder(
                order: NumericFocusOrder(1),
                child: TextField(
                  focusNode: usernameFocus,
                  decoration: InputDecoration(labelText: 'Username'),
                ),
              ),
              FocusTraversalOrder(
                order: NumericFocusOrder(2),
                child: TextField(
                  focusNode: passwordFocus,
                  decoration: InputDecoration(labelText: 'Password'),
                  obscureText: true,
                ),
              ),
              FocusTraversalOrder(
                order: NumericFocusOrder(3),
                child: ElevatedButton(
                  focusNode: loginButtonFocus,
                  onPressed: () {
                    // Handle login
                  },
                  child: Text('Login'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Советы по тестированию доступности

Чтобы убедиться, что ваше приложение доступно:

  • Проверьте с помощью клавиатуры. Можете ли вы перемещаться по всем фокусируемым виджетом?
  • Проверьте индикаторы фокуса. Явно ли виден текущий фокусируемый виджет?
  • Избегайте ловушек фокуса. Убедитесь, что пользователи могут выйти из скрытых или отключённых элементов.
  • Проверьте с реальными пользователями. Получите обратную связь от пользователей с инвалидностью.

Заключение

Доступность является важной частью разработки приложений. С системой фокусировки Flutter, навигация по клавиатуре может быть легко реализована, чтобы сделать ваше приложение доступным и удобным для всех.

Используя FocusTraversalGroup, FocusTraversalOrder, и связанные виджеты, вы можете создать предсказуемое, интуитивно понятное поведение фокуса, которое работает для всех.

Report Page