AndroidKMP之瀑布流实现
1.前言:
之前写了入门的kmpdemo,最近用compose写了一个瀑布流,然后使用KMP在Android、桌面和web端都运行了一下,发现非常强大,iOS由于没有设备就暂时不贴效果图了.
2.项目配置:
AGP9.3.2和Gradle9.7.1
ini
#Sun Sep 06 14:14:56 CST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=553c78f50dafcd54d65b9a444649057857469edf836431389695608536d6b746
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-9.7.1-bin.zip
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
ini
[versions]
agp = "9.3.2"
android-compileSdk = "37"
android-minSdk = "24"
android-targetSdk = "37"
androidx-activity = "1.13.0"
androidx-appcompat = "1.8.0"
androidx-core = "1.19.0"
androidx-espresso = "3.7.0"
androidx-lifecycle = "2.11.0"
androidx-testExt = "1.3.0"
composeMultiplatform = "1.12.0"
junit = "4.13.2"
kotlin = "2.4.10"
kotlin-wrappers = "2026.8.4"
kotlinx-coroutines = "1.11.0"
material3 = "1.11.0-alpha07"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-testJunit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
junit = { module = "junit:junit", version.ref = "junit" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-testExt-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-testExt" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
compose-uiTooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "composeMultiplatform" }
androidx-lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeMultiplatform" }
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "composeMultiplatform" }
compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "material3" }
compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "composeMultiplatform" }
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "composeMultiplatform" }
compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "composeMultiplatform" }
kotlinx-coroutinesSwing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
wrappers-browser = { module = "org.jetbrains.kotlin-wrappers:kotlin-browser", version.ref = "kotlin-wrappers" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
androidMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }


3.项目模块总览:
| 模块 | 作用 | 运行平台 | 入口文件 |
|---|---|---|---|
shared |
共享核心模块,存放公共 Compose UI、业务逻辑、数据模型;所有平台复用 | Android / Desktop(JVM) / iOS / Web(Wasm‑JS) | src/commonMain/kotlin/.../LazyVerticalStaggeredGridDemo.kt |
androidApp |
Android 平台应用壳,仅 Android 宿主,不写业务 UI | Android | src/main/kotlin/com/staggeredgrid/kmpdemo/MainActivity.kt |
desktopApp |
桌面 (JVM) 应用壳,桌面启动入口 | Desktop(JVM) | src/main/kotlin/com/staggeredgrid/kmpdemo/main.kt |
webApp |
Web (Wasm‑JS) 应用壳,浏览器运行 | Web(Wasm‑JS) | src/webMain/kotlin/com/staggeredgrid/kmpdemo/main.kt |
iosApp |
iOS 平台壳(截图可见存在,未展示代码) | iOS | iosMain 入口 |
4.shared 共享模块(核心)
shared 是 KMP 核心模块,所有平台共用代码,不同平台源码放在不同 sourceSet:
scss
shared/src
├─ commonMain 【通用】所有平台共用,Compose UI、业务逻辑、数据模型
├─ commonTest 通用单元测试
├─ androidMain Android平台专属代码(Android SDK API)
├─ androidHostTest
├─ iosMain iOS平台专属代码
├─ iosTest
├─ jvmMain Desktop(JVM)平台专属
├─ jvmTest
├─ jsMain JS/旧Web
├─ wasmJsMain Wasm‑JS(Web浏览器)
└─ webTest
关键:
LazyVerticalStaggeredGridDemo()这个 Composable 组件写在 commonMain,Android、Desktop、Web 全部直接调用,不用重复写 UI。
5. 各平台宿主模块
5.1 androidApp(Android 宿主)
- 传统 Android App 模块,依赖
shared模块 - 结构:
bash
androidApp/src/main
├─ kotlin/com/staggeredgrid/kmpdemo
│ └─ MainActivity.kt // Android Activity,调用shared的Compose组件
└─ res
└─ AndroidManifest.xml
- 逻辑:Activity 中 setContent,调用
LazyVerticalStaggeredGridDemo(),UI 来自 shared 模块。
5.2 desktopApp(JVM 桌面宿主)
- 纯 JVM Compose Desktop 应用
- 入口:
desktopApp/src/main/kotlin/com/staggeredgrid/kmpdemo/main.kt
kotlin
fun main() = application {
Window(
onCloseRequest = ::exitApplication,
title = "KMP StaggeredGrid Demo",
) {
LazyVerticalStaggeredGridDemo() // 调用shared共享UI
}
}
5.3 webApp(Web Wasm‑JS 宿主)
- Compose for Web,编译为 Wasm‑JS,浏览器运行
- 入口:
webApp/src/webMain/kotlin/com/staggeredgrid/kmpdemo/main.kt
kotlin
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
ComposeViewport {
LazyVerticalStaggeredGridDemo() // 调用shared共享UI
}
}
5.4 iosApp(iOS 宿主)
- 截图可见目录存在,iOS 平台壳,入口在
iosMain,同样调用 shared 的 Compose 组件。
6.项目完整目录:
css
AndroidKMPDemo/
├─ .gradle
├─ .idea
├─ .kotlin
├─ androidApp
│ ├─ build
│ └─ src/main
│ ├─ kotlin/com/staggeredgrid/kmpdemo/MainActivity.kt
│ ├─ res
│ └─ AndroidManifest.xml
├─ app (旧Android模块,可废弃)
├─ build
├─ desktopApp
│ └─ src/main/kotlin/com/staggeredgrid/kmpdemo/main.kt
├─ gradle
├─ iosApp
├─ kotlin‑js‑store
│ ├─ wasm
│ └─ yarn.lock
├─ shared
│ └─ src
│ ├─ commonMain
│ ├─ commonTest
│ ├─ androidMain
│ ├─ androidHostTest
│ ├─ iosMain
│ ├─ iosTest
│ ├─ jvmMain
│ ├─ jvmTest
│ ├─ jsMain
│ ├─ wasmJsMain
│ └─ webTest
├─ webApp
│ └─ src/webMain/kotlin/com/staggeredgrid/kmpdemo/main.kt
└─ settings.gradle.kts
7.项目架构(KMP):
-
业务 UI、逻辑、数据模型全部放在 shared/commonMain,实现一份代码多端运行;
-
各个平台(androidApp /desktopApp/webApp /iosApp)只做
宿主壳:
- 负责平台生命周期、窗口 / 视图初始化;
- 仅仅调用 shared 模块的 Composable 根组件;
-
平台差异化代码:如果需要调用平台特有 API,写在对应 sourceSet:
androidMain/iosMain/jvmMain/wasmJsMain; -
测试:
commonTest写跨平台单元测试;各平台可以写各自平台测试。
数据流示意图:
scss
[shared/commonMain] 业务Compose UI(LazyVerticalStaggeredGridDemo)
↓
┌──────────┬──────────┬──────────┬──────────┐
│androidApp│desktopApp│webApp │iosApp │
│(Android) │(JVM桌面) │(Wasm‑JS) │(iOS) │
└──────────┴──────────┴──────────┴──────────┘
8.根目录settings.gradle.kts配置
scss
pluginManagement {
repositories {
google {
mavenContent {
includeGroupAndSubgroups("androidx")
includeGroupAndSubgroups("com.android")
includeGroupAndSubgroups("com.google")
}
}
mavenCentral()
gradlePluginPortal()
maven ("https://repo.huaweicloud.com/repository/maven/")
maven ("https://jitpack.io")
}
}
dependencyResolutionManagement {
repositories {
google{
mavenContent {
includeGroupAndSubgroups("androidx")
includeGroupAndSubgroups("com.android")
includeGroupAndSubgroups("com.google")
}
}
mavenCentral()
maven ("https://repo.huaweicloud.com/repository/maven/")
maven ("https://jitpack.io")
}
}
rootProject.name = "AndroidKMPDemo"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
include(":androidApp")
include(":desktopApp")
include(":shared")
include(":webApp")
9.项目测试代码:
9.1 主界面:
分为横向瀑布流和竖向瀑布流
scss
package com.staggeredgrid.kmpdemo
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.ScrollableDefaults
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.staggeredgrid.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlin.random.Random
data class ListItem(
val height: Dp,
val color: Color
)
fun generateItems(count: Int = 100): List<ListItem> {
return (1..count).map {
ListItem(
height = Random.nextInt(100, 300).dp,
color = Color(Random.nextLong(0XFFFFFF)).copy(alpha = 1f)
)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun LazyVerticalStaggeredGridDemo() {
val items = generateItems()
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Adaptive(110.dp),
modifier = Modifier.fillMaxSize(),
state = rememberLazyStaggeredGridState(),
contentPadding = PaddingValues(16.dp),
verticalItemSpacing = 16.dp,
horizontalArrangement = Arrangement.spacedBy(16.dp),
flingBehavior = ScrollableDefaults.flingBehavior(),
userScrollEnabled = true
) {
items(items) { item ->
VerticalRandomColorBox(item)
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun LazyHorizontalStaggeredGridDemo() {
val items = generateItems()
LazyHorizontalStaggeredGrid(
rows = StaggeredGridCells.Adaptive(110.dp),
modifier = Modifier.fillMaxSize(),
state = rememberLazyStaggeredGridState(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalItemSpacing = 16.dp,
flingBehavior = ScrollableDefaults.flingBehavior(),
userScrollEnabled = true
) {
items(items) { item ->
HorizontalRandomColorBox(item)
}
}
}
@Composable
fun VerticalRandomColorBox(item: ListItem) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(item.height)
.clip(RoundedCornerShape(10.dp))
.background(item.color)
)
}
@Composable
fun HorizontalRandomColorBox(item: ListItem) {
Box(
modifier = Modifier
.width(200.dp)
.fillMaxHeight()
.clip(RoundedCornerShape(10.dp))
.background(item.color)
)
}
9.2 调用代码:
kotlin
package com.staggeredgrid.kmpdemo
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent(){
LazyVerticalStaggeredGridDemo()
}
}
}
@Preview
@Composable
fun AppAndroidPreview() {
LazyVerticalStaggeredGridDemo()
}
10.实现效果:
ios由于没有环境暂时不运行了有设备的同学可以试试,后面有设备了在运行一下。
Android端:

桌面:

web:
