UIKit 是一个以 Fluent Design 为基础,融合了 Apple 设计精神的一个现代、简约的 Compose Multiplatform 组件库,致力于在 Windows 与 Android 两主要平台上打造出 Apple iOS 级别的视觉与交互体验;绝大多数组件完全自绘,在多端呈现一致的视觉与交互体验,同时对于部分控件做出桌面端与移动端差异性,以提高跨平台应用的交互体验
如果你希望在 Compose Multiplatform 中快速尝试 Material Design 之外的设计风格,UIKit 一定能满足你的需求
当前 UIKit 仍处于开发阶段,控件尚不齐全
- 跨平台一致性: 所有组件核心代码均在 commonMain 中使用纯 Compose 实现,需要的平台特性均在其余平台提供了 Fallback
- 快捷调用与高自定义性: 大部分控件提供了多层 API,既可以使用简单几行代码创建一个漂亮的默认配置控件,也可以使用更底层的 API 实现更多属性的自定义
- 完整的主题体系:
UIKitTheme提供了颜色、排版、形状、布局、动画、材质六项可自定义的可变主题,默认内置了亮色与暗色配置,你只需使用UIKitThemeHost包裹你的应用根并传入主题配置,你就可以在应用的任何地方使用getUIKitTheme获取并使用主题 - 流畅的动画系统: UIKit 主张一切都拥有过渡,动画与过渡动画渗透了 UIKit 的每一处设计
- 强大的符号系统: UIKit Symbols 提供了强大的动画能力与扩展性,并提供了一套基于 FluentUI System Icons 的内置符号集,并在其基础上深入设计,为符号提供了可编程动画、分层渲染等功能
| 平台 | 支持情况 |
|---|---|
| Android (minSdk 24) | 🟢 |
| iOS | 🟡 (大部分支持) |
| Windows (JVM) | 🟢 |
| macOS (JVM) | 🟡 (理论完全支持) |
| Linux (JVM) | 🟡 (理论完全支持) |
当前 UIKit 专注于 Android 及 Windows (JVM) 平台,Android 平台(移动端)优先
由于我并没有 Mac 或 iPhone 设备,无法测试及开发 iOS 平台,虽项目绝大多数为 Compose 跨平台自绘,但缺少实机测试的 iOS 平台中兼容性及使用体验存疑
如果你拥有一台 Mac 设备且了解 iOS 开发,并且对此项目感兴趣的话,欢迎对此项目做出一份贡献
macOS 及 Linux 端同样没有经过实机测试,不过由于同属 JVM,故绝大多数内容不会有问题
你可以使用 JetBrains IntelliJ IDEA 打开此项目,并确保你已经安装并配置 JDK、Gradle 以及 Kotlin Multiplatform 扩展,该项目开发时的 JDK 及 Gradle 版本如下(推荐):
- JDK 21
- Gradle 9.5
等待 Gradle 完成加载后,你可以直接启动 *Example 或在你的项目中使用
当前 UIKit 还未发布到 Maven,你可以将其发布到本地并引用:
git clone https://github.com/MillenTec/UIKit.git
cd UIKit/src
./gradlew :uikitMain:publishToMavenLocal然后在你需要引用 UIKit 的项目中:
// settings.gradle.kts - 仓库配置
repositories {
mavenLocal()
// ... 其他仓库
}
// build.gradle.kts - 依赖配置(commonMain)
dependencies {
implementation("com.millentec.uikit:uikit:0.0.1-dev")
}然后重新同步 Gradle 项目,测试 UIKit 能否正常使用
在 UIKitTheme 中,你可以通过 getLight() 或 getDark() 来获取默认的亮色或暗色主题并传入 UIKitThemeHost 中,直接创建 UIKitTheme 实例即默认为亮色主题
@Composable
fun App() {
UIKitThemeHost(UIKitTheme.getLight()) {
Box(
Modifier
.fillMaxSize()
.background(getUIKitColors().contentFillColorPrimaryBrush)
)
}
}UIKitThemeHost 本质是一个 CompositionLocalProvider,访问主题的 getUIKitColors() 写法等价于 UIKitTheme.LocalTheme.current.colors;若在应用上层没有使用 UIKitThemeHost 包裹,那么 getUIKitTheme 默认为亮色
你可以在你的应用程序中创建一个可观察属性并将其传入 UIKitThemeHost,通过改变它以改变主题
@Composable
fun App() {
val checked = remember { mutableStateOf(false) }
UIKitThemeHost(
if (checked.value) UIKitTheme.getDark() else UIKitTheme.getLight()
) {
Box(
Modifier
.fillMaxSize()
.background(getUIKitColors().contentFillColorPrimaryBrush)
) {
UIKitToggleSwitch(
checked = checked.value,
onCheckedChange = {
checked.value = it
}
)
}
}
}UIKit 提供了一套受 SF Symbols 设计启发的符号系统 UIKit Symbols,并内置了基于 FluentUI System Icons 的符号,使得你可以通过简单的 API 在 UI 中绘制各种复杂动画逻辑的符号
Tip
此前还提供一套基于 ImageVector 的 FluentIcons 图标集,现将逐步弃用转移至 UIKit Symbols,你可以通过兼容层将 ImageVector 转换并创建为可用的 UIKit Symbol
UIKitImageVectorSymbol(imageVector)内置的 UIKit Symbols 可以通过 UIKitSymbols 入口调用
UIKitSymbols.systemUI.AddCircle每个符号都是 UIKitSymbol 抽象类的子类对象,它们负责存储对于绘制行为的描述,图标的绘制由 UIKitIcon 可组合项进行
UIKitIcon(
modifier = Modifier
.size(32.dp),
symbol = UIKitSymbols.systemUI.AddCircle,
contentDescription = "Add",
symbolStyle = UIKitSymbolStyle.MultiColor,
symbolEffect = UIKitSymbolEffect()
.visibleEffect(true)
)symbolStyle 参数是 UIKitIcon 的一个重要参数,它决定了图标的着色模式,UIKit Symbols 提供了以下四种着色模式及一个辅助着色模式
- Monochrome: 单色着色,可传入一个画刷并整体使用
- Hierarchical: 分层着色,可传入一个画刷并整体使用,同时内部会对各个层施加不同的透明度,可以为符号提高层次感或区分视觉优先级
- MultiColor: 多色,使用符号内置的配色,让图标拥有更好的语义着色或反映图标现实原型的颜色
- Palette: 调色板,你可以为每层传入不同的颜色以获得最高自定义性
- PaletteWithId: 作为调色板的辅助方案,你可以通过 ID 以更好地为各层图标精准着色
UIKit Symbols 提供了 UIKitSymbolEffect 系统以添加动画,你可以链式调用各个动画 Effect 并传入触发器;UIKitSymbolEffect 主要有两种不同类型
- 离散: 通过
trigger触发,每当 trigger 变动时播放一次或多次动画val trigger = remember { mutableStateOf(0) } UIKitIcon( symbol = UIKitSymbols.shapes.Layer, contentDescription = "Layer", symbolStyle = UIKitSymbolStyle.MultiColor, symbolEffect = UIKitSymbolEffect() .bounceEffect(trigger, repeat = 1) )
- 无限: 通过
isActive布尔属性控制,当其为 true 时持续播放周期性动画,部分无限动画提供了离散版本,可以在 trigger 变化时播放一次或多次周期UIKitIcon( symbol = UIKitSymbols.media.Volume, contentDescription = "Volume", symbolStyle = UIKitSymbolStyle.MultiColor, symbolEffect = UIKitSymbolEffect() .variableColorEffect(isActive = true) )
在内部,图标通过 UIKitSymbolAnimTree 编排动画,可以添加串、并行节点并链式调用
如果你不满足于内置的动画,你可以通过 customEffect 传入自定义的 UIKitSymbolAnimTree
UIKit Symbols 支持自定义,只需要继承 UIKitSymbol 抽象基类,即可创建一个自定义符号,我们推荐使用 对象 (object) 而不是类来作为符号载体
你可以创建一个 UIKitSymbol 子对象,并实现 layers 属性,在其中使用 DSL 描述符号矢量路径,并实现 colorSet 方法定义着色,abilityStatement 属性声明能力
object MySymbol: UIKitSymbol(
name = "MySymbol",
defaultSize = DpSize(20.dp, 20.dp),
viewportSize = Size(20f, 20f),
) {
override val layers: List<UIKitSymbolLayer> = listOf(
UIKitSymbolLayer("layer0").apply {
group(
id = "group0",
drawType = UIKitPathDrawType.Fill
) {
moveTo(10f, 2f)
curveTo(5.6f, 2f, 2f, 5.6f, 2f, 10f)
// ...
}
}
)
override val abilityStatement: List<UIKitSymbolAbility> = listOf(
UIKitSymbolAbility.Appear
// ...
)
@Composable
override fun colorSet(
style: UIKitSymbolStyle,
states: List<Pair<String, UIKitSymbolGroupState>>
): List<UIKitSymbolColor> {
// ...
}
}如果你希望为图标设定动画,你可以覆写 *Effect 系列方法以返回一个 UIKitSymbolAnimTree,或返回 null 则使此动画不支持(调用时无事发生)
在 UIKit 中提供了 AcrylicMaterial, 它包含一个背景模糊和边缘高光,可以在 UIKitAcrylicMaterial 中配置默认属性
背景模糊效果由开源库 Cloudy 支持
要使用亚克力材质,应该先使用 rememberAcrylicMaterialState 创建一个 State,然后设置 Source 并为容器添加材质
Box {
val state = rememberAcrylicMaterialState()
Box(
modifier = Modifier
.acrylicMaterialSource(state)
) {
// ...
}
Box(
modifier = Modifier
.acrylicMaterial(state = state)
) {
// ...
}
}Important
绝对不能在 AcrylicMaterialSource 的子级使用同一个 State 的 AcrylicMaterial,即一个 AcrylicMaterial 的 Source 不能是自己,否则会导致程序崩溃:
Box {
val state = rememberAcrylicMaterialState()
Box(
modifier = Modifier
.acrylicMaterialSource(state)
) {
Box(
modifier = Modifier
.acrylicMaterial(state = state) // ❌ 这么做会导致程序崩溃
) {
// ...
}
}
}本项目基于 MIT License 开源,这意味着你获得了:
- 在不受限制的情况下处理本软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本
但是你应当:
- 保留版权声明: 版权声明和许可声明应包含在软件的所有副本或主要部分中
同时 UIKit 离不开开源社区的支持,UIKit 使用的所有第三方开源软件及其许可证在 THIRD_PARTY.txt 列出
我是来自中国的一名高中生,一名科技爱好者,编程爱好者,独立学习并开发软件,爱好二次元、动漫;我在今年(2026年)5月份时初识了 Kotlin 这门语言和 Compose Multiplatform 框架,并喜欢上了这种声明式 UI 框架,从此开始深入学习和使用此语言和框架,并于同年7月初中学业水平考试结束后开始投入到 UIKit 的开发
如果你喜欢 UIKit 的话,请给我一个 Star 吧
