Освой Compose играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Compose: Начало

Для работы понадобится Android Studio Giraffe и старше (впервые возможность появилась в Arctic Fox), в котором есть готовый шаблон Empty Activity (до версии Flamingo было два шаблона Empty Compose Activity).

Версия Flamingo.

Empty Activity template

Версия Electric Eel, Dolphin и раньше.

Empty Compose Activity template

Запустим проект на основе предлагаемого шаблона и изучим его.

В build.gradle прописано следующее (другие настройки пока не рассматриваем).


android {
    buildFeatures {
        compose true
    }
    ...
}

Посмотрим на код программы. Первое, что бросается в глаза - нет XML-файла для разметки. Есть только код для MainActivity.kt. Выделена строка, которая добавилась в Android Studio и мои изменения в строках.

В старых версиях использовался старый Material Design, сейчас стал использоваться Material 3, из-за этого при копирования кода из старых примеров может понадобиться небольшая переделка.

package ru.alexanderklimov.compose

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import ru.alexanderklimov.compose.ui.theme.ComposeTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Kitty")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello \$name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeTheme {
        Greeting("Kitty")
    }
}

Наш класс наследуется от класса ComponentActivity. По-прежнему есть метод onCreate(), в котором вызывается уже не метод setContentView(), а другой метод setContent(), определяющий макет экрана. Только вместо загрузки XML-файла, мы вызываем composable-функции. В студии эти методы выводятся зелёным цветом и начинаются с большой буквы - к этому придётся привыкать.

Встречаются composable-функции ComposeTheme, Surface и Greeting (внутри неё функция Text).

Например, функция Text() определена в библиотеке Compose UI и вам нужно лишь указать текст. Всё очень просто.

Работа функции Greeting понятна - выводит текст "Hello Android". Вообще-то положено выводить текст "Hello World", но Гугл в 2021 году осмелилась нарушить традицию и изменить привычное выражение. Но компания отстала от меня на 10 лет, я начал выводить "Hello Kitty" гораздо раньше. Вот и в первом нашем проекте я также внёс единственное изменение.

По поводу ComposeTheme - она задаёт тему, а её имя создаётся на основе имени вашего проекта. Если посмотрите на структуру проекта, то увидите, что кроме файла MainActivity.kt есть подпапка ui.theme с набором файлов, в том числе и Theme.kt. В нём можно найти описание используемой темы на основе MaterialTheme.

Функция Surface отвечает за фон приложения. По умолчанию это белый цвет (в том же файле Theme.kt есть сноска на этот счёт.

В шаблоне реализован самый простой пример для знакомства, мы упростим ещё больше - просто выводим строку на экран.


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello Kitty!")
        }
    }
}

Составные функции можно вызывать только из области видимости других составных функций. Чтобы сделать функцию составной, нужно добавить аннотацию @Composable.

В примере есть пример такой собственной составной функции с одним параметром для установки имени. С её помощью можно здороваться с котом.


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Greeting("Барсик")
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text (text = "Привет \$name!")
}

Чтобы увидеть результат, нам необходимо запустить приложение на эмуляторе или на устройстве. Это не очень удобно при частых правках. Студия позволяет увидеть будущий вид экрана через аннотацию @Preview. Аннотация @Preview должна находиться до аннотации @Composable. Но есть небольшое ограничение у аннотации - составная функция не должна содержать параметры. По этой причине мы не сможем увидеть предыдущий пример, где функция использует один параметр. Пойдём на хитрость и вызовем функцию в другой функции.


@Composable
fun Greeting(name: String) {
    Text(text = "Hello \$name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    ComposeTheme {
        Greeting("Kitty")
    }
}

@Preview
@Composable
fun PreviewGreeting() {
    Greeting("Барсик")
}

Превью-функцию желательно создавать как отдельный элемент кода, который не будет вызываться в приложении. Она служит для просмотра внешнего вида и только. Чтобы увидеть визуальную картинку, используйте значки Split или Design, как обычно мы делали для просмотра XML-файла.

После сделанных изменений в коде не забывайте нажимать кнопку Refresh в верхней части редактора.

Шаблон для уроков

Если присмотреться, то можно увидеть, что определённая часть кода всегда остаётся неизменной. Для экономии места я буду использовать сокращённый вариант для примеров. Для начала полный код.


package ru.alexanderklimov.compose

import ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Content()
        }
    }
}

@Composable
fun Content()
{
    // Здесь код для примера
}

@Preview(showBackground = true)
@Composable
fun ContentPreview() {
    Content()
}

Для демонстрации простейших примеров достаточно показать код из Content(). На всякий случай также буду добавлять список импортированных классов, так как порой имена совпадают и на первых порах можно делать ошибочный импорт.


// Один из примеров
@Composable
fun Content() {
    Text(text = "Hello Kitty")
}

Урокам по Compose выделен отдельный раздел. Сейчас практически все быстро мигрируют на новый способ написания приложений. Первоначально непривычно, но потом начинаешь привыкать. Надеюсь, вам понравится.

Дополнительное чтение

Реклама