Від дизайну до андроїда, частина 2

З моєї попередньої публікації минуло багато часу, багато речей сталося з того часу, але нарешті тут. Сподіваюся, вам сподобається!

Це нова історія в моїй серії статей під назвою "Від дизайну до андроїда", якщо ви пам'ятаєте першу частину цієї серії, я підбираю дизайнерську концепцію, яка мені здається цікавою, і намагаюся реалізувати її на Android, орієнтуючись на деякі цікаві теми попутно з моєї точки зору розробника для Android.

Весь код, згаданий у цій публікації, можна знайти у цьому сховищі Github

Це концепція, яку я вибрав для цієї частини:

Бізнес Google - Slider від Johny Vino

Я вкотре використав концепцію, що походить від Johny Vino.

Спробуйте зупинитись на секунду, з'ясовуючи, як розробник андроїд, як ви, як зробити реалізацію цього екрана.

Якщо ви помітили два наступні моменти, ви, можливо, погодилися зі мною, на перший погляд, мені прийшли в голову дві частини:

  • Як реалізувати анімацію будівлі, звичайно.
  • Ця смуга пошуку може бути не такою тривіальною, як має бути

Анімація будівлі

Давайте покладемо цю вправу на ідеальне середовище, ми можемо попросити нашого дизайнера створити анімацію. Можливо, після роботи After Effects + плагіну Bodymovin вони можуть дати нам бажаний анімаційний вектор для малювання.

Або… у нас, можливо, взагалі немає дизайнера, і ви хоробрий і самотній розробник, який повинен зробити це без особливих дизайнерських навичок, давайте спробуємо цей шлях.

Робота з векторами

З невеликою роботою над векторним інструментом, як Sketch або BoxySvg, ми могли б легко векторизувати зображення будівлі. Групування тих частин, чиї анімовані групи будуть корисні для наступного пункту.

Створення потрібного зображення на ескізі

Далі на сцену виходить новий дивовижний інструмент, а це - Shape Shifter, від Alex Lockwood. Цей дивовижний інструмент допомагає анімувати зображення на основі SVG та експортувати ці анімації в AVD серед інших форматів.

Форма перемикача

Створивши потрібний ефект за кілька кліків, ми зможемо експортувати наш свіжий анімований вектор, який можна малювати, вставити його в Android Studio, прив’язати його до ImageView і ми закінчили!

(img_building.drawable як анімаційний) .start ()
Експортований avd ShapeFilter на Android-пристрої

Так, дивовижно, правда ?! Ми просто створили чудову анімацію без особливих зусиль, але якщо ми ще раз подивимось на концепцію Джонні Віно, ми пропустили незначну деталь. Анімація обробляється слайд-панеллю (відомою як Seekbar на Android), яка обробляє вміст анімації залежно від ходу смуги.

Отже, нам потрібно поки що встановити хід анімації в AVD. Ну ... це на даний момент не підтримується з того, що я бачив (Лотті робить). Ми просто маємо у своєму розпорядженні такі методи, як .start (), .stop () та reset ().

На даний момент ми можемо спробувати наступне:

Або продовжуйте, давайте повторимо трохи більше.

Анімовані селекторні малюнки

У нашому теперішньому пункті у нас є анімація, якій потрібно наказати перейти до певного кадру, коли SeekBar досягне певної позиції. Іншими словами, ми маємо деякі стани під час анімації.

Давайте оголосимо деякі атрибути для визначення цих кадрів або станів.

<оголосити-styleable name = "BuildingState">
    
    
    
    
    
    

У цьому пункті дозвольте мені представити, можливо, не добре відомий малюнок, AnimatedStateListDravable, який повністю врятує наш день.

Давайте звернемось до документації для Android:

Малюнок, що містить набір ключових кадрів Dravable, де поточний відображений ключовий кадр вибирається на основі поточного набору стану. Анімації між ключовими кадрами необов'язково можуть бути визначені за допомогою перехідних елементів.
Це малювання можна визначити у файлі XML з елементом . Кожен ключовий кадр Dravable визначається вкладеним елементом. Переходи визначаються вкладеним елементом.

