fragmject is a learning project prepared for Kotlin and Jetpack Compose. | fragmject 是一个为初学者准备的上手项目。 通过对 Kotlin 和 Compose 的系统运用,实现的一个功能完备符合主流市场标准 App。 fragmject 没有复杂的业务和多余的封装, 完全依照 Android Developer 官方的写法。 代码简单,内容全面,快速上手,对理解其他项目设计思想和封装技巧也很有帮助。
Kotlin
1,467
598 commits
updated Oct 17, 2026
Read this in English
刚开始学习 Kotlin 其实挺痛苦的,相关的书籍或视频偏向于知识点的讲解,没有完整的项目实操。
开源项目业务复杂,代码层层封装,用来上手实在不合适,于是便有了 fragmject 项目。
在此感谢 玩Android 及其提供 开放API 。
fragmject 是一个为初学者准备的上手项目。
通过对 Kotlin 和 Compose 的系统运用,实现的一个功能完备符合主流市场标准应用。
fragmject 没有复杂的业务和多余的封装, 完全依照 Android Developer 官方的写法。
代码简单,内容全面,快速上手,对理解其他项目设计思想和封装技巧也很有帮助。
core + feature + app)NavBackStack + NavDisplay)学习本项目你将有如下收获:
build-logic)以 JVM 21 为目标编译,Gradle 需运行在 JDK 21 或更高版本上,低版本会在配置阶段报 requires at least JVM runtime version 21。Android Studio 请在 Settings > Build Tools > Gradle 中选择 Android Studio default JDK(内置 JBR 满足要求);命令行请让 JAVA_HOME 指向 JDK 21+。项目未配置 toolchain 自动下载,也不强制某个精确版本。keystore.properties / keystore.key 是测试专用密钥,入库为有意设计;正式发布请使用独立的私有签名。.github/workflows/ci.yml 会在 PR 与主分支上运行模块依赖守卫、Compose 稳定性校验和全部单元测试(含 ArchitectureTest)。为了您能正常运行本项目,请先更新你的 Android Studio (可能需要梯子)。
Download Android Studio | Android Developer
您也可以自行配置 AGP 和 compose来进行适配。 libs.versions.toml
将 build 迁移到版本目录 | Android Developer
在学习前希望您能了解以下知识,这将帮助您更快的上手本项目。
如果你更希望以较少的封装、更直白的代码快速上手,建议切换到 v1.4.0 标签版本,该版本保留了更简洁的实现,没有复杂的架构分层与封装,更容易理解和学习。
![]() | ![]() | ![]() |
|---|
├── app app 壳工程
| └── src
| └── main
| | ├── assets assets 目录(HTML/JS/JSON 测试数据)
| | └── java 源码目录
| | ├── MainActivity.kt 唯一 Activity
| | ├── FragmjectApplication.kt Application(Hilt 入口)
| | └── AppNavGraph.kt 导航图(Navigation 3 + WindowSizeClass 自适应)
| |
| ├── build.gradle.kts 模块构建配置
| ├── dictionary 自定义混淆字典
| └── proguard-rules.pro 代码混淆配置文件
|
├── core 核心层(基础能力,不依赖业务)
| ├── android-platform 平台与进程级能力(AppScope / BaseContentProvider / File* / CacheUtils / UriPathUtils)
| ├── data-contract 数据端口契约(remote/local DataSource + HTTP 协议模型)
| ├── data-repository 数据实现(RepositoryImpl / PagingSource / Hilt 绑定)
| ├── database 数据库(Room 3)
| ├── designsystem 设计系统(AppTheme / WindowSizeClass / 颜色 / 间距,不含组件)
| ├── domain 领域层(Repository 接口 + UseCase + DomainResult)
| ├── image-editor 图片编辑引擎(画布 / 裁剪 / 编码 / 落盘)
| ├── model 数据模型
| ├── navigation-contract 导航契约(语义 Navigator,跨 feature 解耦)
| ├── navigation-runtime 导航能力(Navigation 3 类型安全路由)
| ├── network 网络层(Retrofit + OkHttp)
| ├── qrscanner 扫码能力(CameraX / ML Kit)
| ├── ui UI 组件库(FeedCard / PagingSwipeRefreshBox 等)
| └── webview WebView 能力(池化 / 缓存 / CookieStore)
|
├── feature 功能模块层(每个模块均含 api / impl 两个子模块)
| ├── article 文章模块(WebView 详情 / 下载)
| | ├── api API 层(NavKey 定义)
| | └── impl 实现层(Screen / ViewModel)
| ├── auth 登录 / 注册
| ├── authenticator 动态口令(OTP 账户管理 / 密钥 Keystore 加密)
| ├── collection 收藏 / 分享
| ├── demo 组件 Demo(日历 / 滚轮 / 扫码 / 嵌套滚动等)
| ├── home 首页(Home / Nav / Project / System / My)
| ├── picture 图片模块(选择器 / 预览 / 编辑器)
| ├── search 搜索
| └── user 用户(主页 / 积分 / 排行 / 设置 / 历史)
|
├── build-logic 构建逻辑(Gradle Convention 插件)
| └── convention
| └── src/main/kotlin
| ├── FragmjectAndroidApplicationPlugin application 约定插件
| ├── FragmjectAndroidComposePlugin compose 约定插件
| ├── FragmjectKotlinParcelizePlugin Kotlin Parcelize 能力插件
| ├── FragmjectKotlinSerializationPlugin Kotlin Serialization 能力插件
| ├── FragmjectAndroidHiltPlugin Hilt 约定插件
| ├── FragmjectAndroidLibraryPlugin library 约定插件
| ├── FragmjectAndroidDependencyGuardPlugin dependency 校验插件
| └── FragmjectAndroidRoomPlugin Room 约定插件
|
├── gradle
| └── libs.versions.toml 版本目录(统一依赖管理)
|
├── build.gradle.kts 项目构建配置
├── config.properties 项目配置
├── gradle.properties gradle 配置
└── settings.gradle.kts 项目模块依赖配置
项目基于 material3-window-size-class 实现了完整的大屏/折叠屏自适应布局。
| 窗口尺寸 | 宽度 | 导航组件 | 详情展示 |
|---|---|---|---|
| Compact | < 600dp | NavigationBar(底部导航栏) | 全屏推入 |
| Medium | 600–840dp | NavigationDrawerItem + Surface(左侧导航) | 全屏推入 |
| Expanded | ≥ 840dp | PermanentNavigationDrawer(常驻侧栏) | 右侧面板同屏 |
Expanded 模式下(平板横屏/桌面),点击文章、用户主页、系统设置等页面不再全屏跳转,而是在右侧面板渲染:
graph LR
A["列表 (50%)"] --> B["DetailPane (50%)"]
B --> C["WebScreen"]
B --> D["UserScreen"]
B --> E["SettingScreen"]
B --> F["..."]
CompositionLocal 注入 + 便捷扩展NavKey,传递给 DetailPaneDetailPane 路由val windowSizeClass = LocalWindowSizeClass.current
when (windowSizeClass.widthSizeClass) {
WindowWidthSizeClass.Compact -> CompactLayout()
WindowWidthSizeClass.Medium -> MediumLayout()
WindowWidthSizeClass.Expanded -> ExpandedLayout()
}
如果你暂时不需要 Compose ,可以切换到 Tags v1.3.0 。
与使用 Android View 系统相比,Compose 可让我们用更少的代码实现更多的功能,这样需要测试和调试的代码会更少,出现 bug 的可能性也更小。对于审核人员或维护人员,需要阅读、理解、审核和维护的代码就更少。
Compose 的布局系统在概念上更简单,所有代码都使用同一种语言编写并且位于同一文件中,而不必在 Kotlin 和 XML 二者之间来回切换。
Compose 使用声明性API,这意味着您只需描述界面,Compose 会负责完成其余工作。
利用 Compose ,您可以构建不与特定 activity 或 fragment 相关联的小型无状态组件。
在 Compose 中,状态是显式的,并且会传递给相应的可组合项。这样一来,状态便具有单一可信来源,因而是封装和分离的。然后,应用状态变化时,界面会自动更新。
Compose 与您所有的现有代码兼容:您可以从 View 调用 Compose 代码,也可以从 Compose 调用 View 。大多数常用库(如 Navigation 、 ViewModel 和 Kotlin 协程)都适用于 Compose ,因此您可以随时随地开始采用。

