Spec-Zone.ru › Kotlin 2

Изображения и значки в приложении

Compose Multiplatform для настольных компьютеров загружает изображения из библиотеки мультимплатформенных ресурсов, как и другие платформы. Настольные приложения также могут считывать изображения из файловой системы или сети с помощью API JVM и использовать изображения в качестве значков окна и системного трея.

Примеры в этом руководстве представляют собой запускаемые настольные приложения. Чтобы попробовать пример:

  1. Создайте проект Compose Multiplatform с помощью плагина IDE Kotlin Multiplatform или онлайн-мастера.

  2. Откройте файл точки входа настольного приложения. Например, desktopApp/src/main/kotlin/com/example/my_desktop_app/main.kt.

  3. Замените его содержимое приведённым примером.

В примерах на этой странице используются логотипы Kotlin и Compose Multiplatform. Оба логотипа входят в пакет Kotlin Brand Assets.

Отображение изображений из ресурсов

Чтобы показать изображение, включённое в приложение, добавьте его в мультимплатформенные ресурсы проекта и соберите проект, чтобы сгенерировать средства доступа к ресурсам. Создайте экземпляр Painter, передав средство доступа в painterResource(), и передайте полученный Painter в компонуемую функцию Image():

import androidx.compose.foundation.Image import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.ui.Modifier import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.application import org.jetbrains.compose.resources.painterResource import com.example.composeapp.generated.resources.Res import com.example.composeapp.generated.resources.kotlin_logo fun main() = application { Window( onCloseRequest = ::exitApplication, title = "Resource image", state = WindowState(size = DpSize(500.dp, 250.dp)) ) { Image( painter = painterResource(Res.drawable.kotlin_logo), contentDescription = "Kotlin logo", modifier = Modifier.fillMaxSize().padding(24.dp) ) } }
An image from multiplatform resources

painterResource() поддерживает растровые форматы изображений, такие как .png, .jpg, .bmp и .webp, а также формат векторных изображений Android XML. Подробнее о доступе к ресурсам в виде значений ImageBitmap или ImageVector, а также об использовании значков, шрифтов и строк см. в разделе Использование мультимплатформенных ресурсов в приложении.

Ресурсы не обязательно хранить в общем исходном наборе. Любой исходный набор или модуль может использовать собственную директорию composeResources, поэтому изображения, предназначенные только для настольного приложения, можно хранить рядом с кодом, относящимся к настольной платформе.

Чтобы использовать ресурсы, объявленные в другом модуле, сделайте сгенерированный класс Res этого модуля открытым.

Загрузка изображений из файловой системы или сети

Изображения, не входящие в состав приложения (выбранные пользователем файлы или загруженные во время выполнения), не являются ресурсами. Считайте их байты с помощью любого API JVM и декодируйте их одной из следующих функций библиотеки ресурсов:

Формат изображения

Функция декодирования

Результат

Растровое изображение

decodeToImageBitmap()

ImageBitmap

Векторное изображение XML

decodeToImageVector()

ImageVector

SVG

decodeToSvgPainter()

Painter

Чтение файла или сетевого ответа блокирует вызывающий поток, поэтому всегда выполняйте эти операции вне потока пользовательского интерфейса.

В следующем примере объявлена компонуемая функция AsyncImage(), которая загружает изображение в контексте Dispatchers.IO и отображает его, когда оно готово:

