Прямые ссылки на публичные уроки для быстрого старта и стабильной индексации lesson-страниц.
Будем верстать экран по дизайн-макету, доступному по ссылке.
Figma — наиболее популярный инструмент для дизайна сайтов и мобильных приложений. Он векторный, браузерный, поддерживает совместную работу команд, а также имеет десктопное приложение.
Файл дизайна LearnEnglishWordsApp содержит набор страниц на панели слева. Каждая страница содержит фреймы — при дизайне мобильных приложений фрейм, как правило, соответствует одному состоянию экрана. На фрейме размещаются линии, фигуры, тексты и картинки. При клике на элемент его свойства отображаются на панели справа.
Начнём с экрана изучения конкретного слова. Для вёрстки нужно освоить 4 навыка:
Начнём с иконки закрытия экрана. В разделе Export нажимаем + и экспортируем в SVG — как наиболее лёгкий и адаптивный векторный формат.
Создаём новый лейаут activity_learn_word с основным контейнером LinearLayout и вертикальной ориентацией.
Для добавления изображений используется ImageView. Но так как это иконка для нажатия, используем ImageButton — специализированную версию ImageView, которая позволяет изображению вести себя как кнопка.
Для импорта идём в ресурсы и нажимаем ПКМ на каталоге drawable. Выбираем New → Vector Asset (не путать с Image Asset — он для растровых изображений). Далее Local file и выбираем скачанную иконку. Иконки рекомендуется именовать с префиксом ic в snake_case — например, ic_close. После импорта иконка появится в ресурсах в формате XML.
Чтобы присвоить иконку ImageButton, прописываем атрибут src со ссылкой на ресурс:
android:src="@drawable/ic_close"
Ссылка формируется так: после @ указывается каталог, через слэш — название ресурса. Использование префиксов упрощает поиск ресурсов в списках.
Для прозрачного фона используем атрибут background со ссылкой на стандартный ресурс Android:
android:background="@android:color/transparent"
Перейти к любому ресурсу можно кликом с Ctrl/Cmd. Отступы иконки задаём по макету через margin: 10dp сверху и 24dp слева.
Замечание: данное решение не оптимально — отсутствует эффект нажатия, область клика мала и совпадает с размером иконки, нет
contentDescriptionдля голосовых помощников. Эти темы будут рассмотрены в следующих уроках.
Для отображения слова используем TextView. Расставляем отступы по макету, задаём горизонтальное центрирование и размер текста 50sp через атрибут textSize.
Статический текст задаётся через атрибут text, однако он останется неизменным в приложении. Для тестовых значений, которые не должны видеть пользователи, используют пространство имён tools:
tools:text="Test word"
Значение из tools отображается только в превью; пользователь видит только содержимое обычного атрибута text. Иногда текст в tools делают заведомо длинным, чтобы проверить поведение при переносах.
По дизайн-макету видим структуру из вложенных контейнеров: один общий LinearLayout с вертикальной ориентацией для всех вариантов, внутри которого каждый вариант — горизонтальный контейнер с порядковым номером и словом.
LinearLayout: высота по контенту, ширина match_parent, вертикальная ориентация, отступы сверху и по сторонам.TextView для цифры и TextView для слова. Размеры фиксированные, берём из макета.В XML вложенность наблюдается по отступам слева. При наведении на превью видны контуры созданных элементов.
16sp, размеры TextView цифры — 40dp × 40dp, gravity="center".TextView цифры — 12dp.gravity="center_vertical".TextView слова — 8dp, размер текста по макету.background (цвет из макета), цвет текста — через textColor.Для добавления обводки и закруглённых углов (Corner Radius = 10 по макету) используется механизм ShapeDrawable — создание фигуры нужной формы и её назначение в качестве фона контейнера.
Алгоритм создания фона:
drawable создаём Drawable Resource File, называем по правилу «тип + назначение» — например, shape_rounded_variants.shape.solid с атрибутом color — цвет заливки из макета.corners с атрибутом radius="10dp" — скругление углов.android:background="@drawable/shape_rounded_variants".Аналогично создаём фигуру с обводкой для контейнера варианта ответа. Тег stroke принимает атрибуты толщины линии (1dp по макету) и цвета.
После завершения дублируем элемент для трёх оставшихся вариантов, корректируем верхний отступ (18dp) и нумерацию.
Базовая вёрстка вариантов ответа завершена. Обработка поведения и стилизация для отображения правильного / неправильного варианта будет производиться из MainActivity.kt.
В нижней части экрана расположены кнопка пропуска слова и информационная плашка с результатом ответа — оба элемента должны быть прижаты к нижней части экрана.
Применение android:layout_gravity="bottom" для кнопки внутри LinearLayout не работает: элементы в нём располагаются строго последовательно. В вертикальном LinearLayout через layout_gravity можно позиционировать только по горизонтали, в горизонтальном — только по вертикали.
Альтернатива — вставить пустой View со android:layout_weight="1" между элементами, чтобы он занял всё свободное пространство и прижал кнопку вниз. Но это решение неэлегантно.
Оптимальный вариант — заменить основной контейнер на ConstraintLayout. После замены добавляем констрейнты и отступы: элементы до кнопки позиционируются относительно элемента выше, кнопка привязывается к нижней грани.
Параметры кнопки пропуска по макету: ширина 310dp, высота 58dp. Цвет задаётся атрибутом backgroundTint (Hex-значение из макета).
Кнопку скрываем через android:visibility="gone" — программно она будет показываться из MainActivity. Атрибут visibility принимает три значения:
visible — элемент виден (по умолчанию).invisible — скрыт, но занимает место и влияет на позиционирование зависимых элементов.gone — полностью исключён из макета, не занимает пространства.Используем gone: скрытый элемент не влияет на расположение других. Вместо манипуляции множеством атрибутов из кода лучше ограничиться изменением видимости — это снижает вероятность ошибок в долгосрочной перспективе.
Информационный блок с результатом ответа верстаем через ConstraintLayout без вложенности:
match_parent, высота по контенту; констрейнты к родителю снизу и по бокам; цвет фона из макета.tools — пользователь этого не увидит.Экспортируем иконку-группу из Figma как единый SVG и импортируем в проект как вектор. Размещаем через ImageView, задаём src со ссылкой на ресурс, проставляем констрейнты (сверху и слева) и марджины по макету.
Текст рядом с иконкой добавляем через TextView с констрейнтами:
Если задать элементу констрейнты к верху и низу другого view, он автоматически центрируется относительно него по вертикали.
Добавляем тег Button, позиционируем по бокам и сверху относительно иконки, задаём отступы сверху и снизу, стилизуем (размеры и цвет текста).
Для скруглённой формы кнопок создаём ShapeDrawable с нужным cornerRadius и присваиваем через background. После этого кнопка отображается некорректно — потому что Android Studio добавляет в проект библиотеку Material Design, которая подменяет тег Button на MaterialButton.
Material Design — спецификация Google по визуальному оформлению приложений: анимации, шрифты, цвета и т.д. Именно она обеспечивает единый стиль системных компонентов Android.
Решение: заменить тег Button на android.widget.Button, явно указав путь к стандартному компоненту SDK:
<android.widget.Button ... />
Это заставляет систему обращаться к конкретному компоненту напрямую, минуя подмену библиотекой Material.
Решение работоспособно, но не идеально: стандартная кнопка из SDK может выглядеть по-разному в разных версиях Android. В следующих уроках рассмотрим корректный способ переопределения компонентов Material Design.