SharedFlowBus:30行代码实现消息总线你确定不看吗
// 发送消息
SharedFlowBus.with(objectKey: Class<T>).tryEmit(value: T)
// 发送粘性消息
SharedFlowBus.withSticky(objectKey: Class<T>).tryEmit(value: T)
// 订阅消息
SharedFlowBus.on(objectKey: Class<T>).observe(owner){ it ->
println(it)
}
// 订阅粘性消息
SharedFlowBus.onSticky(objectKey: Class<T>).observe(owner){ it ->
println(it)
}
字节码插桩相关源码(
library-plugin/MiaowPlugin)已从当前分支移除,如需查看完整实现,请切换到 Tags v1.3.0。
├── library-plugin
| └── src
| └── main
| ├── kotlin
| └── resources
| └── statistic.properties 插件配置
|
└── repos 插件生成目录
在 MiaowPlugin 添加 ScanBean 并配置目标字段或方法以及对应的替换字段或方法。
ScanBean(
owner = "android/os/Build",
name = "BRAND",
desc = "Ljava/lang/String;",
replaceOpcode = Opcodes.INVOKESTATIC,
replaceOwner = "com/example/fragment/library/common/utils/BuildUtils",
replaceName = "getBrand",
"()Ljava/lang/String;"
)
在 MiaowPlugin 添加 TimeBean 并配置打印目标或范围。
TimeBean( //以包名和执行时间为条件
"com/example/fragment/library/base",
time = 50L
)
在 MiaowPlugin 添加 TraceBean 并配置埋点目标以及对应埋点方法。
TraceBean(
owner = "Landroid/view/View\$OnClickListener;",
name = "onClick",
desc = "(Landroid/view/View;)V",
traceOwner = "com/example/fragment/library/common/utils/StatisticHelper",
traceName = "viewOnClick",
traceDesc = "(Landroid/view/View;)V" //参数应在desc范围之内
)
配置完成后 gradle 执行 publish 任务生成插件。
在根目录 setting.gradle 添加本地插件源。
pluginManagement {
repositories {
maven {
url uri('repo')
}
}
}
在根目录 build.gradle 添加插件依赖。
buildscript {
dependencies {
classpath 'com.example.miaow:plugin:1.0.0'
}
}
在app目录 build.gradle apply插件。
plugins {
id 'miaow'
}
![]() | ![]() | ![]() |
|---|
└── feature
└── picture
├── api API 层
└── impl 实现层
PictureEditorDialog.newInstance()
.setBitmapPath(path)
.setEditorFinishCallback(object : EditorFinishCallback {
override fun onFinish(path: String) {
val bitmap = BitmapFactory.decodeFile(path, BitmapFactory.Options())
}
})
.show(childFragmentManager)
如上所示:
PictureEditorDialog 调用图片编辑器。setBitmapPath(path) 传入图片路径。setEditorFinishCallback(callback) 获取编辑后的图片地址。如果觉得 PictureEditorDialog 不能满足需求,还可以通过 PictureEditorView 来自定义样式。
<com.example.miaow.picture.editor.PictureEditorView
android:id="@+id/pic_editor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
picEditor.setBitmapPath(path)
picEditor.setMode(PictureEditorView.Mode.STICKER)
picEditor.setGraffitiColor(Color.parseColor("#ffffff"))
picEditor.setSticker(StickerAttrs(bitmap))
picEditor.graffitiUndo()
picEditor.mosaicUndo()
picEditor.saveBitmap()
如上所示:
setBitmapPath(path) 传入图片路径。setMode(mode) 设置编辑模式,分别有:涂鸦,橡皮擦,马赛克,贴纸。setGraffitiColor(color) 设置涂鸦画笔颜色。setSticker(StickerAttrs(bitmap)) 设置贴纸。graffitiUndo() 涂鸦撤销。mosaicUndo() 马赛克撤销。saveBitmap() 保存编辑图片。PictureEditorView 就介绍到这里,具体使用请查看 PictureEditorDialog。
<com.example.miaow.picture.editor.PictureClipView
android:id="@+id/clip"
android:layout_width="match_parent"
android:layout_height="match_parent" />
clip.setBitmapResource(bitmap)
clip.rotate()
clip.reset()
clip.saveBitmap()
如上所示:
setBitmapResource(bitmap) 传入裁剪图片。clip.rotate() 图片旋转。clip.reset() 图片重置。clip.saveBitmap() 保存裁剪框内图片。PictureClipView 就介绍到这里,具体使用请查看 PictureClipDialog。
if (context is AppCompatActivity) {
PictureSelectorDialog.newInstance()
...省略部分代码
.show(context.supportFragmentManager)
}

