Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Исторически так сложилось, что разработчики всегда использовали пиксели при создании компьютерных интерфейсов. Но с развитием технологий данный подход стал источником проблем - на многих новых дисплеях элементы стали очень мелкими при установленных высоких разрешениях. Поэтому стали появляться новые единицы измерения, не зависящие от разрешения экрана.
Android поддерживает несколько стандартных единиц измерения. Вкратце перечислим их.
Как правило, при установке размера текста используются единицы измерения sp, которые наиболее корректно отображают шрифты:
android:textSize="48sp"
В остальных случаях рекомендуется использовать dp.
Так как на разных устройствах dp может различаться, то для получения величин в пикселях и наоборот используйте методы (float):
// Kotlin
fun convertDpToPixels(context: Context, dp: Float) =
dp * context.resources.displayMetrics.density
fun convertPixelsToDp(context: Context, pixels: Float) =
pixels / context.resources.displayMetrics.density
// Java
float convertDpToPixels(Context context, float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
float convertPixelsToDp(Context context, float pixels) {
return pixels / context.getResources().getDisplayMetrics().density;
}
Часто точность не требуется и можно использовать целые числа int. Напишем аналогичные методы.
// Kotlin
fun convertDpToPixels(context: Context, dp: Int) =
(dp * context.resources.displayMetrics.density).toInt()
fun convertPixelsToDp(context: Context, pixels: Int) =
(pixels / context.resources.displayMetrics.density).toInt()
// Java
float convertDpToPixels(Context context, int dp) {
return (int) (dp * context.getResources().getDisplayMetrics().density);
}
float convertPixelsToDp(Context context, int pixels) {
return (int) (pixels / context.getResources().getDisplayMetrics().density);
}
На Kotlin можно написать функцию-расширение:
fun Int.toDp(context: Context): Int = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics
).toInt()
Если вы не определили размеры в XML, то их можно задать программно с помощью следующего кода (устанавливаем отступы для компонента):
final float scale = getResources().getDisplayMetrics().density;
int padding_5dp = (int) (5 * scale + 0.5f);
int padding_20dp = (int) (20 * scale + 0.5f);
int padding_50dp = (int) (50 * scale + 0.5f);
RadioButton rb = new RadioButton(this);
rb.setText("My Radio Button");
rb.setLayoutParams(new LayoutParams(padding_50dp,padding_50dp));
rb.setPadding(padding_20dp,padding_5dp,padding_5dp,padding_5dp);
Давайте чуть подробнее поговорим о работе со шрифтами, чтобы лучше понять специфику работы с текстами. Все люди разные - у кого-то зрение хорошое, у кого-то плохое. Android позволяет в настройках задать размеры шрифта в четырёх вариантах: Мелкий, Обычный, Крупный, Огромный. Для этого нужно зайти в Настройки | Экран | Размер шрифта.

Можно узнать программно выбранный вариант через свойство fontScale:
float fontScale = getResources().getConfiguration().fontScale;
mInfoTextView.setText("fontScale:: " + fontScale);
Обычному шрифту соответствует значение 1, мелкому - 0.9, крупному - 1.1, огромному - 1.15.
Если вы хотите, чтобы ваш текст мог меняться в зависимости от выбора пользователя, то используйте единицы измерения SP:
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Текст с размером 26sp"
android:textSize="26sp" />
В тех случаях, когда изменять текст по желанию пользователя не следует, но при этом текст должен отображаться корректно в зависимости от разрешения экрана устройства, то используйте единицы измерения DP.
Третий вариант - если вы ни при каких обстоятельствах (какой же вы упрямый) не хотите зависеть от предпочтений пользователя и разрешения экрана, то пользуйтесь PX (пиксели). Среда разработки будет сопротивляться вашему желанию и выводить предупреждающие сообщения. Подумайте ещё раз о своём решении.
В Android зашиты три системный размера шрифтов, основанных на SP: Small, Medium и Large. Вы можете использовать их в стандартных случаях, когда вам не нужно задавать конкретные значения (атрибут style):
<TextView
android:id="@+id/textView1"
style="@android:style/TextAppearance.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста - Small" />
<TextView
android:id="@+id/textView2"
style="@android:style/TextAppearance.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста - Medium" />
<TextView
android:id="@+id/textView3"
style="@android:style/TextAppearance.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста - Large" />
На самом деле стилей @android:style/TextAppearance.* гораздо больше. Если вы вдруг забыли про названия стилей, то можете использовать встроенные возможности среды разработки. На панели инструментов виджет TextView представлен в четырёх вариантах: TextView, Large, Medium, Small, и в них используется атрибут android:textAppearance.
Создадим проект со всеми возможными вариантами и посмотрим на результат. В первом случае будем использовать стандартные настройки шрифта, во втором - увеличим его.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. Размер 20px"
android:textSize="20px" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. Размер не указан" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. textAppearanceSmall"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. textAppearanceMedium"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. textAppearanceLarge"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/textView6"
style="@android:style/TextAppearance.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. TextAppearance.Small" />
<TextView
android:id="@+id/textView7"
style="@android:style/TextAppearance.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. TextAppearance.Medium" />
<TextView
android:id="@+id/textView8"
style="@android:style/TextAppearance.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. TextAppearance.Large" />
<TextView
android:id="@+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Пример текста. Размер 30sp"
android:textSize="30sp" />
</LinearLayout>

