This media is not supported in your browser
VIEW IN TELEGRAM
Сопротивление свайпа и порог открытия — разные настройки
Строка может сдвигаться медленнее пальца, но оставаться открытой уже после небольшого сдвига. В ReanimatedSwipeable за эти ощущения отвечают разные параметры:
Направления у действий названы по стороне панели: свайп вправо открывает
В документации Gesture Handler 3.x есть параметры и методы управления. Для компонента требуется установленный Reanimated и обёртка
Строка может сдвигаться медленнее пальца, но оставаться открытой уже после небольшого сдвига. В ReanimatedSwipeable за эти ощущения отвечают разные параметры:
friction меняет движение панели относительно жеста, а leftThreshold и rightThreshold — пороги открытия.Направления у действий названы по стороне панели: свайп вправо открывает
renderLeftActions, влево — renderRightActions. На видео из документации видно, как кнопки появляются под сдвинутой строкой. Сам жест не подтверждает удаление данных, за действие отвечает callback приложения.В документации Gesture Handler 3.x есть параметры и методы управления. Для компонента требуется установленный Reanimated и обёртка
GestureHandlerRootView.👏1
Почему анализ кадров может остановить превью CameraX
Если анализатор обрабатывает кадры медленнее, чем камера их выдаёт, в CameraX выбор режима backpressure влияет и на привязанное превью.
Анализ начинается после привязки к lifecycle. Для остановки используют
Если анализатор обрабатывает кадры медленнее, чем камера их выдаёт, в CameraX выбор режима backpressure влияет и на привязанное превью.
STRATEGY_KEEP_ONLY_LATEST хранит один свежий кадр для следующей обработки. Новые кадры заменяют его, пока анализатор занят. Увеличение setImageQueueDepth() в этом режиме ничего не меняет.STRATEGY_BLOCK_PRODUCER позволяет накопить очередь заданной глубины. Когда она заполняется, блокировка затрагивает всю камеру, включая привязанное превью. Если обработать все кадры всё равно невозможно, неблокирующий режим позволяет пропускать их в анализе, сохраняя работу других use case.Анализ начинается после привязки к lifecycle. Для остановки используют
clearAnalyzer() или отвязывают ImageAnalysis.❤3
TextFieldState хранит больше, чем строку
У редактируемого поля есть текст, выделение и незавершённая композиция ввода.
Объект можно держать во ViewModel: он использует snapshot-систему Compose, а зависимостей от UI у него нет. В руководстве по полям ввода показаны
У редактируемого поля есть текст, выделение и незавершённая композиция ввода.
TextFieldState в Compose хранит их вместе и синхронизирует правки из разных источников.rememberTextFieldState() создаёт объект с сохранением и восстановлением состояния. Переданный initialText нужен при создании. Если после загрузки профиля передать другое начальное значение при рекомпозиции, уже существующее поле не обновится. Для этого нужны методы редактирования самого состояния.Объект можно держать во ViewModel: он использует snapshot-систему Compose, а зависимостей от UI у него нет. В руководстве по полям ввода показаны
edit, работа с буфером и выделением.🤝1
Проверки доступности можно встроить в Compose UI-тест
Кликабельный элемент без подписи может пройти обычный сценарий нажатия и остаться непонятным для TalkBack. Начиная с Compose 1.8.0 часть таких дефектов проверяет Accessibility Test Framework.
Подключают зависимость
В примере Android Developers тест падает из-за элемента без читаемой подписи. Эту проверку можно включить в регрессионные тесты экрана. Ручная проверка с TalkBack или Switch Access всё равно нужна: автоматические проверки покрывают лишь часть проблем доступности.
Кликабельный элемент без подписи может пройти обычный сценарий нажатия и остаться непонятным для TalkBack. Начиная с Compose 1.8.0 часть таких дефектов проверяет Accessibility Test Framework.
Подключают зависимость
ui-test-junit4-accessibility и вызывают enableAccessibilityChecks() у AndroidComposeTestRule. Затем проверки запускает действие в тесте или явный вызов tryPerformAccessibilityChecks. Проверяются в том числе подписи, контраст, размер целей нажатия и порядок обхода.В примере Android Developers тест падает из-за элемента без читаемой подписи. Эту проверку можно включить в регрессионные тесты экрана. Ручная проверка с TalkBack или Switch Access всё равно нужна: автоматические проверки покрывают лишь часть проблем доступности.
🤝1
Откуда Android берёт список языков приложения
На Android 13 / API 33 и новее язык приложения можно выбрать отдельно от языка системы. Список поддерживаемых языков необязательно вручную вести в XML.
Начиная с Android Studio Giraffe и AGP 8.1,
Перед включением проверьте локали зависимостей: их ресурсы тоже участвуют в списке. Наличие языка в библиотеке ещё не означает, что весь ваш интерфейс переведён. Автогенерация собирает конфигурацию, переводы строк она не создаёт.
В инструкции по настройке также есть выбор базовой локали. Уже созданный вручную LocaleConfig перед включением генерации нужно убрать, иначе сборка завершится ошибкой.
На Android 13 / API 33 и новее язык приложения можно выбрать отдельно от языка системы. Список поддерживаемых языков необязательно вручную вести в XML.
Начиная с Android Studio Giraffe и AGP 8.1,
generateLocaleConfig позволяет собрать LocaleConfig из ресурсов приложения и библиотек. Ссылка на него попадёт в итоговый manifest. Нужен compileSdk не ниже 33. Для более старых Android нужны отдельные API и выбор языка внутри приложения.Перед включением проверьте локали зависимостей: их ресурсы тоже участвуют в списке. Наличие языка в библиотеке ещё не означает, что весь ваш интерфейс переведён. Автогенерация собирает конфигурацию, переводы строк она не создаёт.
В инструкции по настройке также есть выбор базовой локали. Уже созданный вручную LocaleConfig перед включением генерации нужно убрать, иначе сборка завершится ошибкой.
👍2
Видимость элемента не исключает конфликт жестов
На Android 15 / API 35 и новее при target SDK 35 приложение рисует под системными панелями и вырезами экрана. Для важных элементов нужны подходящие отступы.
В Compose есть три безопасных набора WindowInsets.
Для карусели у нижнего края важны и видимость карточки, и область, в которой пользователь начинает свайп. Для неподвижной подписи задача другая — сохранить читаемость.
На Android 15 / API 35 и новее при target SDK 35 приложение рисует под системными панелями и вырезами экрана. Для важных элементов нужны подходящие отступы.
В Compose есть три безопасных набора WindowInsets.
safeDrawing защищает содержимое от визуального перекрытия системным UI. safeGestures помогает избежать конфликта жестов приложения с системными. safeContent объединяет обе защиты.Для карусели у нижнего края важны и видимость карточки, и область, в которой пользователь начинает свайп. Для неподвижной подписи задача другая — сохранить читаемость.
💯1
Размер AAB не равен размеру скачивания
Debug-сборка Flutter содержит накладные расходы для отладки и hot reload. По ней нельзя судить, сколько пользователь скачает из магазина. Размер release-пакета для загрузки в стор тоже не показывает, сколько скачает пользователь.
Магазины разделяют пакет под устройство: учитывают архитектуру процессора и плотность ресурсов. Поэтому в Android размер скачивания и установки смотрят в Play Console после загрузки AAB. В отчёте из документации базовый вариант — XXXHDPI и arm64-v8a, у других устройств размер может отличаться.
Для iOS Xcode создаёт
Сравнивать оптимизации имеет смысл на одинаковом варианте устройства и отдельно для скачивания и установки.
Debug-сборка Flutter содержит накладные расходы для отладки и hot reload. По ней нельзя судить, сколько пользователь скачает из магазина. Размер release-пакета для загрузки в стор тоже не показывает, сколько скачает пользователь.
Магазины разделяют пакет под устройство: учитывают архитектуру процессора и плотность ресурсов. Поэтому в Android размер скачивания и установки смотрят в Play Console после загрузки AAB. В отчёте из документации базовый вариант — XXXHDPI и arm64-v8a, у других устройств размер может отличаться.
Для iOS Xcode создаёт
App Thinning Size Report.txt с оценками по вариантам устройств и ОС. Точный отчёт получают после загрузки release IPA в App Store Connect.Сравнивать оптимизации имеет смысл на одинаковом варианте устройства и отдельно для скачивания и установки.
🔥1
Редко используемый экран можно загрузить позже
Flutter умеет загружать часть кода и ресурсов Android-приложения, когда они понадобились пользователю. Для большого редко используемого раздела можно настроить deferred components.
Отложенная загрузка работает в release и profile, а debug трактует такие компоненты как обычные импорты. При обновлении по-прежнему собирают и загружают целый AAB: отправлять независимые патчи таким способом нельзя.
Документация Flutter разбирает настройку модулей. Выигрыш первого скачивания зависит от того, какие код и ресурсы останутся в базовой части.
Flutter умеет загружать часть кода и ресурсов Android-приложения, когда они понадобились пользователю. Для большого редко используемого раздела можно настроить deferred components.
deferred-импорт позволяет использовать библиотеку после завершения loadLibrary(). Доставку на Android обеспечивают dynamic feature modules. Для Google Play нужны настройка SplitCompat и менеджер deferred components — одного импорта недостаточно.Отложенная загрузка работает в release и profile, а debug трактует такие компоненты как обычные импорты. При обновлении по-прежнему собирают и загружают целый AAB: отправлять независимые патчи таким способом нельзя.
Документация Flutter разбирает настройку модулей. Выигрыш первого скачивания зависит от того, какие код и ресурсы останутся в базовой части.
👍2🥱1
Тяжёлый расчёт конкурирует с отрисовкой кадра
Если CPU-работа не укладывается в промежуток между кадрами, главный isolate Flutter может задержать отрисовку. Такой расчёт можно перенести в отдельный isolate через
У isolate своя память и цикл событий. Данные передают сообщениями, поэтому нужно учитывать затраты на создание isolate и передачу объектов. Для частых повторных вычислений документация предлагает рассмотреть долгоживущий worker.
UI и
В документации Flutter изоляты рекомендуют для CPU-работы, вызывающей рывки. Само наличие асинхронной задачи ещё не повод создавать isolate.
Если CPU-работа не укладывается в промежуток между кадрами, главный isolate Flutter может задержать отрисовку. Такой расчёт можно перенести в отдельный isolate через
Isolate.run: он создаёт isolate, возвращает результат и завершает его.У isolate своя память и цикл событий. Данные передают сообщениями, поэтому нужно учитывать затраты на создание isolate и передачу объектов. Для частых повторных вычислений документация предлагает рассмотреть долгоживущий worker.
UI и
rootBundle остаются в главном isolate. Фоновые platform channels принимают ответы на запросы, но не незапрошенные события от платформы. В Flutter web compute выполняется на главном потоке, изоляты там не поддерживаются.В документации Flutter изоляты рекомендуют для CPU-работы, вызывающей рывки. Само наличие асинхронной задачи ещё не повод создавать isolate.
❤2🥱2🤝1
Flutter проверяет размер зоны нажатия по правилам платформы
В Flutter Guideline API проверки целей нажатия разделены:
В widget-тесте сначала включают semantics через
В документации Flutter есть полный тест. Такая проверка помогает заметить, например, что после изменения отступов область нажатия иконки стала слишком маленькой. Сценарий взаимодействия отдельно проверяют с VoiceOver или TalkBack.
В Flutter Guideline API проверки целей нажатия разделены:
androidTapTargetGuideline проверяет минимум 48 × 48, а iOSTapTargetGuideline — 44 × 44.В widget-тесте сначала включают semantics через
ensureSemantics(), создают экран и проверяют нужный guideline. Полученный semantics handle после работы освобождают. В том же тесте можно проверить подписи целей нажатия и контраст через labeledTapTargetGuideline и textContrastGuideline.В документации Flutter есть полный тест. Такая проверка помогает заметить, например, что после изменения отступов область нажатия иконки стала слишком маленькой. Сценарий взаимодействия отдельно проверяют с VoiceOver или TalkBack.
👍2
React Native 0.88 добавил управление осями шрифта
Для текста с переменной насыщенностью
В релизе React Native 0.88 поддержаны строковая CSS-форма и объект. У объекта ключи — четырёхсимвольные теги осей, значения — конечные числа. Ось должна существовать в выбранном шрифте: настройка не добавляет её в файл.
Для текста с переменной насыщенностью
fontVariationSettings теперь работает в Text и TextInput на Android и iOS.В релизе React Native 0.88 поддержаны строковая CSS-форма и объект. У объекта ключи — четырёхсимвольные теги осей, значения — конечные числа. Ось должна существовать в выбранном шрифте: настройка не добавляет её в файл.
👏2
Новый путь событий в React Native 0.88
В React Native 0.88 события по умолчанию проходят через W3C
Имена event props и их synthetic event objects сохраняются.
В React Native 0.88 события по умолчанию проходят через W3C
EventTarget: сначала идут к цели в фазе capture, затем всплывают. После обновления стоит проверить библиотеки, которые обращаются к внутреннему plugin registry.Имена event props и их synthetic event objects сохраняются.
onLayout по-прежнему срабатывает только на цели. Методы native refs addEventListener, removeEventListener и dispatchEvent в этом релизе доступны только в Canary.🔥2
Deep import в React Native стал ошибкой типов
После перехода на React Native 0.87 TypeScript может перестать принимать импорты из
Начать миграцию стоит с внутренних импортов и типов refs. Для refs теперь есть отдельные типы, например
Временный обход — условие
В публикации о 0.87 авторы обещали сохранить обход до 0.88 включительно. Удаление старых типов в следующем релизе они обозначили как план.
После перехода на React Native 0.87 TypeScript может перестать принимать импорты из
react-native/Libraries/*. Strict TypeScript API включён по умолчанию. Он считает публичным API только экспорты из корня react-native. Типы генерируются из исходного кода.Начать миграцию стоит с внутренних импортов и типов refs. Для refs теперь есть отдельные типы, например
ViewInstance и TextInputInstance. В описании 0.87 есть ссылки на руководство по изменениям.Временный обход — условие
react-native-legacy-deep-imports в customConditions файла tsconfig.json. Оно меняет только анализ TypeScript в вашем проекте. Приложение и его библиотеки мигрируют независимо.В публикации о 0.87 авторы обещали сохранить обход до 0.88 включительно. Удаление старых типов в следующем релизе они обозначили как план.
❤1👍1
Выбрать фото и загрузить его — два разных шага
В SwiftUI
Загрузка может вернуть изображение, пустое значение или ошибку. Например, фото из iCloud Photos может потребовать сеть, и без соединения получить данные не удастся. Состояние интерфейса должно учитывать эту загрузку после закрытия пикера.
SwiftUI
Документация PhotosPicker показывает обработку результата и отслеживание прогресса. Сам пикер доступен с iOS 16 и iPadOS 16.
В SwiftUI
PhotosPicker возвращает PhotosPickerItem — объект выбора, а не готовое изображение. Содержимое загружают отдельно через loadTransferable.Загрузка может вернуть изображение, пустое значение или ошибку. Например, фото из iCloud Photos может потребовать сеть, и без соединения получить данные не удастся. Состояние интерфейса должно учитывать эту загрузку после закрытия пикера.
SwiftUI
Image поддерживает только PNG и JPEG в своей реализации Transferable. Для других типов изображений Apple предлагает собственную модель Transferable.Документация PhotosPicker показывает обработку результата и отслеживание прогресса. Сам пикер доступен с iOS 16 и iPadOS 16.
🤝2
SharePreview убирает ожидание метаданных ссылки
При отправке URL через SwiftUI
Если передать собственный
Оба сценария разобраны в документации ShareLink. API доступен с iOS 16 и iPadOS 16. Немедленное превью не означает, что сами отправляемые данные уже подготовлены.
При отправке URL через SwiftUI
ShareLink система сначала может показать иконку ссылки и базовый адрес. Заголовок и значок появятся после загрузки метаданных по сети.Если передать собственный
SharePreview, превью отобразится сразу. Это удобно, когда у приложения уже есть название и изображение материала. Настройка касается только превью содержимого в системном меню.ShareLink работает с Transferable. Если нужного сервиса нет среди вариантов, проверьте представления данных: часть сервисов принимает файлы. Apple предлагает добавить FileRepresentation к модели.Оба сценария разобраны в документации ShareLink. API доступен с iOS 16 и iPadOS 16. Немедленное превью не означает, что сами отправляемые данные уже подготовлены.
💯1
Шторка уведомлений не меняет AppState на Android
Если в React Native слушать только событие
Для возвращения фокуса есть событие
Событие
Если в React Native слушать только событие
change, открытие шторки уведомлений на Android останется незамеченным. В этом примере из документации AppState не меняется, но приходит отдельное событие blur: пользователь больше не взаимодействует с приложением.Для возвращения фокуса есть событие
focus. Оба события относятся к Android. Перед использованием проверьте поддержку этих событий в версии React Native вашего проекта. Их можно обрабатывать отдельно от перехода в фон, например, чтобы при потере фокуса приостановить анимацию. Решение о паузе принимает само приложение, автоматически AppState ничего не останавливает.Событие
blur не сообщает, какая именно системная панель открыта. Шторка — пример из справочника AppState, а не способ распознать её. На схеме показаны два разных сигнала: состояние приложения и взаимодействие.👍2
Как URLSession возвращает события после перезапуска iOS-приложения
Фоновая
В обработчике
При force quit через экран многозадачности iOS отменяет фоновые передачи и не перезапускает приложение автоматически. Это отличается от завершения процесса системой.
Руководство Apple разбирает настройку и восстановление сессии. Метод
Фоновая
URLSession передаёт загрузку файла отдельному системному процессу. Если iOS завершила приложение, система может запустить его снова для обработки событий передачи.В обработчике
UIApplicationDelegate сначала сохраняют completionHandler, затем восстанавливают сессию с тем же identifier и делегатом. После urlSessionDidFinishEvents и обработки доставленных событий сохранённый handler вызывают на главном потоке. Этот callback говорит о доставке накопленных событий, а не о завершении всех будущих задач.При force quit через экран многозадачности iOS отменяет фоновые передачи и не перезапускает приложение автоматически. Это отличается от завершения процесса системой.
Руководство Apple разбирает настройку и восстановление сессии. Метод
background(withIdentifier:) доступен с iOS 8.👍2
This media is not supported in your browser
VIEW IN TELEGRAM
Независимые Flutter-экраны с общими ресурсами движка
При постепенной миграции приложения маршрут может чередовать нативные и Flutter-экраны. На Android и iOS для нескольких экземпляров Flutter есть
У каждого движка остаются собственные Dart-программа, интерфейс, навигация и состояние. Для обмена данными между экземплярами документация предлагает platform channels или Pigeon через нативное приложение.
Первый движок запускается с обычными затратами. Чтобы следующие продолжали разделять ресурсы, должен оставаться хотя бы один живой движок из группы. После уничтожения всех следующий снова запускается как первый.
В ролике из руководства Flutter показан пример с нативными и Flutter-экранами, включая две Flutter-области одновременно. Это демонстрация интерфейса, без замеров производительности.
Перед использованием сверьте поддержку API с версией Flutter в проекте.
При постепенной миграции приложения маршрут может чередовать нативные и Flutter-экраны. На Android и iOS для нескольких экземпляров Flutter есть
FlutterEngineGroup. Созданные им движки разделяют GPU-контекст, метрики шрифтов и snapshot группы изолятов.У каждого движка остаются собственные Dart-программа, интерфейс, навигация и состояние. Для обмена данными между экземплярами документация предлагает platform channels или Pigeon через нативное приложение.
Первый движок запускается с обычными затратами. Чтобы следующие продолжали разделять ресурсы, должен оставаться хотя бы один живой движок из группы. После уничтожения всех следующий снова запускается как первый.
В ролике из руководства Flutter показан пример с нативными и Flutter-экранами, включая две Flutter-области одновременно. Это демонстрация интерфейса, без замеров производительности.
Перед использованием сверьте поддержку API с версией Flutter в проекте.
🔥1