└── feature
└── demo
└── impl
└── ui
└── calendar
└── CalendarScreen.kt
val calendarState = rememberCalendarState()
calendarState.addSchedule(text)
Calendar(
state = calendarState,
modifier = Modifier.padding(vertical = 15.dp),
onSelectedDateChange = { y, m, d ->
println("CalendarScreen: $y - $m - $d")
}
)
感谢所有优秀的开源项目 ^^
如果喜欢的话希望给个 Star 或 Fork ^^
谢谢~~
fragmject is a learning project prepared for Kotlin and Jetpack Compose. | fragmject 是一个为初学者准备的上手项目。 通过对 Kotlin 和 Compose 的系统运用,实现的一个功能完备符合主流市场标准 App。 fragmject 没有复杂的业务和多余的封装, 完全依照 Android Developer 官方的写法。 代码简单,内容全面,快速上手,对理解其他项目设计思想和封装技巧也很有帮助。
Kotlin
1,467
598 commits
updated Oct 17, 2026
Read this in English
刚开始学习 Kotlin 其实挺痛苦的,相关的书籍或视频偏向于知识点的讲解,没有完整的项目实操。
开源项目业务复杂,代码层层封装,用来上手实在不合适,于是便有了 fragmject 项目。
在此感谢 玩Android 及其提供 开放API 。
fragmject 是一个为初学者准备的上手项目。
通过对 Kotlin 和 Compose 的系统运用,实现的一个功能完备符合主流市场标准应用。
fragmject 没有复杂的业务和多余的封装, 完全依照 Android Developer 官方的写法。
代码简单,内容全面,快速上手,对理解其他项目设计思想和封装技巧也很有帮助。
core + feature + app)NavBackStack + NavDisplay)学习本项目你将有如下收获:
build-logic)以 JVM 21 为目标编译,Gradle 需运行在 JDK 21 或更高版本上,低版本会在配置阶段报 requires at least JVM runtime version 21。Android Studio 请在 Settings > Build Tools > Gradle 中选择 Android Studio default JDK(内置 JBR 满足要求);命令行请让 JAVA_HOME 指向 JDK 21+。项目未配置 toolchain 自动下载,也不强制某个精确版本。keystore.properties / keystore.key 是测试专用密钥,入库为有意设计;正式发布请使用独立的私有签名。.github/workflows/ci.yml 会在 PR 与主分支上运行模块依赖守卫、Compose 稳定性校验和全部单元测试(含 ArchitectureTest)。为了您能正常运行本项目,请先更新你的 Android Studio (可能需要梯子)。
Download Android Studio | Android Developer
您也可以自行配置 AGP 和 compose来进行适配。 libs.versions.toml
将 build 迁移到版本目录 | Android Developer
在学习前希望您能了解以下知识,这将帮助您更快的上手本项目。
如果你更希望以较少的封装、更直白的代码快速上手,建议切换到 v1.4.0 标签版本,该版本保留了更简洁的实现,没有复杂的架构分层与封装,更容易理解和学习。
![]() | ![]() | ![]() |
|---|
├── app app 壳工程
| └── src
| └── main
| | ├── assets assets 目录(HTML/JS/JSON 测试数据)
| | └── java 源码目录
| | ├── MainActivity.kt 唯一 Activity
| | ├── FragmjectApplication.kt Application(Hilt 入口)
| | └── AppNavGraph.kt 导航图(Navigation 3 + WindowSizeClass 自适应)
| |
| ├── build.gradle.kts 模块构建配置
| ├── dictionary 自定义混淆字典
| └── proguard-rules.pro 代码混淆配置文件
|
├── core 核心层(基础能力,不依赖业务)
| ├── android-platform 平台与进程级能力(AppScope / BaseContentProvider / File* / CacheUtils / UriPathUtils)
| ├── data-contract 数据端口契约(remote/local DataSource + HTTP 协议模型)
| ├── data-repository 数据实现(RepositoryImpl / PagingSource / Hilt 绑定)
| ├── database 数据库(Room 3)
| ├── designsystem 设计系统(AppTheme / WindowSizeClass / 颜色 / 间距,不含组件)
| ├── domain 领域层(Repository 接口 + UseCase + DomainResult)
| ├── image-editor 图片编辑引擎(画布 / 裁剪 / 编码 / 落盘)
| ├── model 数据模型
| ├── navigation-contract 导航契约(语义 Navigator,跨 feature 解耦)
| ├── navigation-runtime 导航能力(Navigation 3 类型安全路由)
| ├── network 网络层(Retrofit + OkHttp)
| ├── qrscanner 扫码能力(CameraX / ML Kit)
| ├── ui UI 组件库(FeedCard / PagingSwipeRefreshBox 等)
| └── webview WebView 能力(池化 / 缓存 / CookieStore)
|
├── feature 功能模块层(每个模块均含 api / impl 两个子模块)
| ├── article 文章模块(WebView 详情 / 下载)
| | ├── api API 层(NavKey 定义)
| | └── impl 实现层(Screen / ViewModel)
| ├── auth 登录 / 注册
| ├── authenticator 动态口令(OTP 账户管理 / 密钥 Keystore 加密)
| ├── collection 收藏 / 分享
| ├── demo 组件 Demo(日历 / 滚轮 / 扫码 / 嵌套滚动等)
| ├── home 首页(Home / Nav / Project / System / My)
| ├── picture 图片模块(选择器 / 预览 / 编辑器)
| ├── search 搜索
| └── user 用户(主页 / 积分 / 排行 / 设置 / 历史)
|
├── build-logic 构建逻辑(Gradle Convention 插件)
| └── convention
| └── src/main/kotlin
| ├── FragmjectAndroidApplicationPlugin application 约定插件
| ├── FragmjectAndroidComposePlugin compose 约定插件
| ├── FragmjectKotlinParcelizePlugin Kotlin Parcelize 能力插件
| ├── FragmjectKotlinSerializationPlugin Kotlin Serialization 能力插件
| ├── FragmjectAndroidHiltPlugin Hilt 约定插件
| ├── FragmjectAndroidLibraryPlugin library 约定插件
| ├── FragmjectAndroidDependencyGuardPlugin dependency 校验插件
| └── FragmjectAndroidRoomPlugin Room 约定插件
|
├── gradle
| └── libs.versions.toml 版本目录(统一依赖管理)
|
├── build.gradle.kts 项目构建配置
├── config.properties 项目配置
├── gradle.properties gradle 配置
└── settings.gradle.kts 项目模块依赖配置
项目基于 material3-window-size-class 实现了完整的大屏/折叠屏自适应布局。
| 窗口尺寸 | 宽度 | 导航组件 | 详情展示 |
|---|---|---|---|
| Compact | < 600dp | NavigationBar(底部导航栏) | 全屏推入 |
| Medium | 600–840dp | NavigationDrawerItem + Surface(左侧导航) | 全屏推入 |
| Expanded | ≥ 840dp | PermanentNavigationDrawer(常驻侧栏) | 右侧面板同屏 |
Expanded 模式下(平板横屏/桌面),点击文章、用户主页、系统设置等页面不再全屏跳转,而是在右侧面板渲染:
graph LR
A["列表 (50%)"] --> B["DetailPane (50%)"]
B --> C["WebScreen"]
B --> D["UserScreen"]
B --> E["SettingScreen"]
B --> F["..."]
CompositionLocal 注入 + 便捷扩展NavKey,传递给 DetailPaneDetailPane 路由val windowSizeClass = LocalWindowSizeClass.current
when (windowSizeClass.widthSizeClass) {
WindowWidthSizeClass.Compact -> CompactLayout()
WindowWidthSizeClass.Medium -> MediumLayout()
WindowWidthSizeClass.Expanded -> ExpandedLayout()
}
如果你暂时不需要 Compose ,可以切换到 Tags v1.3.0 。
与使用 Android View 系统相比,Compose 可让我们用更少的代码实现更多的功能,这样需要测试和调试的代码会更少,出现 bug 的可能性也更小。对于审核人员或维护人员,需要阅读、理解、审核和维护的代码就更少。
Compose 的布局系统在概念上更简单,所有代码都使用同一种语言编写并且位于同一文件中,而不必在 Kotlin 和 XML 二者之间来回切换。
Compose 使用声明性API,这意味着您只需描述界面,Compose 会负责完成其余工作。
利用 Compose ,您可以构建不与特定 activity 或 fragment 相关联的小型无状态组件。
在 Compose 中,状态是显式的,并且会传递给相应的可组合项。这样一来,状态便具有单一可信来源,因而是封装和分离的。然后,应用状态变化时,界面会自动更新。
Compose 与您所有的现有代码兼容:您可以从 View 调用 Compose 代码,也可以从 Compose 调用 View 。大多数常用库(如 Navigation 、 ViewModel 和 Kotlin 协程)都适用于 Compose ,因此您可以随时随地开始采用。

