Android 12. Splash Screen API. Делаем анимированный экран загрузки

Всем привет!

Сплеш-скрин (также известный как экран загрузки) — неотъемлемая часть приложения, когда оно разрастается так, что холодный старт начинает занимать какое-то ощутимое время. До недавнего обновления сплеш-скрин реализовывался двумя основными способами:

  1. Через атрибут темы windowBackground

  2. Через отдельную Activity

Первый подход является более оптимальным, т.к. не расходует лишних ресурсов на создание и манипуляции с отдельной активити. Однако с первым подходом нет возможности использовать анимации — картинка, помещаемая в windowBackground, должна быть статичной.

На помощь нам с выходом Android 12 разработчики предоставили новую API для создания сплеш-скринов.

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

Ожидаемый результат

При старте приложения у нас происходит небольшая подгрузка изначальных данных, поэтому одновременно функцией сплешскрина должна быть и индикация загрузки. Лучше всего для этого подходит старый добрый спиннер (или лоудинг индикатор). Для этого удобнее всего закрутить логотип BestDoctor (среди сотрудников компании известный как АГРЕССИВНЫЙ КРОВАВЫЙ ЁЖ).

Вот такой сплешскрин хотим получить в результате:

image-loader.svg

Приступаем к реализации

Следуя официальной доке, реализовать новый сплеш-скрин можно двумя способами:

  1. Через атрибуты общей темы приложения

  2. Через compat-библиотеку

Разница этих двух методов в том, что первый работает только для Android 12+, а второй сделает такой же сплшскрин для старых версий.

ВАЖНО: анимированную картинку возможно использовать только на Android 12+, т.е. даже при использовании компат-библиотеки на предыдущих версиях все равно будет статичная картинка.

Т.к. наш сплеш-скрин должен заменить индикацию загрузки, нам критично важна анимация, поэтому мы будем реализовывать сплеш-скрин через атрибуты общей темы только для Android 12+; для старых версий оставим наш старый сплеш.
Приступим.

Начнем со статичной картинки с бэкграундом. Добавляем нужные атрибуты в тему приложения.

@color/splashscreen_background
@drawable/ic_splashscreen_logo

В качестве картинки используем векторный логотип BestDoctor:


    

Запускаем приложение и получаем вот такой отстой:

image-loader.svg

Лого как-то непонятно растянулось, нам такое не подходит. Начинаем разбираться в проблеме.

Переходим в раздел официальной документации по размеру картинки и находим вот такой текст:

The splash screen icon uses the same specifications as Adaptive icons, as follows:

* Branded image: This should be 200×80 dp.
* App icon with an icon background: This should be 240×240 dp, and fit within a circle of 160 dp in diameter.
* App icon without an icon background: This should be 288×288 dp, and fit within a circle of 192 dp in diameter.

For example, if the full size of an image is 300×300 dp, the icon needs to fit within a circle with a diameter of 200 dp. Everything outside the circle will be invisible (masked).

Что все это значит:
В Android 12 при запуске приложения по дефолту в качестве сплеш-скрин картинки используется иконка приложения. Собственно, для той картинки, которую мы хотим использовать явно, используется те же спецификации, что и для адаптивных иконок. Мы используем картинку без бэкграунда (без бэкграунда именно картинки, а не самого экрана), поэтому, судя по доке, наша картинка должна быть размера 192×192 dp. Окей. Обновим наш вектор, установив атрибуты viewportWidth и viewportHeight. Также придется завернуть весь наш вектор в group и добавить translate, чтобы в увеличенном viewport разместиться по центру.
Получаем:


    
        
    

Запускаем приложение:

image-loader.svg

Ура! Картинку больше не размазывает, размер правильный. Двигаемся дальше.

Анимация кручения

Splash Screen API поддерживает использование AnimationDrawable и AnimatedVectorDrawable — воспользуемся же этой возможностью!

  1. Внесем изменения в код нашего вектора: добавим атрибуты name (идентификатор group нашего вектора, нужен для обращения к нему) и pivotX, pivotY (координаты точки вращения, в нашем случае — центр картинки).


    
        
    
  1. В res/animator добавляем аниматор кручения:

Обратите внимание, что здесь duration="1500" (время, за которое картинка совершает полный оборот на 360 градусов), repeatCount="-1" (бесконечный повтор анимации), мы к этому еще вернемся.

  1. В res/drawable добавляем ic_splashscreen_logo_animated. В target.name указываем имя группы, в которую завернут path всего нашего вектора.


    
  1. И наконец добавляем нужные атрибуты темы (заменив ссылку с обычной иконки на анимированную):

@color/splashscreen_background
@drawable/ic_splashscreen_logo_animated
1500

Обратите внимание, что в windowSplashScreenAnimationDuration указаны те же самые 1500, что в animator, т.е. мы хотим, чтобы лого совершало один полный оборот за 1500 миллисекунд.
Запускам и получаем вот такое:

image-loader.svg

Хммм… Проблемка: лого делает один оборот и останавливается, хотя загрузка у нас еще не завершилась.

В атрибутах темы отсутствует что-то, отвечающее за повтор анимации, хотя в нашем animator установлен repeatCount="-1". Что ж, будем чинить это дерзким хаком.

  1. В animator оставляем желаемое время одного цикла анимации.

  2. В windowSplashScreenAnimationDuration вместо времени одного цикла анимации подставляем Integer.MAX_VALUE, то есть 2147483647. Если загрузка не будет занимать 25 дней, то пользователи никогда и не заметят, что анимация закончилась.

Обновленные атрибуты темы выглядят вот так:

@color/splashscreen_background
@drawable/ic_splashscreen_logo_animated
2147483647

Запускаем и получаем ожидаемый результат, ура!

image-loader.svg

Брендинг

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

Добавляем нужный атрибут темы с векторной картинкой:

@drawable/ic_splashscreen_branding

Запускаем и получаем вот эту кашу:

image-loader.svg

Немножко погуглив, я нашел легкий обход этой проблемы:

  1. В res/drawable добавляем ic_splashscreen_branding_centered:


    
  1. Меняем в теме ссылку на отцентрированную картинку:

@drawable/ic_splashscreen_branding_centered

Вуаля: картинка стала нормальной :)

image-loader.svg

Что ж, вот мы и получили ожидаемый результат! Такой сплешскрин мы держим на экране до окончания изначальной загрузки данных. Как это сделать, описано в официальной доке.

Большое спасибо за внимание!

© Habrahabr.ru