Кроме файлов кода на языке Kotlin проект может включать дополнительные файлы, которые используются в приложении, например, файлы изображений, определения иконок, файлы xml и так далее. Подобные файлы называются ресурсами. Все ресурсы находятся в проекте в каталоге res.
Одним из наиболее применяемых типов ресурсов являются ресурсы строк. Они используются при выведении названия приложения, различного текста, например, текста кнопок и т.д. Например, нам нужно вывести в различных местах приложения один и тот же текст. Вместо того, чтобы по несколько раз определять его в коде Kotlin, мы можем определить его один раз в виде строкового ресурса и использовать в любом месте приложения.
По умолчанию строковые ресурсы хранятся в проекте в каталоге res/values. При создании проекта в этот каталог по умолчанию добавляется файл строковых ресурсов strings.xml.
Если мы откроем файл, то мы найдем в нем строки наподобие следующих:
<resources> <string name="app_name">helloapp</string> </resources>
Каждый отдельный строковый ресурс определяется с помощью элемента string, а его атрибут name содержит название ресурса. Так, в самом простом виде этот файл определяет один ресурс "app_name", который устанавливает название приложения и который в моем случае имеет значение "helloapp" (по умолчанию значение этого ресурса соответствует названию проекта). Но естественно мы можем определить любые строковые ресурсы.
Затем в приложении в файлах кода мы можем ссылаться на эти ресурсы через их идентификатор, который имеет следующий вид:
R.string.название_ресурса
Например, для обращения к определенному по умолчанию строковому ресурсу app_name применяется идентификатор
R.string.app_name
Чтобы получить строковый ресурс в коде Kotlin, применяется встроенная функция androidx.compose.ui.res.stringResource(), в которую передается идентификатор ресурса и которая возвращает строку в виде объекта String. Например, получим в коде ресурс app_name:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text( text = stringResource(R.string.app_name), fontSize = 28.sp ) } } }
В данном случае параметру text компонента Text передается строка из строкового ресурса app_name:
Подобным образом при необходимоси мы можем определять и свои ресурсы. Например, изменим файл res/values/strings.xml следующим образом:
<resources> <string name="app_name">helloapp</string> <string name="message">Hello METANIT.COM</string> </resources>
Здесь добавлен строковый ресурс "message", который имеет значение "Hello METANIT.COM"
Используем этот строковый ресурс в коде:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material3.Text import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text( text = stringResource(R.string.message), fontSize = 28.sp ) } } }
Хотя по умолчанию для ресурсов строк применяется файл strings.xml, но можно добавлять дополнительные файлы ресурсов в каталог проекта res/values. При этом достаточно соблюдать структуру файла: он должен иметь корневой узел <resources> и иметь один или несколько элементов <string>.
Так, нажмем на папку res/values правой кнопкой мыши и в появившемся списке выберем пункт New -> Value Resource File:
После этого нам будет предложено определить для файла имя:
Назовем, к примеру, headers.xml (название файла произвольное), а для всех остальных полей оставим значения по умолчанию. И в папку res/values будет добавлен новый файл headers.xml. Определим в нем пару ресурсов:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Добро пожаловать</string> <string name="click_button">Отправить</string> </resources>
И после этого мы также сможем использовать эти ресурсы в коде Kotlin, например:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Column{ Text( text = stringResource(R.string.welcome), fontSize = 28.sp ) Button({}){ Text( text = stringResource(R.string.click_button), fontSize = 22.sp ) } } } } }
Функция stringResource() позволяет применять к ресурсам строк форматирование. Преимуществом форматирования является то, что мы можем определить общий щаблон и затем подставлять в него необходимые значения. Например, изменим файл strings.xml:
<resources> <string name="app_name">helloapp</string> <string name="user_data">Имя: %1$s. Возраст: %2$d. Компания: %3$s</string> </resources>
Здесь ресурс user_data
представляет строку с форматированием. Так, она содержит такие символы как %1$s, %2$d и %3$ds.
Что они означают? %1$s указывает, что это первый аргумент, а символ "s" говорит, что этот аргумент представляет строку.
%2$d представляет второй аргумент, а символ "d" в конце указывает, что это будет целое число. Аналогично %3$s указывает, что это
третий аргумент, который представляет строку.
Получим ресурс в коде Kotlin:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.material3.Text import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Column{ Text( text = stringResource(R.string.user_data, "Tom", 37, "JetBrains"), fontSize = 28.sp ) Text( text = stringResource(R.string.user_data, "Bob", 41, "Google"), fontSize = 28.sp ) } } } }
Вызов функции stringResource(R.string.user_data, "Tom", 37, "JetBrains")
получает ресурс "user_data" и в
качестве последующих параметров передает в строку вставляемые значения. Так, вместо первого аргумента-строки в user_data вставляется второй аргумент функции -
строка "Tom", вместо второго аргумента-числа в user_data вставляется число 37, а вместо третьего аргумента в user_data передается строка "JetBrains".
Ресурсы Plurals представляют еще один вид набора строк, в которым применяется форматирование. Он предназначен для описания количества элементов. Для чего это надо? К примеру, возьмем существительное: нередко оно изменяет окончание в зависимости от числительного, которое с ним употребляется: 1 цветок, 2 цветка, 7 цветков. Для подобных случаев и используется ресурс plurals.
Посмотрим на примере. Добавим в папку res/values новый ресурс flowers.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="flowers"> <item quantity="one">%d цветок</item> <item quantity="few">%d цветка</item> <item quantity="many">%d цветков</item> </plurals> </resources>
Для задания ресурса используется элемент <plurals>. Его атрибут name
хранит название ресурса.
Сами наборы строк вводятся дочерними элементами <item>
. Этот элемент имеет атрибут quantity
,
который имеет значение, указывающее, когда эта строка используется. Данный атрибут может принимать следующие значения:
zero: строка для количества в размере 0
one: строка для количества в размере 1 (для русского языка - для задания всех количеств, оканчивающихся на 1, кроме 11)
two: строка для количества в размере 2
few: строка для небольшого количества
many: строка для больших количеств
other: все остальные случаи
Причем в данном случае многое зависит от конкретного языка. А система сама позволяет определить, какое значение брать для того или иного числа.
Получим и используем этот ресурс в коде Kotlin:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.material3.Text import androidx.compose.ui.unit.sp import androidx.compose.ui.platform.LocalContext class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val resources = LocalContext.current.resources Column{ Text( text = resources.getQuantityString(R.plurals.flowers, 21, 21), fontSize = 28.sp ) Text( text = resources.getQuantityString(R.plurals.flowers, 7, 7), fontSize = 28.sp ) } } } }
На данный момент Jetpack Compose не поддерживает напрямую получение подобных ресурсов. Поэтому для их извлечения
вначале необходимо получить текущий контекст через свойство LocalContext.current
и затем обратиться к его свойству resource
, которое представляет
класс Resources и ассоциирован со всеми ресурсами приложения.
Далее с помощью метода getQuantityString класса Resources получаем значение ресурса. Первым параметром передаем идентификатор ресурса. Вторым параметром идет значение. для которого нужно найти нужную строку. Третий параметр представляет собой значение, которое будет вставляться на место плейсхолдера %d. То есть мы получаем строку для числа 21.
Еще один тип ресурсов представляют массивы строк в виде элемента string-array. Его можно использовать, когда надо определить какой-нибудь набор строк. Например, добавим в папку res/values новый файл, который назовем languages.xml:
В этом файле определим следующее содержимое:
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="languages"> <item>Kotlin</item> <item>Java</item> <item>JavaScript</item> <item>Python</item> <item>C++</item> </string-array> </resources>
Массив строк определяется с помощью элемента <string-array name="languages">
. В данном случае этот ресурс называется "languages". Каждая отдельная строка этотго массива представлена элементом
<item>
. И в данном случае в массиве определено 5 элементов.
Теперь получим этот массив в приложении на Kotlin:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.ui.unit.sp import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val items = resources.getStringArray(R.array.languages) setContent { Column{ for(item in items){ Text(item, Modifier.padding(8.dp), fontSize = 28.sp) } } } } }
Для получения массива применяется метод getStringArray(), в который передается имя ресурса:
val items = resources.getStringArray(R.array.languages)
Возвращаемый объект представляет массив типа Array<String>
, который, например, можно перебрать и вывести в виде компонентов Text в приложении: