Flutter
April 30, 2021

Приборкуємо Icon: як він працює зсередини?

У даній статті ми розглянемо віджет Icon, а також розкажемо про лайфхак, завдяки якому значення для піктограми можна задавати динамічно: наприклад, передавати з сервера.

Також ми переклали цю статтю англійською

Віджет Icon

У Material Framework, що входить до Flutter, є віджет Icon. Даний віджет використовується, щоб відобразити яку-небудь піктограму. Його відмінність від віджету Image у тому, що даний віджет підпорядковується встановленій темі та може бути інтегрований з віджетом, у якому він використовується (наприклад, піктограма відповідно змінює свій колір у віджеті IconButton).

Розглянемо, які параметри приймає даний віджет:

Приклад роботи віджету Icon

Наведений приклад виводить піктограму з колекції Material Icons. Розберемо параметри:

  • Перший позиційний параметр: значення типу IconData. Його ми розглянемо нижче
  • Непозиційний параметр color: значення типу Color щоб, відповідно, перефарбувати піктограму
  • Непозиційний параметр size: дійсне число, розмір піктограми у пікселях

Віджет ImageIcon

Даний віджет дозволяє використовувати растрові зображення для простого створення власних піктограм:

Приклад роботи віджету ImageIcon

Синтаксис аналогічний до Icon, окрім того, що у перший позиційний параметр передається об'єкт типу ImageProvider. ImageProvider це об'єкт у Flutter, що відповідає за отримання зображення іншими віджетами. Наприклад, віджетом Image.

Скоріш за все, ви ніколи не працюватимете з ImageProvider напряму, натомість, ви будете використовувати одну з готових реалізацій:

У даному прикладі використовується зображення-асет.

Слід зазначити, що кольорові піктограми будуть приведені до монохромного вигляду за каналом прозорості:

Зміна кольору у ImageIcon

Колекція Icons та CupertinoIcons

Дані класи містять у собі колекції піктограм для Material Design та iOS відповідно. Слід зазначити, що між собою дані колекції не сумісні: якщо ви розробляєте такий застосунок, що використовує Material Icons на Android, а Cupertino — на iOS, вам доведеться власноруч вказувати відповідну піктограму, або, наприклад, скористатись бібліотекою flutter_platform_widgets, яка пропонує обмежений список піктограм, що відповідають одна одній.

Список усіх піктограм для Material Design знаходиться на сторінці Material Icons. Кожна піктограма представлена у чотирьох стилях: звичайний, Rounded, Sharp та Outline. Щоб звернутися до необхідного стилю, слід додати до назви піктограми відповідне закінчення:

Використання різних стилів для піктограм

Список усіх наявних Cupertino Icons наведено на сторінці бібліотеки.

Піктограми та теми

Усі компоненти Material Framework підпорядковуються заданій темі. Тема задається у віджеті MaterialApp, завдяки об'єкту ThemeData та властивості theme.

Ви можете глобально змінити стиль за замовчуванням для усіх піктограм у вашому застосунку, використовуючи властивість iconTheme у ThemeData:

Приклад використання теми для задання стилю піктограм

Але крім цього, тему можна перезаписати безпосередньо у дереві віджетів, використовуючи віджет IconTheme (варто помітити, при цьому на перезаписану піктограму властивості теми діяти припиняють):

Приклад локального перезапису теми піктограми

Як працюють векторні піктограми

У Flutter для роботи векторних піктограм використовуються так звані icon fonts, тобто шрифти, що використовують символи для виводу піктограм. Насправді, коли ви використовуєте віджет Icon, Flutter створює віджет Text з спеціально заданим шрифтом. Ми переконаємося у цьому далі.

Тип IconData

IconData виступає контейнером для даних піктограми, що має бути виведено. Саме об'єкти цього типу зберігаються у колекції Icons: наприклад, Icons.people є об'єктом IconData. Давайте розглянемо конструктор цього об'єкта:

Конструктор IconData — саме так зберігаються піктограми у колекції Icons

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

Параметр fontFamily містить назву шрифта, що використовується для виводу піктограми.

Таким чином, вивід піктограми зводиться до віджету Text (\ue8f5 - позначення символу під номером e8f5):

Аналог віджету Icon, реалізований на Text

Крім того ж, у поле тексту можна помістити читабельну назву піктограми:

Замінюємо '\ue8f5' на 'people' — віджет продовжує функціонувати

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

Динамічні піктограми й інтеграція з Material Framework

❗ Робіть зазначене нижче тільки якщо вам дійсно це треба. Дана практика шкодить розміру застосунку. Замість цього, ви можете, наприклад, завантажувати піктограму з мережі через NetworkImage та використовувати ImageIcon.

Таким чином можна зробити висновок, що використовуючи віджет Text можна відобразити піктограму за її кодом або навіть назвою. Проте, у такого підходу є суттєвий недолік: відсутність інтеграції з темою та Material Framework у цілому, адже Flutter сприймає таку піктограму як звичайний текст. Тому, ми напишемо власний об'єкт Icon, що не є константою, та який приймає назву піктограми для її відображення (див. кінець статті).

Використання:

Приклад використання DynamicIcon

Увага, через те, що конструктор не константний, tree shaking не працюватиме, що призведе до помилки компіляції, але дану поведінку можна виключили прапорцем збирання --no-tree-shake-icons.

Приєднуйтесь до нашого чату.

Віджет DynamicIcon