Дещо виглядає, що ми шукаємо, правда? Ми могли б визначити деякі , які визначатимуть різні кадри в нашій анімації та переходи для переходу елемента до іншого.

Оскільки кожен тег буде представляти наш кадр, ми визначимо три з них, кожен з яких складається з векторного малюнка.

dravable / vd_building1.xml
dravable / vd_building2.xml
dravable / vd_building3.xml

І кожен <переклад> буде представляти, як переходить до іншої, нам знадобиться 4 для переходу через усі кадри вперед і назад.

За допомогою вищезгаданого Shape Shifter ми можемо легко експортувати потрібні AVD в Android Studio, які працюватимуть як переходи в AnimationStateListDravable.

dravable / avd_building_1_2
dravable / avd_building_2_3
dravable / avd_building_3_2
dravable / avd_building_2_1
avd_building_1_2.xmlavd_building_2_3.xml

І нарешті весь анімований державний драйв, який ми тільки що створили:


<анімований селектор
    xmlns: android = "http://schemas.android.com/apk/res/android"
    xmlns: app = "http://schemas.android.com/apk/res-auto"
    >

    <предмет
        android: id = "@ + id / frame_0"
        android: dravable = "@ dravable / vd_building_1"
        app: state_one = "помилково"
        app: state_two = "помилково"
        />

    <предмет
        android: id = "@ + id / frame_1"
        android: dravable = "@ dravable / vd_building_2"
        app: state_one = "вірно"
        />

    <предмет
        android: id = "@ + id / frame_2"
        android: dravable = "@ dravable / vd_building_3"
        app: state_two = "вірно"
        />

    <перехід
        android: fromId = "@ id / frame_0"
        android: toId = "@ id / frame_1"
        android: dravable = "@ dravable / avd_building_1_2"
        />

    <перехід
        android: fromId = "@ id / frame_1"
        android: toId = "@ id / frame_2"
        android: dravable = "@ dravable / avd_building_2_3"
        />

    <перехід
        android: fromId = "@ id / frame_2"
        android: toId = "@ id / frame_1"
        android: dravable = "@ dravable / avd_building_3_2"
        />

    <перехід
        android: fromId = "@ id / frame_1"
        android: toId = "@ id / frame_0"
        android: dravable = "@ dravable / avd_building_2_1"
        />

Трохи налаштувавши нашу активність та макет, ми встановили цей дивовижний AnimatedSelectorDravable в ImageView як вихідний ресурс, і використовуючи метод setImageState з потрібним станом, анімація буде працювати магічно, як очікувалося.

приватний val STATE_ZERO = intArrayOf (
        R.attr.state_zero, -R.attr.state_one, -R.attr.state_two
)

приватний val STATE_ONE = intArrayOf (
        -R.attr.state_zero, R.attr.state_one, -R.attr.state_two
)

приватний val STATE_TWO = intArrayOf (
        -R.attr.state_zero, -R.attr.state_one, R.attr.state_two
)
приватні розваги onSeekProgressChanged (позиція: Int) {
    val max = tražibar.max

    val businessType = коли (позиція) {
        в 0..max / 3 -> STATE_ZERO
        в 10..max / 2 -> STATE_ONE
        через 20..max / 1 -> STATE_TWO
        else -> кинути IllegalStateException ()
    }

    imageView.setImageState (businessType, true)
}

Результат:

Анімація великого пальця шукача

Яй! Поки ми дійшли до однієї з двох моїх гарячих точок, у другій - вдається реалізовувати розмір великого пальця Seekbar під час прогресу, як це робить Джонні Віно у своїй концепції:

Розмір великого пальця панелі пошуку при перетягуванні

Тут можна виділити дві форми поведінки:

  • Розмір великого пальця збільшується певним чином, пов'язаним з прогресом
  • Під час випуску виконується якась анімація з видаленням

Візит до ScaleDrawable

Інший невідомий малюнок (принаймні для мене) - це ScaleDravable, давайте ще раз переглянемо документацію на android:

