При разработке мобильных приложений для терминалов сбора данных (ТСД) на платформе 1С часто возникает задача, которая ставит в тупик многих разработчиков. На обычном компьютере мы привыкли, что по любому списку можно легко перемещаться с помощью клавиш-стрелок на клавиатуре. Однако при переносе этой логики на ТСД с аппаратной клавиатурой оказывается, что в динамических списках клавиши навигации просто не работают. При этом в других элементах формы, например, при переходе по полям карточки объекта, те же самые клавиши могут функционировать исправно.
Разберем, почему так происходит и как заставить мобильное приложение 1С реагировать на аппаратные клавиши ТСД для навигации по элементам динамического списка.
Основная причина кроется в архитектуре мобильной платформы 1С. В отличие от настольной версии, она изначально ориентирована на сенсорное управление (touch-интерфейс). Динамический список на мобильном устройстве обрабатывает касания и свайпы, но не имеет встроенного механизма для преобразования кодов аппаратных клавиш (например, "стрелка вверх" или "стрелка вниз") в команды для смены текущей строки.
Платформа просто не "знает", что нажатие определенной физической кнопки должно приводить к перемещению по списку. Эту логику необходимо реализовать самостоятельно. Задача распадается на два ключевых этапа:
Рассмотрим оба этих этапа подробно.
Стандартными средствами языка 1С "услышать" нажатие физической клавиши на Android-устройстве невозможно. Для этого необходим мост между операционной системой устройства и средой исполнения 1С. Таким мостом выступает внешняя компонента (ВК).
Внешняя компонента — это, по сути, нативная библиотека, которая может взаимодействовать с API операционной системы (в нашем случае Android) и передавать события в 1С. Когда пользователь нажимает клавишу, Android генерирует системное событие. ВК перехватывает его и инициирует процедуру ВнешнееСобытие в модуле формы 1С, передавая в параметрах информацию о произошедшем событии (например, название устройства и код нажатой клавиши).
Где взять такую компоненту?
Библиотека подключаемого оборудования (БПО). В первую очередь стоит изучить стандартные драйверы, поставляемые вместе с БПО для мобильных приложений. Например, драйвер InputDevice или "1С:Сканер штрихкода (NativeApi)". Иногда они могут перехватывать не только сканирование, но и другие системные события. Важно: как показывает практика, их работа сильно зависит от модели ТСД и версии Android. На одном устройстве все может заработать сразу, а на другом — драйвер выдаст ошибку или просто не будет видеть устройство.
ВК от производителя или поставщика ТСД. Это самый надежный путь. Крупные производители (например, Urovo, Honeywell, Zebra) и поставщики (например, RightScan) часто предоставляют собственные SDK (Software Development Kit) и уже готовые внешние компоненты для 1С. Эти ВК написаны специально под их оборудование и обеспечивают наиболее стабильную работу. Рекомендуется обратиться в техническую поддержку вашего поставщика ТСД с запросом на предоставление такой компоненты.
Сторонние и самописные разработки. На профильных форумах и в сообществах можно найти универсальные компоненты от независимых разработчиков, предназначенные для перехвата событий клавиатуры.
После подключения и настройки компоненты необходимо в модуле формы, где расположен ваш динамический список, создать обработчик события ВнешнееСобытие.
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Здесь мы будем анализировать пришедшие данные
// и вызывать процедуру навигации по списку.
// Например, ВК может передавать имя события "KeyPress"
Если Событие = "KeyPress" Тогда
// В параметре "Данные" может быть код клавиши
// Например, "ArrowDown" или "ArrowUp". Названия условны
// и зависят от конкретной ВК. Их нужно выяснять
// из документации к ВК или опытным путем.
Если Данные = "ArrowDown" Тогда
ПерейтиНаСледующуюСтрокуСписка();
ИначеЕсли Данные = "ArrowUp" Тогда
ПерейтиНаПредыдущуюСтрокуСписка();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Иногда внешние компоненты передают более сложную структуру данных, где нужно анализировать несколько полей. Например, название события (ActionName) и дополнительные параметры (ExtraName), которые могут быть уникальны для каждой модели ТСД.
Предположим, мы успешно перехватили событие и знаем, что пользователь нажал "стрелку вниз". Теперь нужно заставить сам список сменить текущую строку. Простого метода вроде Элементы.Список.Следующий() в мобильной платформе нет. Поэтому придется действовать немного сложнее, работая с коллекцией данных формы.
Алгоритм действий следующий:
Посмотрим, как это выглядит в коде. Допустим, ваш динамический список на форме называется СписокНоменклатуры.
&НаКлиенте
Процедура ПерейтиНаСледующуюСтрокуСписка()
// 1. Получаем идентификатор текущей строки
ТекущийИдентификатор = Элементы.СписокНоменклатуры.ТекущаяСтрока;
// Если ни одна строка не выбрана, выходим
Если ТекущийИдентификатор = Неопределено Тогда
Возврат;
КонецЕсли;
// Получаем коллекцию данных, с которой связан список
КоллекцияДанных = ДанныеФормыВЗначение(ЭтаФорма.СписокНоменклатуры, Тип("ДанныеФормыКоллекция"));
// 2. Находим элемент данных по идентификатору
ТекущийЭлементДанных = КоллекцияДанных.НайтиПоИдентификатору(ТекущийИдентификатор);
Если ТекущийЭлементДанных = Неопределено Тогда
Возврат;
КонецЕсли;
// Определяем его индекс
ТекущийИндекс = КоллекцияДанных.Индекс(ТекущийЭлементДанных);
// 3. Вычисляем новый индекс
НовыйИндекс = ТекущийИндекс + 1;
// 4. Проверяем границы списка
Если НовыйИндекс >= КоллекцияДанных.Количество() Тогда
// Мы на последней строке, дальше двигаться некуда
Возврат;
КонецЕсли;
// 5. Получаем новый элемент данных
НовыйЭлементДанных = КоллекцияДанных[НовыйИндекс];
// 6. Устанавливаем новую текущую строку
Элементы.СписокНоменклатуры.ТекущаяСтрока = НовыйЭлементДанных.ПолучитьИдентификатор();
КонецПроцедуры
&НаКлиенте
Процедура ПерейтиНаПредыдущуюСтрокуСписка()
ТекущийИдентификатор = Элементы.СписокНоменклатуры.ТекущаяСтрока;
Если ТекущийИдентификатор = Неопределено Тогда
Возврат;
КонецЕсли;
КоллекцияДанных = ДанныеФормыВЗначение(ЭтаФорма.СписокНоменклатуры, Тип("ДанныеФормыКоллекция"));
ТекущийЭлементДанных = КоллекцияДанных.НайтиПоИдентификатору(ТекущийИдентификатор);
Если ТекущийЭлементДанных = Неопределено Тогда
Возврат;
КонецЕсли;
ТекущийИндекс = КоллекцияДанных.Индекс(ТекущийЭлементДанных);
НовыйИндекс = ТекущийИндекс - 1;
// Проверяем, что не ушли "ниже" первой строки
Если НовыйИндекс < 0 Тогда
Возврат;
КонецЕсли;
НовыйЭлементДанных = КоллекцияДанных[НовыйИндекс];
Элементы.СписокНоменклатуры.ТекущаяСтрока = НовыйЭлементДанных.ПолучитьИдентификатор();
КонецПроцедуры
Важный момент: работа с ДанныеФормыВЗначение и обратно может быть не самой производительной на больших списках. Однако для типичных сценариев на ТСД, где на экране отображается ограниченное количество строк, этот подход вполне рабочий.
В процессе работы вы можете столкнуться с еще двумя частыми неудобствами.
Как скрыть экранную клавиатуру?
При использовании аппаратной клавиатуры всплывающая экранная клавиатура сильно мешает, перекрывая половину экрана. Решение часто лежит за пределами кода 1С:
Как правильно работать со сканером?
Часто сканер на ТСД настроен в режиме "эмуляции клавиатуры" или "в разрыв клавиатуры". Это значит, что отсканированный штрихкод передается в приложение так, будто его быстро набрали на клавиатуре. Это простой способ, но у него есть минус: для сканирования всегда должно быть активно какое-то поле ввода. Более правильный и гибкий подход — использовать нативный режим работы сканера через ту же внешнюю компоненту. В этом случае данные от сканера приходят как внешнее событие, независимо от того, какой элемент формы активен. Это позволяет, например, сканировать штрихкоды прямо в форме списка для поиска товара, не активируя специально поле ввода.
В итоге, для полноценной и удобной работы с аппаратной клавиатурой и сканером на ТСД в мобильном приложении 1С необходимо отойти от стандартного функционала и воспользоваться возможностями внешних компонент, дополнив их логикой на встроенном языке 1С.