UI
https://m3.material.io/ | Material3 |
https://m2.material.io/design/color/the-color-system.html | Material2 Color system |
https://fonts.google.com/ | Google Fonts |
https://fonts.google.com/icons | Google Icons |
https://pictogrammers.com/library/mdi/ | Material Design Icons |
https://www.color-name.com/hex | Name a Color |
https://icon.kitchen/ | App Icon Generator |
https://romannurik.github.io/AndroidAssetStudio/icons-app-shortcut.html | App Shortcut Icon Generator |
https://mockuphone.com/ | Screenshots Device Mockups Generator |
Единицы измерения
dp | Density-independent pixels. Независимые от разрешения пиксели. Используются, чтобы элементы сохраняли размер независимо от разрешения экрана. 1 dp = 160 px (базовая плотность). |
sp | Scalable pixels. Используется для определения размеров текста. Не следует использовать для размеров макета. По умолчанию sp имеет тот же размер, что и dp, но изменяется в зависимости от настроек текста пользователя. |
nodpi | Ресурсы для всех разрешений экранов. Система не масштабирует ресурсы, помеченные этим квалификатором, независимо от текущей плотности экрана. |
anydpi | Эти ресурсы имеют приоритет выше, чем у квалификаторов конкретной плотности экрана. Как правило используются для векторных картинок. |
Слои
Layer List
LayerDrawable - drawable, который управляет массивом других drawables. Каждый drawable ресуется порядке списка, последнее рисуется сверху.
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/drawable_resource"
android:id="@id/resource_name"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension" />
<item
android:top="20dp"
android:left="20dp">
<bitmap
android:src="@drawable/android_blue"
android:gravity="center" />
</item>
</layer-list>
State List
StateListDrawable — drawable, определенный в XML, который использует несколько разных изображений для представления одной и той же графики в зависимости от состояния объекта.
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="@drawable/button_pressed" /> <!-- pressed -->
<item
android:state_focused="true"
android:drawable="@drawable/button_focused" /> <!-- focused -->
<item
android:state_hovered="true"
android:drawable="@drawable/button_focused" /> <!-- hovered -->
<item
android:drawable="@drawable/button_normal" /> <!-- default -->
</selector>
Level list
An XML file that defines a drawable that manages a number of alternate Drawables, each assigned a maximum numerical value. Creates a LevelListDrawable.
<level-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/status_off"
android:maxLevel="0" />
<item
android:drawable="@drawable/status_on"
android:maxLevel="1" />
</level-list>
Bitmap
Растровое цифровое изображение, состоящее из матрицы точек. Каждая точка соответствует отдельному пикселю на дисплее. Каждой точке может быть присвоен цвет.
9-Patch
Растровые изображения, размер которых автоматически изменяется в соответствии с содержимым представления и размером экрана. Выбранные части изображения масштабируются по горизонтали или вертикали на основе индикаторов, нарисованных внутри изображения.
Density
Плотность экрана - характеристика устройства, отражающая количество пикселей на физической площади экрана. В Android используется сокращение DPI (dot per inch). Экраны должны быть сверстаны так, чтобы размеры элементов выглядели одинаково на экранах с разной плотностью пикселей.
Server-Driven UI
SDUI. Подход для динамичного и гибкого пользовательского интерфейса, когда сервер посредством API сообщает приложению, какие компоненты и с каким контентом отображать.
Plurals
Для русских строк корректно будет работать только если в системе установлен русский язык.
LayoutInflater
Используется для преобразования XML-файлов разметки в соответствующие объекты View
.
// Получаем LayoutInflater из контекста
val inflater = LayoutInflater.from(context)
// Используем inflater для создания View из XML
val view = inflater.inflate(R.layout.custom_view_layout, null)
attachToRoot
Если вы используете LayoutInflater в производительном коде, например, в адаптерах RecyclerView
, рекомендуется использовать метод inflate с параметром attachToRoot = false, чтобы избежать лишних операций и улучшить производительность.
val view = LayoutInflater.from(context).inflate(R.layout.my_layout, rootView, attachToRoot = true)
AsyncLayoutInflater
Позволяет асинхронно инфлейтить XML-разметку. Это полезно для улучшения производительности и избегания блокировки основного потока приложения при создании сложных или ресурсозатратных пользовательских интерфейсов. Выполняется в фоновом потоке.
AsyncLayoutInflater(context).inflate(R.layout.my_layout, null) { inflatedView, _, _ ->
// Этот блок кода выполняется после завершения инфлейтации
// Вы можете использовать inflatedView для дальнейших операций
}
Choreographer
Класс, который помогает синхронизировать обновления экрана и анимации с частотой обновления экрана (refresh rate). Он играет ключевую роль в обеспечении плавности анимаций и поддержке высокой производительности пользовательского интерфейса.
• Синхронизация с частотой обновления экрана. Choreographer обеспечивает, чтобы обновления и отрисовка экрана происходили синхронно с частотой обновления экрана, что помогает избегать мерцания и улучшает плавность анимаций.
• Планирование и обработка кадров. Класс управляет планированием и обработкой кадров в цикле отображения. Он гарантирует, что обновления пользовательского интерфейса и отрисовка происходят в нужное время.
• Методы для добавления задач. Choreographer предоставляет методы для добавления задач, которые будут выполняться до или после обновления экрана.
postFrameCallback
Позволяет добавить FrameCallback, который будет вызван перед следующим обновлением экрана. Это полезно для выполнения задач, которые должны быть синхронизированы с кадровой частотой, например, обновление анимаций.
Choreographer.getInstance().postFrameCallback(object: Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
// Ваш код для обновления UI
Choreographer.getInstance().postFrameCallback(this) // Повторное добавление
}
})
postCallback
Позволяет добавить Runnable (или Callback) для выполнения задачи в заданный момент времени, например, после обновления экрана.
Choreographer.getInstance().postCallback(
Choreographer.CALLBACK_ANIMATION,
Runnable {
// Ваш код для выполнения после обновления экрана
},
null
)
RenderThread
Новый системно-управляемый поток обработки обеспечивает плавность анимации даже при наличии задержек в основном потоке пользовательского интерфейса. Работает асинхронно. Выполняет рендеринг onDraw
в то время как UI Thread выполняет onMeasure
и onLayout
. Приводит к плавному FPS.
• появился в Android 5.0.
Animations
ValueAnimator
Представляет механизм для запуска анимаций вычисления анимированных значений и установки их для целевых объектов.
ObjectAnimator
Наследуется от ValueAnimator. Обеспечивает поддержку анимации свойств целевых объектов. Анимации можно создавать из кода и XML.
ViewPropertyAnimator
Вызывается через View.animate
. Подходит для выполнения нескольких анимаций одновременно.
С какой частотой должен отрисовываться UI?
Чтобы сделать приложение плавным - нужно отрисовывать кадры менее чем за 16 мс для 60 кадров в секунду (FPS). 11 мс для 90 FPS. 8 мс для 120 FPS. Если приложение медленно отрисовывает UI - система будет пропускать кадры и юзер ощутит заикание интерфейса (jank).
• на любом телефона идет постоянная перерисовка экрана (герцовка).
• если кадр не успевает отрисоваться - он просто пропускается и готовится следующий. Это выглядит как лаг. В консоли пишется DROP_FRAME_BUFFER.
• иногда GPU рисует быстрее, чем может экран. Для этого в телефоне есть V-SYNC, чтобы кадры готовились ровно в тот промежуток, который нужен. Отвечает за это класс Choreographer
(дирижер).
• если кадр не изменился - он берется из специального буффера (Frame Buffer).
HEX-Colors Opacity
HEX | Opacity |
---|---|
100% | FF |
99% | FC |
98% | FA |
97% | F7 |
96% | F5 |
95% | F2 |
94% | F0 |
93% | ED |
92% | EB |
91% | E8 |
90% | E6 |
89% | E3 |
88% | E0 |
87% | DE |
86% | DB |
85% | D9 |
84% | D6 |
83% | D4 |
82% | D1 |
81% | CF |
80% | CC |
79% | C9 |
78% | C7 |
77% | C4 |
76% | C2 |
75% | BF |
74% | BD |
73% | BA |
72% | B8 |
71% | B5 |
70% | B3 |
69% | B0 |
68% | AD |
67% | AB |
66% | A8 |
65% | A6 |
64% | A3 |
63% | A1 |
62% | 9E |
61% | 9C |
60% | 99 |
59% | 96 |
58% | 94 |
57% | 91 |
56% | 8F |
55% | 8C |
54% | 8A |
53% | 87 |
52% | 85 |
51% | 82 |
50% | 80 |
49% | 7D |
48% | 7A |
47% | 78 |
46% | 75 |
45% | 73 |
44% | 70 |
43% | 6E |
42% | 6B |
41% | 69 |
40% | 66 |
39% | 63 |
38% | 61 |
37% | 5E |
36% | 5C |
35% | 59 |
34% | 57 |
33% | 54 |
32% | 52 |
31% | 4F |
30% | 4D |
29% | 4A |
28% | 47 |
27% | 45 |
26% | 42 |
25% | 40 |
24% | 3D |
23% | 3B |
22% | 38 |
21% | 36 |
20% | 33 |
19% | 30 |
18% | 2E |
17% | 2B |
16% | 29 |
15% | 26 |
14% | 24 |
13% | 21 |
12% | 1F |
11% | 1C |
10% | 1A |
9% | 17 |
8% | 14 |
7% | 12 |
6% | 0F |
5% | 0D |
4% | 0A |
3% | 08 |
2% | 05 |
1% | 03 |
0% | 00 |
Android UI. Вопросы на собесе
- C какой частотой должен отрисовываться UI?
- Что такое RenderThread?
- Как оптимизировать UI?
• Не рисовать фон в xml. устанавливать его в
windowBackground
.• Задавать размеры
View
если они известны чтобы не тратить ресурсы на измерение.