Малюнок, який змінює розмір іншого Dravable на основі його поточного значення. Ви можете керувати, наскільки дитина може змінювати ширину та висоту залежно від рівня, а також сила тяжіння, щоб контролювати, де вона розміщена в загальній ємності. Найчастіше застосовується для реалізації таких речей, як бари прогресу.
Рівень за умовчанням може бути визначений у XML за допомогою властивості android: level. Якщо ця властивість не вказана, рівень за замовчуванням дорівнює 0, що відповідає нульовій висоті та / або ширині залежно від значень, визначених для android.R.styleable # ScaleDravable_scaleWidth scaleWidthand android.R.styleable # ScaleDravable_scaleHeight scaleHeight. Під час виконання рівень може бути встановлений через setLevel (int).

Отже, здається, що ми могли б визначити якийсь тип малювання, який буде позначати інший рисунок, рівень та масштабний фактор. Якщо ми приєднаємо прогрес планки до цього рівня, він повинен працювати, правда?

Давайте визначимо перелік шарів, що малюються, і, оскільки ми хочемо лише змінити синю частину, ми перетворимо її в ScaleDravable.


<шар-список xmlns: tools = "http://schemas.android.com/tools"
    xmlns: android = "http://schemas.android.com/apk/res/android"
    xmlns: aapt = "http://schemas.android.com/aapt">
    
        <масштаб
            android: scaleWidth = "30%"
            android: scaleHeight = "30%"
            android: scaleGravity = "центр"
            android: level = "1"
            інструменти: ignore = "UnusedAttribute">

            
              <форма android: shape = "oval">
                  <розмір
                      android: width = "70dp"
                      android: height = "70dp" />

                  <твердий андроїд: color = "@ color / blue_accent_200" />
              
            
        
    
    <предмет
        android: left = "25dp"
        android: top = "25dp"
        android: right = "25dp"
        android: bottom = "25dp">
        <форма android: shape = "oval">
            <твердий андроїд: color = "# FFF" />
        
    

Як ви бачите, використовуючи інструмент , ми можемо вбудувати необхідні атрибути прямо в

thumb <layer-list>, що містить програму ScaleDravable

Тепер нам залишається лише знову налаштувати нашу діяльність, щоб встановити рівень ScaleDravable, саме тоді, коли хід SeekBar змінюється, помічайте також, що приємно, що ми можемо використовувати властивість рівня з програми Dravable of the thumb.

приватні розваги onSeekProgressChanged (позиція: Int) {
    // ...
    
    ((searchbar.thumb як LayerDravable)). рівень =
            (позиція * (SCALE_MAX / searchbar.max))
}

І результат:

Тепер нам просто потрібно оживити великий палець, коли випускати, ми можемо позбутися цього, використовуючи ScaleDrawable та ValueAnimator.

приватне задоволення animateThumbRelease () {
    валь великий палець = searchbar.thumb
    val initLevel = thumb.level
    val maxLevel = thumb.level * THUMB_RELEASE_SCALE_FACTOR
    val animator = ValueAnimator.ofInt (
            initLevel, maxLevel, initLevel)

    з (аніматор) {
        інтерполятор = НАДНІШИЙ
        тривалість = THUMB_SCALE_DURATION

        addUpdateListener {
            thumb.level = it.animatedValue як Int
        }

        start ()
    }
}

Результат:

Підведенню

На даний момент ми вирішили проблему з анімацією, а після цього - з панеллю пошуку, з ще кількома тривіальними модифікаціями як створення AVD для рухомих хмар, використовуючи новий шрифт як ресурс для наших текстів, і додаючи свіжа нова адаптивна ікона, у нас є щось досить схоже на концепцію Джонні Віно.

Сподіваюся, вам сподобалось під час дороги, і якщо вам доведеться вбити мене через щось, будь ласка, зробіть це з приємним коментарем та агресивними емоджими.

Кінцевий результат:

Сховище Github

тут

Список літератури

  • VectorDravable адаптивних іконок, озеро Ян
  • Дизайн адаптивних іконок, Нік Різник
  • Форма Шіфтера, Алекс Локвуд
  • Вступ в методики анімаційних іконок, Алекс Локвуд
  • adp-delightful-деталі, Алекс Локвуд
  • Як ми розробляємо прекрасну анімацію, Джеремі Мартінес