import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.application import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.jetbrains.compose.resources.decodeToImageBitmap import org.jetbrains.compose.resources.decodeToImageVector import org.jetbrains.compose.resources.decodeToSvgPainter import java.io.File import java.io.IOException import java.net.URI fun main() = application { val density = LocalDensity.current Window( onCloseRequest = ::exitApplication, title = "Images from the file system and the network", state = WindowState(size = DpSize(380.dp, 480.dp)) ) { Column( modifier = Modifier.fillMaxSize().padding(24.dp), verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text("PNG from the file system") AsyncImage( load = { File("kotlin-logo.png").readBytes().decodeToImageBitmap() }, painterFor = { remember { BitmapPainter(it) } }, contentDescription = "Kotlin logo", modifier = Modifier.width(260.dp) ) Text("XML vector from the file system") AsyncImage( load = { File("compose-logo.xml").readBytes().decodeToImageVector(density) }, painterFor = { rememberVectorPainter(it) }, contentDescription = "Compose Multiplatform logo", contentScale = ContentScale.FillWidth, modifier = Modifier.width(100.dp) ) Text("SVG from the network") AsyncImage( load = { loadBytes(COMPOSE_LOGO_URL).decodeToSvgPainter(density) }, painterFor = { it }, contentDescription = "Compose Multiplatform logo", contentScale = ContentScale.FillWidth, modifier = Modifier.width(100.dp) ) } } } private const val COMPOSE_LOGO_URL = "https://github.com/JetBrains/compose-multiplatform/raw/master/artwork/compose-logo.svg" fun loadBytes(url: String): ByteArray = URI(url).toURL().openStream().use { it.readBytes() } @Composable fun <T> AsyncImage( load: suspend () -> T, painterFor: @Composable (T) -> Painter, contentDescription: String, modifier: Modifier = Modifier, contentScale: ContentScale = ContentScale.Fit ) { val image: T? by produceState<T?>(null) { value = withContext(Dispatchers.IO) { try { load() } catch (e: IOException) { // Instead of printing to the console, you can log the error // or show a placeholder image. e.printStackTrace() null } } } if (image != null) { Image( painter = painterFor(image!!), contentDescription = contentDescription, contentScale = contentScale, modifier = modifier ) } }
Images loaded from the file system and the network

Пути к файлам в примере задаются относительно рабочего каталога приложения.

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

Настройка значка окна

Чтобы использовать изображение в качестве значка окна, передайте экземпляр Painter в компонуемую функцию Window() в качестве параметра icon:

import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import androidx.compose.ui.draw.paint import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.application import org.jetbrains.compose.resources.painterResource import com.example.composeapp.generated.resources.Res import com.example.composeapp.generated.resources.compose_logo fun main() = application { val icon = painterResource(Res.drawable.compose_logo) Window( onCloseRequest = ::exitApplication, title = "Window icon", icon = icon, state = WindowState(size = DpSize(400.dp, 300.dp)) ) { Box(Modifier.fillMaxSize().paint(icon, contentScale = ContentScale.Fit)) } }

Расположение значка зависит от операционной системы:

  • В Windows и Linux это значок окна и его элемента на панели задач.

  • В macOS значок приложения берётся из пакета приложения. Чтобы изменить значок в Dock, задайте его в конфигурации дистрибутива.

На следующем снимке экрана показано упакованное приложение в macOS. В окне отображается то же изображение, которое передано в параметр icon, а значок Dock берётся из файла .icns, указанного в конфигурации дистрибутива:

A packaged application and its Dock icon

Значок приложения с одним окном

Функция singleWindowApplication() вычисляет параметр icon вне композиции, где painterResource() недоступен. Вместо этого считайте ресурс с помощью Res.readBytes(), принимающего путь к файлу внутри каталога composeResources, и декодируйте его в BitmapPainter:

import androidx.compose.material.Text import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.window.singleWindowApplication import kotlinx.coroutines.runBlocking import org.jetbrains.compose.resources.decodeToImageBitmap import com.example.composeapp.generated.resources.Res fun main() { val iconBytes = runBlocking { Res.readBytes("drawable/kotlin-logo.png") } val icon = BitmapPainter(iconBytes.decodeToImageBitmap()) singleWindowApplication(icon = icon, title = "Single window icon") { Text("Hello, World!") } }

Настройка значка системного трея

Чтобы использовать изображение в качестве значка системного трея, передайте экземпляр Painter в компонуемую функцию Tray() в качестве параметра icon:

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Tray
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.application
import com.example.composeapp.generated.resources.Res
import com.example.composeapp.generated.resources.compose_logo
import org.jetbrains.compose.resources.painterResource

fun main() = application {
  val icon = painterResource(Res.drawable.compose_logo)

  Tray(
    icon = icon,
    tooltip = "Compose Multiplatform",
    menu = {
      Item("Exit", onClick = ::exitApplication)
    }
  )

  Window(
    onCloseRequest = ::exitApplication,
    title = "Tray icon",
    icon = icon,
    state = WindowState(size = DpSize(400.dp, 300.dp))
  ) {
    Box(modifier = Modifier.fillMaxSize().padding(24.dp)) {
      Image(
        painter = icon,
        contentDescription = "Compose Multiplatform logo",
        modifier = Modifier.fillMaxSize()
      )
    }
  }
}

В macOS значок системного трея отображается в строке меню:

A tray icon in the macOS menu bar

Что дальше

  • Узнайте больше о мультимплатформенных ресурсах и о том, как обращаться к ним из общего кода.

  • Узнайте, как добавить значок приложения в системный трей.

  • Узнайте, как создавать нативные дистрибутивы с отдельными значками приложения для разных платформ.

  • Ознакомьтесь с руководствами по другим компонентам для настольных приложений.

31 августа 2026 г.
API только для настольных приложенийУправление окнами верхнего уровня

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform/compose-desktop-images.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API