Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created March 29, 2026 11:33
Show Gist options
  • Select an option

  • Save sunmeat/4bec7a7ba319edd7a0f6c409b29f6383 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/4bec7a7ba319edd7a0f6c409b29f6383 to your computer and use it in GitHub Desktop.
jetpack compose example
build.gradle.kts (Project):
plugins {
alias(libs.plugins.android.application) apply false
kotlin("plugin.compose") version "2.0.21" apply false // !!!
}
==================================================================================================================
build.gradle.kts (Module:app):
plugins {
alias(libs.plugins.android.application)
kotlin("plugin.compose") // !!!
}
android {
namespace = "site.sunmeat.compose"
compileSdk = 36
defaultConfig {
applicationId = "site.sunmeat.compose"
minSdk = 33
targetSdk = 36
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures { // !!!
compose = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
// !!!
implementation("androidx.activity:activity-compose:1.13.0")
implementation(platform("androidx.compose:compose-bom:2026.03.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")
}
==================================================================================================================
MainActivity.kt:
package site.sunmeat.compose
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// enableEdgeToEdge - контент займає весь екран, включно зі статус-баром
enableEdgeToEdge()
// setContent замінює XML-леяут - тут описується весь UI
setContent {
// MaterialTheme автоматично підхоплює світлу/темну тему системи
MaterialTheme {
// Surface - базовий контейнер, який дає правильний колір фону
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingScreen()
}
}
}
}
}
// @Composable - анотація, що робить функцію частиною UI-дерева Compose
@Composable
fun GreetingScreen() {
// remember - зберігає значення між перемальовуваннями (recomposition)
// mutableIntStateOf - оптимізований стан для Int
var count by remember { mutableIntStateOf(0) }
// mutableStateOf - стан для будь-якого типу, тут String
var name by remember { mutableStateOf("") }
// Column - вертикальний контейнер, аналог LinearLayout з вертикальною орієнтацією
Column(
modifier = Modifier
.fillMaxSize()
// windowInsetsPadding - відступи з урахуванням статус-бару і навігації
.windowInsetsPadding(WindowInsets.systemBars)
.padding(horizontal = 24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// Card - картка з тінню та заокругленими кутами
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(20.dp),
// cardColors автоматично змінює колір під світлу/темну тему
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Text з динамічним вмістом - змінюється разом зі станом name
Text(
text = if (name.isBlank()) "Привіт!" else "Привіт, $name!",
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold,
// onPrimaryContainer автоматично контрастний до primaryContainer
color = MaterialTheme.colorScheme.onPrimaryContainer
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Введи своє ім'я нижче",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.7f)
)
}
}
Spacer(modifier = Modifier.height(24.dp))
// OutlinedTextField - поле введення тексту в стилі Material3
// onValueChange викликається при кожній зміні - оновлює стан name
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Твоє ім'я") },
placeholder = { Text("Наприклад: Олег") },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(14.dp),
singleLine = true,
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.outline
)
)
Spacer(modifier = Modifier.height(32.dp))
// HorizontalDivider - роздільник між секціями
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
Spacer(modifier = Modifier.height(32.dp))
// лічильник - оновлюється автоматично при зміні count
Text(
text = "Кількість натискань",
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
)
Spacer(modifier = Modifier.height(8.dp))
// велике число лічильника
Text(
text = "$count",
style = MaterialTheme.typography.displayMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(24.dp))
// Button - при натисканні збільшує count на 1
// Compose автоматично перемальовує все, що читає count
Button(
onClick = { count++ },
modifier = Modifier
.fillMaxWidth()
.height(52.dp),
shape = RoundedCornerShape(14.dp)
) {
Text(
text = "Натисни мене",
style = MaterialTheme.typography.titleMedium
)
}
Spacer(modifier = Modifier.height(12.dp))
// OutlinedButton - скидає лічильник до нуля
OutlinedButton(
onClick = { count = 0 },
modifier = Modifier
.fillMaxWidth()
.height(52.dp),
shape = RoundedCornerShape(14.dp)
) {
Text(
text = "Скинути",
style = MaterialTheme.typography.titleMedium
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment