В процессе разработки мобильных приложений на платформе 1С программисты часто сталкиваются с поведением интерфейса, которое кардинально отличается от привычной десктопной версии. Типичный сценарий: в приложении последовательно открывается цепочка окон — Форма1 → Форма2 → Форма3. При этом предыдущие формы остаются открытыми в оперативной памяти. Перед разработчиком встает задача: как, находясь на активной Форма3, переключить фокус обратно на Форма2, не закрывая при этом текущую Форма3?
Настольная версия 1С решает эту задачу элементарно — например, через вызов метода ПолучитьОкна(), поиск нужного объекта ОкноКлиентскогоПриложения и последующий вызов метода Активизировать(). Однако в мобильной среде этот трюк не срабатывает. Давайте подробно разберем, почему возникает это ограничение и какие архитектурные обходные пути существуют в мобильной платформе 1С.
Проанализируем ситуацию детально, разберем причины ограничений операционных систем и рассмотрим несколько эффективных практических приемов обхода этой проблемы.
Поведение платформы напрямую продиктовано ограничениями мобильных операционных систем (Android и iOS) и спецификой их графических подсистем:
ПолучитьОкна() доступны в мобильном клиенте и мобильном приложении, вызов Активизировать() у окна фоновой формы просто игнорируется платформой. Мобильный движок 1С физически не может "вытащить" фоновое окно на передний план, не изменив структуру стека окон.Поскольку напрямую активизировать форму из глубины стека невозможно, рассмотрим рабочие альтернативные варианты, которые позволяют решить исходную бизнес-задачу.
Вместо реального открытия нескольких физических окон программно имитируют переходы внутри одной-единственной формы. Для этого интерфейс формы разбивается на логические шаги (группы элементов), видимость которых переключается программно. Для пользователя это выглядит как полноценное открытие новых экранов, но для платформы форма остается одной и той же.
Рассмотрим по шагам реализацию этого механизма:
ГруппаШаг1, ГруппаШаг2, ГруппаШаг3).Посмотрим на пример кода, управляющего видимостью шагов:
&НаКлиенте
Процедура ПерейтиНаСледующийШаг()
// Скрываем текущий шаг (аналог Формы 2)
Элементы.ГруппаШаг2.Видимость = Ложь;
// Отображаем новый шаг (аналог Формы 3)
Элементы.ГруппаШаг3.Видимость = Истина;
// При необходимости фокус ввода можно перевести на конкретный элемент нового шага
ТекущийЭлемент = Элементы.ПолеВводаШаг3;
КонецПроцедуры
&НаКлиенте
Процедура ВернутьсяНазад()
// Возвращаемся обратно на предыдущий шаг без потери данных
Элементы.ГруппаШаг3.Видимость = Ложь;
Элементы.ГруппаШаг2.Видимость = Истина;
КонецПроцедуры
Этот подход гарантирует мгновенный отклик интерфейса, исключает конфликты со стеком операционной системы и позволяет легко сохранять контекст данных, так как все реквизиты находятся на одной форме.
Этот способ является разновидностью предыдущего метода, но использует стандартный элемент управления платформы 1С — Панель со страницами. Чтобы интерфейс выглядел нативно на мобильном устройстве, у группы страниц отключают отображение закладок (свойство ОтображениеЗакладок устанавливают в значение Не использовать).
Разберем по шагам управление страницами:
Страницы и назовем её ПанельШагов.Страница1, Страница2, Страница3.ТекущаяСтраница.Пример переключения страниц:
&НаКлиенте
Процедура АктивизироватьСтраницу2()
// Прямой переход на нужную страницу без закрытия остальных данных
Элементы.ПанельШагов.ТекущаяСтраница = Элементы.Страница2;
КонецПроцедуры
Данный лайфхак очень популярен в мобильной разработке, так как позволяет логически разделять интерфейсы и избегать "прыжков" по окнам ОС.
Если бизнес-логика требует, чтобы Форма3 оставалась открытой на экране, но при этом необходимо обновить состояние или выполнить расчеты в скрытой Форма2, мы можем организовать их программное взаимодействие. Скрытая форма в мобильном приложении продолжает жить в стеке и способна принимать программные сигналы.
Для реализации этого сценария используется глобальный механизм оповещений 1С:
Форма3 при наступлении определенных событий вызывается метод Оповестить().Форма2 настраивается обработчик события ОбработкаОповещения, который отлавливает сигналы и обновляет экранные данные в фоновом режиме. Когда пользователь закроет Форма3, перед ним появится уже полностью обновленная Форма2.Рассмотрим пример кода отправки оповещения из активной Форма3:
&НаКлиенте
Процедура ВнестиИзмененияИОповестить()
ПараметрыСобытия = Новый Структура;
ПараметрыСобытия.Вставить("ИдентификаторОбъекта", Объект.Ссылка);
ПараметрыСобытия.Вставить("НовоеЗначение", Элементы.ПолеРеквизита.ТекстРедактирования);
// Посылаем глобальное оповещение всем открытым формам
Оповестить("ИзменениеДанныхФормы3", ПараметрыСобытия, ЭтаФорма);
КонецПроцедуры
Теперь опишем прием оповещения в скрытой Форма2:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
// Проверяем, наше ли это событие
Если ИмяСобытия = "ИзменениеДанныхФормы3" Тогда
// Анализируем переданные данные и обновляем реквизиты фоновой формы
Если Параметр.ИдентификаторОбъекта = Объект.Ссылка Тогда
Объект.ДополнительныйПараметр = Параметр.НовоеЗначение;
// Если требуется обновить динамические списки или прочитать данные из БД:
// ЭтаФорма.Прочитать();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если визуальное возвращение на Форма2 является обязательным шагом для продолжения работы пользователя, то правильным решением будет не "перескакивать" фокусом, а штатно закрыть Форма3 с передачей результатов ее работы в Форма2.
Для этого используется механизм описания оповещения о закрытии. Разберем его реализацию:
При вызове Форма3 из Форма2 мы передаем специальный объект обратного вызова:
&НаКлиенте
Процедура ОткрытьТретьюФорму()
// Указываем процедуру-обработчик, которая выполнится на Форме 2 после закрытия Формы 3
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗакрытияФормы3", ЭтаФорма);
ОткрытьФорму("ОбщаяФорма.Форма3", , ЭтаФорма, , , , ОписаниеОповещения);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияФормы3(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
Если РезультатЗакрытия <> Неопределено Тогда
// Обрабатываем возвращенные данные
Объект.РезультатВыбора = РезультатЗакрытия.ЗначениеВыбора;
Модифицированность = Истина;
КонецЕсли;
КонецПроцедуры
В модуле самой Форма3 при завершении работы вызываем закрытие с передачей структуры данных:
&НаКлиенте
Процедура ЗавершитьРаботуИВернуться()
СтруктураРезультата = Новый Структура("ЗначениеВыбора", Элементы.ПолеВводаРезультата.Значение);
// Закрываем форму и автоматически передаем фокус на Форму 2
Закрыть(СтруктураРезультата);
КонецПроцедуры
Этот способ является наиболее стандартным и идеологически верным с точки зрения разработчиков платформы 1С. Он минимизирует потребление оперативной памяти мобильного устройства и предотвращает переполнение стека вызовов.
При необходимости передавать между скрытыми и активными экранами тяжелые структуры данных, таблицы значений или двоичные данные (например, фотографии с камеры устройства), рекомендуется использовать ВременноеХранилище. При переходе на новые шаги или формы передается только текстовый уникальный адрес во временном хранилище, откуда фоновая форма считывает актуальное состояние при активации или получении оповещения.
Подведем итог. Физически перемещать фокус ("прыгать") между открытыми окнами в мобильном приложении 1С без закрытия верхнего окна невозможно из-за ограничений мобильных ОС. Наилучшим выходом для сохранения плавности работы интерфейса является проектирование логики приложения в рамках единой физической формы с использованием динамических групп видимости или страниц, а для раздельных форм — использование штатного механизма оповещений и закрытия окон с передачей параметров.