Как реализовать текст с декоративной заглавной буквой в Android-приложении и почему это важно для UI
Привет! Меня зовут Юля, я Android-разработчица в продуктовой компании OBRIO. Мы ― часть экосистемы бизнесов Genesis и разрабатываем мобильные приложения и игры.
В этой статье хочу уделить внимание ценности UI для успеха приложения и рассмотрю пример компонента для текста с большой заглавной буквой. Понятие «компонент» я использую для обозначения нескольких UI-элементов, объединенных и сконфигурированных для получения желаемого результата.
Материал посвящается всем заинтересованным, а особенно начинающим программистам, которые ищут вдохновение и идеи для красивого UI простыми средствами.
Пример компонента взят из астрологического приложения Nebula, в разработке которого я принимаю участие. Продукт имеет многомиллионную аудиторию пользователей и высокий рейтинг в App Store и Google Play. Предоставляя широкий спектр экспертных услуг, мы также заботимся о комфорте пользователя, создавая красивый и удобный дизайн, чтобы пребывание в приложении было интересным и продолжительным.
Чем больше продукт привлекает внимание пользователя, тем больше вероятность, что увеличится количество скачиваний, его конверсия. Поэтому очень важно выделять ресурсы не только на основной функционал, но и на разработку user friendly дизайна.
В Nebula огромное количество интересных UI-решений. Но сегодня остановимся на UI-компоненте с увеличенной первой буквой.
Проблема
Задача — сделать заглавную букву определенного размера, чтобы остальной текст обрамлял ее.
При поиске подхода, как это сделать, большинство решений были построены на основе SpannableString. Нам он не помог, но давайте рассмотрим, вдруг кому-то будет полезным.
Решение 1
Для изменения свойств части текста (в нашем случае размера одной буквы) обычно используется SpannableString.
Указываем относительный размер в четыре раза больше основного размера текста RelativeSizeSpan(4f). Предварительно можно сделать первую букву заглавной.
fun String.capitalizeFirst(): String = replaceFirstChar { when (it.isLowerCase()) { true -> it.titlecase(Locale.ROOT) else -> it.toString() } }
При таком подходе:
val str = "sample text" val capitalizeStr = str.capitalizeFirst() val spannableString = SpannableString(capitalizeStr) spannableString.setSpan(RelativeSizeSpan(4f), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) textView.text = spannableString
Получаем такой результат:
Букву увеличили, но смотрится не так, как на дизайне.
Решение 2
Так как мы должны иметь возможность указывать размеры пространства для расположения в нем заглавной буквы, то удобно, чтобы компонент состоял из двух TextView: первый для заглавной буквы, второй для остального теста, исключая заглавную букву.
Создадим XML:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/common_padding"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/letter" android:layout_width="75dp" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:gravity="center" android:textColor="@android:color/white" android:textSize="44sp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"/> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:lineSpacingExtra="3dp" android:textColor="@android:color/white" android:textSize="18sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
Далее считаем, какому количество строк (n) нужно добавить отступ, чтобы обрамить заглавную букву. Для этого делим высоту заглавной буквы на размер строки:
val n = (height / textLineHeight).toInt()
Чтобы сдвинуть n строк на ширину заглавной буквы w, реализуем свой класс, наследовавшись от LeadingMarginSpan.LeadingMarginSpan2
. Нужно определить два параметра:
- lines — количество строк для изменения отступа;
- margin — отступ.
Необходимая структура класса описана ниже. Здесь мы упоминаем об основных методах, их реализация может меняться в зависимости от вашего дизайна.
class MarginSpanHelper (private var lines: Int, private var margin: Int): LeadingMarginSpan.LeadingMarginSpan2 { // возвращаем величину отступа для текущей строки (параметр margin или 0) // first = true, если запрашивается отступ для первой строки override fun getLeadingMargin(first: Boolean): Int { } // возвращаем количество строк, к которому будет применен отступ // (параметр lines) override fun getLeadingMarginLineCount(): Int { } }
Для удобства вынесла код в extension:
firstLetterView.text = “F” textView.makeTextAroundView(firstLetterView, text) fun TextView.makeTextAroundView(firstLetterView: View, text: String) { val height = firstLetterView.measuredHeight val width = firstLetterView.measuredWidth val textLineHeight = paint.textSize val span = SpannableString(text) val linesWithMargin = (height / textLineHeight).toInt() val marginHelper = MarginSpanHelper(linesWithMargin, width) span.setSpan(marginHelper, 0, span.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) this.text = span }
Добавим шрифт к заглавной букве и получим желаемый результат:
firstLetterView.typeface = ResourcesCompat.getFont(context, fontId)
Вместо элемента TextView для заглавной буквы можно использовать картинку, анимацию, любой нужный вам view.
Вывод
Удобный и стильный UI — один из основных факторов, который влияет на популярность и успешность продукта, на желание пользователя выбрать именно это приложение. Мы рассмотрели, как можно добавить акцент на текст, увеличить заглавную букву, гармонично расположить текст вокруг нее. Надеюсь, статья была для вас полезной.
Спасибо за внимание, всем красивого UI.
14 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів