При разработке мобильных приложений на платформе 1С разработчики часто сталкиваются с неочевидным поведением интерфейса, которое кардинально отличается от работы в настольной версии платформы (в тонком или толстом клиентах). В этой статье мы подробно разберем две популярные проблемы: почему платформа "не видит" только что введенный текст в поле ввода, и почему системные сообщения могут выводиться по 5-10 раз одновременно. Проанализируем ситуацию по шагам и выясним причину каждого из багов.
Рассмотрим классическую ситуацию: на управляемой форме есть строковый реквизит и привязанное к нему поле ввода. Пользователь вводит текст (например, тему письма) и сразу же, не скрывая клавиатуру, нажимает кнопку отправки. В обработчике кнопки написан следующий код:
Если ТекстПисьма = "" Тогда
Сообщить("Заполните текст письма!");
ИначеЕсли ТемаПисьма = "" Тогда
Сообщить("Заполните тему письма!");
Иначе
// тут делаем отправку письма
КонецЕсли;
При тестировании на компьютере этот код отрабатывает идеально. Однако на мобильном устройстве (Android или iOS) проверка выдает ошибку, сообщая, что реквизит не заполнен, хотя текст визуально находится в поле. Если же перед нажатием кнопки тапнуть в другое поле, текст успешно считывается.
Выясним причину такого поведения. В мобильной платформе 1С передача введенного текста из элемента интерфейса (поля) в сам реквизит формы происходит только в момент потери фокуса. Обычное нажатие на экранную кнопку формы в мобильном интерфейсе не перехватывает фокус у поля ввода. Если пользователь не нажал кнопку Готово (или Enter/Done) на самой виртуальной клавиатуре устройства, фокус остается в поле, и значение не фиксируется в реквизите до начала выполнения программного кода кнопки.
Чтобы обойти этот архитектурный нюанс мобильной платформы, разберем несколько проверенных способов решения.
Способ 1: Принудительная программная смена фокуса
Самый надежный метод — заставить платформу принудительно завершить редактирование поля. Для этого в самом начале процедуры, привязанной к нажатию кнопки, мы программно переводим фокус на саму кнопку (или любой другой нейтральный элемент формы). Посмотрим на пример реализации:
&НаКлиенте
Процедура ОтправитьПисьмо(Команда)
// Принудительно забираем фокус у поля ввода
ЭтаФорма.ТекущийЭлемент = Элементы.КнопкаОтправить;
Если ТекстПисьма = "" Тогда
Сообщить("Заполните текст письма!");
Возврат;
КонецЕсли;
// Дальнейшая логика...
КонецПроцедуры
Благодаря строке с обращением к ТекущийЭлемент, платформа понимает, что ввод в предыдущее поле завершен, и моментально обновляет связанный реквизит.
Способ 2: Изменение свойства обновления текста
Рассмотрим альтернативный вариант решения через свойства самого элемента формы. В палитре свойств поля ввода найдите параметр ОбновлениеТекстаРедактирования и установите его значение в ПриВводе. В этом случае платформа будет пытаться синхронизировать текст с реквизитом по мере набора каждого отдельного символа. Однако стоит учитывать, что на слабых мобильных устройствах или при сложной логике формы это может вызывать подтормаживания интерфейса.
Вторая проблема, с которой сталкиваются мобильные разработчики — это неадекватное поведение функции Сообщить(). Иногда при вызове оповещения платформа выдает сразу по 5-10 абсолютно одинаковых сообщений за раз. Разберем по шагам, откуда берутся эти дубли.
Мобильное приложение 1С по своей внутренней архитектуре является файловой базой данных. В файловых базах существует известный баг работы с памятью и контекстом форм. Если при открытии формы (например, в обработчиках ПриСозданииНаСервере или ПриОткрытии) вы используете конструкцию Отказ = Истина, форма визуально не открывается для пользователя. Однако она не уничтожается из памяти!
Ее контекст остается «висеть» в скрытом кэше приложения. Если пользователь несколько раз попытается открыть такую форму (и каждый раз будет срабатывать отказ), в памяти накопится десяток невидимых копий этой формы. При глобальном вызове обработки оповещения, платформа транслирует команду Сообщить() на каждую из зависших форм, что и приводит к дублированию.
Проанализируем методы исправления этой ситуации, чтобы ваше мобильное приложение работало стабильно и не засоряло оперативную память устройства.
Отказ = Истина. Вместо этого позвольте форме инициализироваться и открыться, а затем программно закройте её. Вы можете вынести проверки в отдельную логику до открытия формы, либо вызывать метод ЭтаФорма.Закрыть() сразу после открытия, если условия не соблюдены.Сообщить().Рассмотрим методы, которые следует применять для взаимодействия с пользователем:
&НаКлиенте
Процедура ВывестиУведомление()
// Вместо Сообщить() используем:
ПоказатьПредупреждение(Неопределено, "Пожалуйста, заполните все обязательные поля!");
// Или более мягкий вариант:
ПоказатьОповещениеПользователя("Внимание", , "Данные успешно сохранены.");
КонецПроцедуры
Методы ПоказатьПредупреждение() и ПоказатьОповещениеПользователя() отрабатывают глобально поверх текущего активного окна и не привязываются к накопившимся в фоне скрытым контекстам форм. Это полностью исключает риск дублирования текста на экране устройства и делает интерфейс мобильного приложения гораздо более отзывчивым и профессиональным.