Jetpack Compose предполагает применение декларативного стиля при определении визуального интерфейса и работы с ним. В этом отношении иногда возникает вопрос как определять какие-то свои собственные данные в виде переменных или действия в виде функций и использовать эти переменные и функции в компонентах для создания графического интерфейса. Рассмотрим некоторые случаи.
Как и в общем случае переменные можно определять на уровне класса (например, на уровне класса MainActivity), либо на уровне отдельного метода/функции, в том числе и в функциях Composable. Например, используем пару переменных:
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.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Hello() } } } @Composable fun Hello(){ val message = "Hello Metanit.com" val size = 28.sp Text(text = message, fontSize = size) }
В данном случае в компоненте Hello определяются две переменных, и их значения передаются параметрам компонента Text:
Это относится ко всем функциям, которые принимают компоненты в качестве параметров. Причем функция каждого компонента определяет свою область видимости, в рамках которой доступны ее переменные. Вложенные компоненты имеют доступ к переменным, определенным в родительских компонентах. Например:
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.unit.sp import androidx.compose.runtime.Composable class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val textSize = 28.sp Hello{ val content = "Hello Work" Text(content, fontSize = textSize) } } } }
Здесь иерархию компонентов можно представить следующим образом: setContent -> Hello -> Text
. На уровне компонента setContent определяется
переменная textSize
- она видна на уровне компонентов в setContent.
На уровне компонента Hello определена переменная content
- она доступна во вложенных компонентах, в частности, в компоненте Text, но недоступна вне компонента Hello.
Стоит отметить, что @Composable-функция может вызывать и стандартные функции Kotlin, однако стандартные функции не могут вызывать @Composable-функции. Например, изменим код MainActivity.kt следующим образом:
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.unit.sp import java.util.Calendar class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text(text = getTime(), fontSize = 28.sp) } } } fun getTime() : String{ val calendar = Calendar.getInstance() val hours = calendar.get(Calendar.HOUR_OF_DAY) val minutes = calendar.get(Calendar.MINUTE) return "$hours:$minutes" }
В данном случае определена стандартная функция getTime, которая с помощью встроенного класса Calendar получает текущее время (часы и минуты) и возвращает его в виде строки. В компоненте Text эта функция используется для установки текста.
Подобным образом можно определять и вызывать лямбда-выражения:
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.unit.sp import java.util.Calendar class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val getTime ={ val calendar = Calendar.getInstance() val hours = calendar.get(Calendar.HOUR_OF_DAY) val minutes = calendar.get(Calendar.MINUTE) "$hours:$minutes" } Text(text = getTime(), fontSize = 28.sp) } } }
Внутри компонентов также можно использовать все стандартные управляющие конструкции, например, условные конструкции, в том числе для создания интерфейса:
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.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val hours = 19 if(hours<18) { Text(text = "Добрый день", fontSize = 28.sp) } else{ Text(text = "Добрый вечер", fontSize = 28.sp) } } } }
Здесь в зависимости от переменной hour в качестве внутренного содержимого установливается определенный компонент.
Если необходимо создать ряд отднотиных компонентов, то удобно определить различающиеся данные в виде списка, а в цикле по этому списку создать набор компонентов:
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 class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val langs = listOf("Kotlin", "Java", "JavaScript", "Python") Column{ for(lang in langs){ Text(text = lang, fontSize = 28.sp) } } } } }
Здесь применяется встроенный компонент Column, который располагает вложенные компоненты в столбик. Но эти компоненты здесь создаются динамически. В начале определяем данные в виде списке langs. В столбце Column пробегаемся по этому списку и создаем для каждого свой компонент Text
Причем в данном случае мы также могли бы применить и встроенную функцию forEach()
списка, которая позволяет перебрать все объекты:
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 class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val langs = listOf("Kotlin", "Java", "JavaScript", "Scala") Column{ langs.forEach{lang -> Text(text = lang, fontSize = 28.sp) } } } } }