SharedFlowBus:30行代码实现消息总线你确定不看吗
// 发送消息
SharedFlowBus.with(objectKey: Class<T>).tryEmit(value: T)
// 发送粘性消息
SharedFlowBus.withSticky(objectKey: Class<T>).tryEmit(value: T)
// 订阅消息
SharedFlowBus.on(objectKey: Class<T>).observe(owner){ it ->
println(it)
}
// 订阅粘性消息
SharedFlowBus.onSticky(objectKey: Class<T>).observe(owner){ it ->
println(it)
}
字节码插桩相关源码(
library-plugin/MiaowPlugin)已从当前分支移除,如需查看完整实现,请切换到 Tags v1.3.0。
├── library-plugin
| └── src
| └── main
| ├── kotlin
| └── resources
| └── statistic.properties 插件配置
|
└── repos 插件生成目录
在 MiaowPlugin 添加 ScanBean 并配置目标字段或方法以及对应的替换字段或方法。
ScanBean(
owner = "android/os/Build",
name = "BRAND",
desc = "Ljava/lang/String;",
replaceOpcode = Opcodes.INVOKESTATIC,
replaceOwner = "com/example/fragment/library/common/utils/BuildUtils",
replaceName = "getBrand",
"()Ljava/lang/String;"
)
在 MiaowPlugin 添加 TimeBean 并配置打印目标或范围。
TimeBean( //以包名和执行时间为条件
"com/example/fragment/library/base",
time = 50L
)
在 MiaowPlugin 添加 TraceBean 并配置埋点目标以及对应埋点方法。
TraceBean(
owner = "Landroid/view/View\$OnClickListener;",
name = "onClick",
desc = "(Landroid/view/View;)V",
traceOwner = "com/example/fragment/library/common/utils/StatisticHelper",
traceName = "viewOnClick",
traceDesc = "(Landroid/view/View;)V" //参数应在desc范围之内
)
配置完成后 gradle 执行 publish 任务生成插件。
在根目录 setting.gradle 添加本地插件源。
pluginManagement {
repositories {
maven {
url uri('repo')
}
}
}
在根目录 build.gradle 添加插件依赖。
buildscript {
dependencies {
classpath 'com.example.miaow:plugin:1.0.0'
}
}
在app目录 build.gradle apply插件。
plugins {
id 'miaow'
}
![]() | ![]() | ![]() |
|---|
└── feature
└── picture
├── api API 层
└── impl 实现层
PictureEditorDialog.newInstance()
.setBitmapPath(path)
.setEditorFinishCallback(object : EditorFinishCallback {
override fun onFinish(path: String) {
val bitmap = BitmapFactory.decodeFile(path, BitmapFactory.Options())
}
})
.show(childFragmentManager)
如上所示:
PictureEditorDialog 调用图片编辑器。setBitmapPath(path) 传入图片路径。setEditorFinishCallback(callback) 获取编辑后的图片地址。如果觉得 PictureEditorDialog 不能满足需求,还可以通过 PictureEditorView 来自定义样式。
<com.example.miaow.picture.editor.PictureEditorView
android:id="@+id/pic_editor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
picEditor.setBitmapPath(path)
picEditor.setMode(PictureEditorView.Mode.STICKER)
picEditor.setGraffitiColor(Color.parseColor("#ffffff"))
picEditor.setSticker(StickerAttrs(bitmap))
picEditor.graffitiUndo()
picEditor.mosaicUndo()
picEditor.saveBitmap()
如上所示:
setBitmapPath(path) 传入图片路径。setMode(mode) 设置编辑模式,分别有:涂鸦,橡皮擦,马赛克,贴纸。setGraffitiColor(color) 设置涂鸦画笔颜色。setSticker(StickerAttrs(bitmap)) 设置贴纸。graffitiUndo() 涂鸦撤销。mosaicUndo() 马赛克撤销。saveBitmap() 保存编辑图片。PictureEditorView 就介绍到这里,具体使用请查看 PictureEditorDialog。
<com.example.miaow.picture.editor.PictureClipView
android:id="@+id/clip"
android:layout_width="match_parent"
android:layout_height="match_parent" />
clip.setBitmapResource(bitmap)
clip.rotate()
clip.reset()
clip.saveBitmap()
如上所示:
setBitmapResource(bitmap) 传入裁剪图片。clip.rotate() 图片旋转。clip.reset() 图片重置。clip.saveBitmap() 保存裁剪框内图片。PictureClipView 就介绍到这里,具体使用请查看 PictureClipDialog。
if (context is AppCompatActivity) {
PictureSelectorDialog.newInstance()
...省略部分代码
.show(context.supportFragmentManager)
}

└── feature
└── demo
└── impl
└── ui
└── calendar
└── CalendarScreen.kt
val calendarState = rememberCalendarState()
calendarState.addSchedule(text)
Calendar(
state = calendarState,
modifier = Modifier.padding(vertical = 15.dp),
onSelectedDateChange = { y, m, d ->
println("CalendarScreen: $y - $m - $d")
}
)
感谢所有优秀的开源项目 ^^
如果喜欢的话希望给个 Star 或 Fork ^^
谢谢~~