├── .gitignore ├── LICENSE ├── README.md ├── README_CN.md ├── build.gradle ├── docs ├── .nojekyll ├── README.md ├── _sidebar.md ├── apis │ ├── commonapis.md │ └── designapis.md ├── img │ ├── alignCenter.png │ ├── alignOpposite.png │ ├── backgroudColor.png │ ├── blur.png │ ├── bold.png │ ├── bullet.png │ ├── color.png │ ├── fontFamily.png │ ├── image.png │ ├── italic.png │ ├── leadingMargin.png │ ├── quote.png │ ├── scale.png │ ├── size.png │ ├── space.png │ ├── strikeThrough.png │ ├── subscript.png │ ├── superscript.png │ ├── underline.png │ └── url.png ├── index.html ├── others │ └── q&a.md └── usage │ ├── activity.md │ ├── activityresult.md │ ├── customview.md │ ├── datetime.md │ ├── dialogs.md │ ├── fragment.md │ ├── intents.md │ ├── json.md │ ├── keyboard.md │ ├── logger.md │ ├── mmkv.md │ ├── permissions.md │ ├── spannablestring.md │ ├── systembars.md │ ├── uri.md │ └── viewmodels.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── longan-design ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dylanc │ │ └── longan │ │ └── design │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── dylanc │ │ └── longan │ │ └── design │ │ ├── Dialogs.kt │ │ ├── Internal.kt │ │ ├── RecyclerView.kt │ │ ├── Snackbar.kt │ │ ├── TabLayout.kt │ │ └── ViewPager2.kt │ └── test │ └── java │ └── com │ └── dylanc │ └── longan │ └── design │ └── ExampleUnitTest.kt ├── longan ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dylanc │ │ └── longan │ │ ├── DateTimeTest.kt │ │ ├── ExampleInstrumentedTest.kt │ │ └── StringTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── dylanc │ │ │ └── longan │ │ │ ├── Activity.kt │ │ │ ├── ActivityResult.kt │ │ │ ├── Annotations.kt │ │ │ ├── AppInitializer.kt │ │ │ ├── Application.kt │ │ │ ├── Arrays.kt │ │ │ ├── Bluetooth.kt │ │ │ ├── Bundle.kt │ │ │ ├── Canvas.kt │ │ │ ├── Clipboard.kt │ │ │ ├── Collections.kt │ │ │ ├── ContentResolver.kt │ │ │ ├── Crash.kt │ │ │ ├── DateTime.kt │ │ │ ├── DeviceInfo.kt │ │ │ ├── Dimensions.kt │ │ │ ├── DownloadManager.kt │ │ │ ├── Encode.kt │ │ │ ├── Encrypt.kt │ │ │ ├── File.kt │ │ │ ├── Flow.kt │ │ │ ├── Fragment.kt │ │ │ ├── Intents.kt │ │ │ ├── Internal.kt │ │ │ ├── Keyboard.kt │ │ │ ├── Lifecycle.kt │ │ │ ├── Location.kt │ │ │ ├── Logger.kt │ │ │ ├── MetaData.kt │ │ │ ├── MultiLanguage.kt │ │ │ ├── Network.kt │ │ │ ├── Paths.kt │ │ │ ├── PdfDocument.kt │ │ │ ├── Resource.kt │ │ │ ├── Rom.kt │ │ │ ├── Screen.kt │ │ │ ├── Share.kt │ │ │ ├── Shell.kt │ │ │ ├── Spannable.kt │ │ │ ├── String.kt │ │ │ ├── SystemBars.kt │ │ │ ├── TextView.kt │ │ │ ├── Threads.kt │ │ │ ├── Toast.kt │ │ │ ├── Uri.kt │ │ │ ├── View.kt │ │ │ ├── ViewModel.kt │ │ │ └── activityresult │ │ │ ├── ActivityResultLauncher.kt │ │ │ ├── CreateDocument.kt │ │ │ ├── CropPicture.kt │ │ │ ├── EnableBluetooth.kt │ │ │ ├── EnableLocation.kt │ │ │ ├── GetContent.kt │ │ │ ├── GetMultipleContents.kt │ │ │ ├── LaunchAppSettings.kt │ │ │ ├── LaunchNotificationSettings.kt │ │ │ ├── LaunchWifiSettings.kt │ │ │ ├── OpenDocument.kt │ │ │ ├── OpenDocumentTree.kt │ │ │ ├── OpenMultipleDocuments.kt │ │ │ ├── PickContact.kt │ │ │ ├── PickContent.kt │ │ │ ├── RequestMultiplePermissions.kt │ │ │ ├── RequestPermission.kt │ │ │ ├── StartActivityForResult.kt │ │ │ ├── StartIntentSenderForResult.kt │ │ │ ├── TakePicture.kt │ │ │ ├── TakePicturePreview.kt │ │ │ └── TakeVideo.kt │ └── res │ │ ├── layout │ │ └── design_layout_snackbar_include.xml │ │ └── values │ │ └── ids.xml │ └── test │ └── java │ └── com │ └── dylanc │ └── longan │ └── ExampleUnitTest.kt ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dylanc │ │ └── longan │ │ └── sample │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── dylanc │ │ │ └── longan │ │ │ └── sample │ │ │ ├── App.kt │ │ │ └── ui │ │ │ ├── ActivityResultActivity.kt │ │ │ ├── DialogsActivity.kt │ │ │ ├── InputTextActivity.kt │ │ │ ├── MainActivity.kt │ │ │ ├── PictureActivity.kt │ │ │ └── SpannableStringActivity.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xhdpi │ │ └── leaf.png │ │ ├── drawable │ │ ├── ic_baseline_arrow_back_24.xml │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_input_text.xml │ │ ├── activity_picture.xml │ │ ├── activity_recycler_view.xml │ │ ├── activity_result.xml │ │ ├── activity_spannable_string.xml │ │ └── item_text.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── file_paths.xml │ └── test │ └── java │ └── com │ └── dylanc │ └── longan │ └── sample │ └── ExampleUnitTest.kt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.buildConfig = [ 3 | 'versionCode' : 1, 4 | 'versionName' : "1.0.0", 5 | 'compileSdkVersion': 30, 6 | 'minSdkVersion' : 21, 7 | 'targetSdkVersion' : 30 8 | ] 9 | ext { 10 | appcompatVersion = '1.3.1' 11 | constraintLayoutVersion = '2.1.1' 12 | coilVersion = '1.4.0' 13 | coreVersion = '1.7.0-alpha01' 14 | espressoVersion = '3.4.0' 15 | glideVersion = '4.12.0' 16 | fragmentVersion = '1.3.6' 17 | lifecycleVersion = '2.4.0-alpha03' 18 | junitExtVersion = '1.1.3' 19 | junitVersion = '4.13.2' 20 | kotlinVersion = "1.5.31" 21 | materialVersion = '1.4.0' 22 | okioVersion = '3.0.0' 23 | starupVersion = '1.1.0' 24 | serializationVersion = "1.2.1" 25 | viewBindingKTXVersion = '2.1.0' 26 | } 27 | repositories { 28 | google() 29 | jcenter() 30 | } 31 | dependencies { 32 | classpath 'com.android.tools.build:gradle:4.2.1' 33 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" 34 | classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion" 35 | } 36 | } 37 | 38 | allprojects { 39 | repositories { 40 | google() 41 | jcenter() 42 | maven { url 'https://www.jitpack.io' } 43 | } 44 | } 45 | 46 | task clean(type: Delete) { 47 | delete rootProject.buildDir 48 | } 49 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Longan 2 | 3 | [![](https://www.jitpack.io/v/DylanCaiCoding/Longan.svg)](https://www.jitpack.io/#DylanCaiCoding/Longan) 4 | [![](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/Longan/blob/master/LICENSE) 5 | [![GitHub Repo stars](https://img.shields.io/github/stars/DylanCaiCoding/Longan?style=social)](https://github.com/DylanCaiCoding/Longan) 6 | 7 | Longan 是一个简化 Android 开发的 Kotlin 工具库,可以使代码更加简洁易读。**目前有超过 500 个常用方法或属性,能有效提高开发效率**。 8 | 9 | 个人认为 API 设计对 Kotlin 工具类来说非常重要,因为 Kotlin 玩法很多,可以设计出很骚的用法,但不一定好用。所以个人花了大量时间去斟酌每一个扩展的用法,每个命名和用法都是经过了非常多的考虑,既要简洁易用又要清晰地描述功能不产生歧义。有的会参考官方 KTX 库的命名规则和用法,与官方用法统一能降低点学习成本。会用尽可能简洁轻量的代码实现功能,有兴趣的可以读下源码。整体会比大多数人封装的工具类好用。 10 | 11 | 本库会长期维护,有任何使用上的问题或者想要的功能都可以反馈。 12 | 13 | ## Gradle 14 | 15 | 在根目录的 build.gradle 添加: 16 | 17 | ```groovy 18 | allprojects { 19 | repositories { 20 | // ... 21 | maven { url 'https://www.jitpack.io' } 22 | } 23 | } 24 | ``` 25 | 26 | 添加依赖: 27 | 28 | ```groovy 29 | dependencies { 30 | implementation 'com.github.DylanCaiCoding.Longan:longan:1.1.1' 31 | // Optional 32 | implementation 'com.github.DylanCaiCoding.Longan:longan-design:1.1.1' 33 | } 34 | ``` 35 | 36 | ## 更新日志 37 | 38 | [Releases](https://github.com/DylanCaiCoding/Longan/releases) 39 | 40 | ## 作者其它的库 41 | 42 | | 库 | 简介 | 43 | | ------------------------------------------------------------ | ---------------------------------------------- | 44 | | [LoadingStateView](https://github.com/DylanCaiCoding/LoadingStateView) | 深度解耦标题栏或加载中、加载失败、无数据等视图 | 45 | | [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | 最全面的 ViewBinding 工具 | 46 | | [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) | 用属性委托的方式使用 MMKV | 47 | | [Tracker](https://github.com/DylanCaiCoding/Tracker) | 基于西瓜视频的责任链埋点思路实现的轻量级埋点框架 | 48 | 49 | ## License 50 | 51 | ``` 52 | Copyright (C) 2021. Dylan Cai 53 | 54 | Licensed under the Apache License, Version 2.0 (the "License"); 55 | you may not use this file except in compliance with the License. 56 | You may obtain a copy of the License at 57 | 58 | http://www.apache.org/licenses/LICENSE-2.0 59 | 60 | Unless required by applicable law or agreed to in writing, software 61 | distributed under the License is distributed on an "AS IS" BASIS, 62 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 63 | See the License for the specific language governing permissions and 64 | limitations under the License. 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * [介绍](/) 2 | 3 | * 所有 APIs 4 | * [Common APIS](/apis/commonapis) 5 | * [Design APIS](/apis/designapis) 6 | 7 | * 部分用法 8 | * [Activity](/usage/activity) 9 | * [ActivityResult](/usage/activityresult) 10 | * [CustomView](/usage/customview) 11 | * [DateTime](/usage/datetime) 12 | * [Dialogs](/usage/dialogs) 13 | * [Fragment](/usage/fragment) 14 | * [Intents](/usage/intents) 15 | * [Json](/usage/json) 16 | * [Keyboard](/usage/keyboard) 17 | * [Logger](/usage/logger) 18 | * [MMKV](/usage/mmkv) 19 | * [Permissions](/usage/permissions) 20 | * [SpannableString](/usage/spannablestring) 21 | * [SystemBars](/usage/systembars) 22 | * [Uri](/usage/uri) 23 | * [ViewModels](/usage/viewmodels) 24 | 25 | * 其它 26 | * [Q&A](/others/q&a) -------------------------------------------------------------------------------- /docs/apis/designapis.md: -------------------------------------------------------------------------------- 1 | # Design APIs 2 | 3 | ## Gradle 4 | 5 | 添加依赖到 `build.gradle`: 6 | 7 | ```groovy 8 | dependencies { 9 | implementation 'com.github.DylanCaiCoding.Longan:longan-design:1.1.1' 10 | } 11 | ``` 12 | 13 | > 下面用法中含有方括号 `[]` 的参数是可选的。 14 | 15 | ## [Dialogs.kt](https://github.com/DylanCaiCoding/Longan/blob/master/longan-design/src/main/java/com/dylanc/longan/design/Dialogs.kt) 16 | 17 | | 用法 | 作用 | 18 | | ------------------------------------------------------------ | ------------------ | 19 | | `Context/Fragment.alert([factory], message, [title]) {...}` | 显示消息弹框 | 20 | | `Context/Fragment.selector([factory], items, [title]) {...}` | 显示选项弹框 | 21 | | `Context/Fragment.singleChoiceSelector([factory], items, checkIndex, [title]) {...}` | 显示单选弹框 | 22 | | `Context/Fragment.singleChoiceSelector([factory], items, checkItems, [title]) {...}` | 显示多选弹框 | 23 | | `Context/Fragment.alertDialog([factory]) {...}` | 显示弹框 | 24 | | `initAlertBuilderFactory(factory)` | 初始化默认弹框样式 | 25 | | `Dialog/DialogInterface.doOnCancel {...}` | 监听取消事件 | 26 | | `Dialog/DialogInterface.doOnDismiss{...}` | 监听消失事件 | 27 | | `Dialog/DialogInterface.doOnShow{...}` | 监听显示事件 | 28 | 29 | ## [RecyclerView.kt](https://github.com/DylanCaiCoding/Longan/blob/master/longan-design/src/main/java/com/dylanc/longan/design/RecyclerView.kt) 30 | 31 | | 用法 | 作用 | 32 | | ------------------------------------------------------- | -------------------- | 33 | | `RecyclerView.setEmptyView(owner, emptyView)` | 设置空布局 | 34 | | `RecyclerView.Adapter<*>.observeDataEmpty(owner) {...}` | 观察数据是否为空 | 35 | | `RecyclerView.smoothScrollToStartPosition(position)` | 顺滑地滚动到起始位置 | 36 | | `RecyclerView.smoothScrollToEndPosition(position)` | 顺滑地滚动到末端位置 | 37 | | `RecyclerView.addItemPadding(...)` | 列表每一项都加边距 | 38 | 39 | ## [Snackbar.kt](https://github.com/DylanCaiCoding/Longan/blob/master/longan-design/src/main/java/com/dylanc/longan/design/Snackbar.kt) 40 | 41 | | 用法 | 作用 | 42 | | ------------------------------------------------------------ | ------------------- | 43 | | `Activity/Fragment/View.snackbar(message, [actionText], [action])` | 显示 Snackbar | 44 | | `Activity/Fragment/View.longSnackbar(message, [actionText], [action])` | 长时间显示 Snackbar | 45 | | `Activity/Fragment/View.indefiniteSnackbar(message, [actionText], [action])` | 永久显示 Snackbar | 46 | 47 | ## [TabLayout.kt](https://github.com/DylanCaiCoding/Longan/blob/master/longan-design/src/main/java/com/dylanc/longan/design/TabLayout.kt) 48 | 49 | | 用法 | 作用 | 50 | | ------------------------------------------------------------ | ---------------- | 51 | | `TabLayout.setupWithViewPager(viewPager, [autoRefresh]) {...}` | 设置 ViewPager | 52 | | `TabLayout.setupWithViewPager2(viewPager, [autoRefresh], [enableScroll]) {...}` | 设置 ViewPager2 | 53 | | `TabLayout.Tab.setCustomView(layoutId) {...}` | 设置自定义布局 | 54 | | `TabLayout.addTab(text) {...}` | 添加标签 | 55 | | `TabLayout.doOnTabSelected {...}` | 监听标签被选中 | 56 | | `TabLayout.doOnTabUnselected {...}` | 监听标签取消选中 | 57 | | `TabLayout.doOnTabReselected {...}` | 监听标签重新选中 | 58 | | `TabLayout.addOnTabSelectedListener(onTabSelected, onTabUnselected, onTabReselected) ` | 监听标签选中事件 | 59 | 60 | ## [ViewPager2.kt](https://github.com/DylanCaiCoding/Longan/blob/master/longan-design/src/main/java/com/dylanc/longan/design/ViewPager2.kt) 61 | 62 | | 用法 | 作用 | 63 | | ------------------------------------------------------------ | ------------------------- | 64 | | `FragmentActivity/Fragment.FragmentStateAdapter(fragments, [isLazyLoading])` | 创建 FragmentStateAdapter | 65 | | `FragmentActivity/Fragment.FragmentStateAdapter(itemCount, [isLazyLoading]) {...}` | 创建 FragmentStateAdapter | 66 | | `ViewPager2.findFragment(fragmentManager, position)` | 获取 Fragment | -------------------------------------------------------------------------------- /docs/img/alignCenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/alignCenter.png -------------------------------------------------------------------------------- /docs/img/alignOpposite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/alignOpposite.png -------------------------------------------------------------------------------- /docs/img/backgroudColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/backgroudColor.png -------------------------------------------------------------------------------- /docs/img/blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/blur.png -------------------------------------------------------------------------------- /docs/img/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/bold.png -------------------------------------------------------------------------------- /docs/img/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/bullet.png -------------------------------------------------------------------------------- /docs/img/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/color.png -------------------------------------------------------------------------------- /docs/img/fontFamily.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/fontFamily.png -------------------------------------------------------------------------------- /docs/img/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/image.png -------------------------------------------------------------------------------- /docs/img/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/italic.png -------------------------------------------------------------------------------- /docs/img/leadingMargin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/leadingMargin.png -------------------------------------------------------------------------------- /docs/img/quote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/quote.png -------------------------------------------------------------------------------- /docs/img/scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/scale.png -------------------------------------------------------------------------------- /docs/img/size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/size.png -------------------------------------------------------------------------------- /docs/img/space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/space.png -------------------------------------------------------------------------------- /docs/img/strikeThrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/strikeThrough.png -------------------------------------------------------------------------------- /docs/img/subscript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/subscript.png -------------------------------------------------------------------------------- /docs/img/superscript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/superscript.png -------------------------------------------------------------------------------- /docs/img/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/underline.png -------------------------------------------------------------------------------- /docs/img/url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanCaiCoding/Longan/817e5061fbec303d84f51a79e18d59e89843434e/docs/img/url.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/others/q&a.md: -------------------------------------------------------------------------------- 1 | # Q&A 2 | 3 | ## 为什么叫 `Longan`? 4 | 5 | 个人想用个水果名来作为库名,最初想到的是 `Guava` (石榴),感觉非常有代表性。但是发现有一个谷歌的同名库,所以换了另一个也是多子的水果 `Longan` (龙眼)。 -------------------------------------------------------------------------------- /docs/usage/activity.md: -------------------------------------------------------------------------------- 1 | # Activity 用法 2 | 3 | ## 跳转 Activity 4 | 5 | 简单地跳转: 6 | 7 | ```kotlin 8 | startActivity() 9 | ``` 10 | 11 | 带参数跳转: 12 | 13 | ```kotlin 14 | startActivity("id" to 5) 15 | ``` 16 | 17 | 带参数跳转推荐用下面的写法: 18 | 19 | ```kotlin 20 | class SomeActivity : AppCompatActivity() { 21 | private val id: String by safeIntentExtras(KEY_ID) 22 | 23 | //... 24 | 25 | companion object { 26 | fun start(id: String) = startActivity(KEY_ID to id) 27 | } 28 | } 29 | ``` 30 | 31 | ```kotlin 32 | SomeActivity.start(id) 33 | ``` 34 | 35 | 编写一个静态的 `start()` 方法传入所需的参数并跳转,在跳转的页面通过委托的方式获取值,可查看 [Intent](/intents) 的用法。调用静态方法跳转可以避免传漏或传错参数。 36 | 37 | ## 结束 Activity 时回调结果 38 | 39 | 在 `startActivityForResult()` 跳转的页面通常需要在结束的时候带上回调的结果,一般需要几行代码来实现。比如: 40 | 41 | ```kotlin 42 | val intent = Intent() 43 | intent.putExtra("id", 5) 44 | intent.putExtra("name", name) 45 | setResult(RESULT_OK, intent) 46 | finish() 47 | ``` 48 | 49 | 几行代码有点繁琐,所以提供了一种更简单的方式能用一行代码实现: 50 | 51 | ```kotlin 52 | finishWithResult("id" to 5, "name" to name) 53 | ``` 54 | 55 | ## Activity 堆栈管理 56 | 57 | 可使用 `topActivity` 获取栈顶的 Activity,使用 `activityList` 获取 Activity 堆栈的列表。 58 | 59 | 判断 Activity 是否在堆栈中: 60 | 61 | ```kotlin 62 | if (isActivityExistsInStack()) { 63 | // ... 64 | } 65 | ``` 66 | 67 | 结束某个 Activity: 68 | 69 | ```kotlin 70 | finishActivity() 71 | ``` 72 | 73 | 结束所有 Activity: 74 | 75 | ```kotlin 76 | finishAllActivities() 77 | ``` 78 | 79 | 结束除了最新以外的所有 Activity: 80 | 81 | ```kotlin 82 | finishAllActivitiesExceptNewest() 83 | ``` 84 | 85 | ## 双击返回键退出 86 | 87 | 快速实现双击返回键退出: 88 | 89 | ```kotlin 90 | pressBackTwiceToExitApp("再次点击退出应用") 91 | ``` 92 | 93 | 默认 2 秒内第二次点击返回键才退出,可以传多一个参数修改间隔时间: 94 | 95 | ```kotlin 96 | pressBackTwiceToExitApp("再次点击退出应用", delayMillis = 1500) 97 | ``` 98 | 99 | 如果需要自定义吐司或者换成 `Snackbar`: 100 | 101 | ```kotlin 102 | pressBackTwiceToExitApp { 103 | snackbar("再次点击退出应用") 104 | } 105 | ``` 106 | 107 | ## 点击返回键不退出 108 | 109 | 有时需要点击返回不退出应用,直接返回桌面: 110 | 111 | ```kotlin 112 | pressBackToNotExitApp() 113 | ``` 114 | 115 | ## 强转 Activity 116 | 117 | 有些时候作用域内的 this 不是 Activity,这时我们用到 Activity 就要指明用哪个 this,比如 `this@SignInActivity`。所以增加了拓展属性 `context`, `activity`, `fragmentActivity`, `lifecycleOwner`,将 Activity 强转成对应的类型进行使用,可以简化代码,提高代码的可读性。 -------------------------------------------------------------------------------- /docs/usage/customview.md: -------------------------------------------------------------------------------- 1 | # 自定义 View 用法 2 | 3 | ## 获取自定义属性 4 | 5 | 获取自定义属性需要不少代码来实现。 6 | 7 | ```kotlin 8 | val attr = context.obtainStyledAttributes(attrs, R.styleable.CustomView, 0, 0) 9 | textSize = attr.getDimension(R.styleable.CustomView_textSize, 12.sp) 10 | textColor = attr.getColor(R.styleable.CustomView_textColor, ContextCompat.getColor(context, R.color.text_normal)) 11 | icon = attr.getDrawable(R.styleable.CustomView_icon) ?: ContextCompat.getDrawable(context, R.drawable.default_icon) 12 | iconSize = attr.getDimension(R.styleable.CustomView_iconSize, 30.dp) 13 | attr.recycle() 14 | ``` 15 | 16 | 所以提供了更简洁的方式来获取自定义属性: 17 | 18 | ```kotlin 19 | withStyledAttrs(attrs, R.styleable.CustomView) { 20 | textSize = getDimension(R.styleable.CustomView_textSize, 12.sp) 21 | textColor = getColor(R.styleable.CustomView_textColor, getCompatColor(R.color.text_normal)) 22 | icon = getDrawable(R.styleable.CustomView_icon) ?: getCompatDrawable(R.drawable.default_icon) 23 | iconSize = getDimension(R.styleable.CustomView_iconSize, 30.dp) 24 | } 25 | ``` 26 | 27 | ## 绘制居中文字 28 | 29 | 绘制居中或者垂直居中的文字: 30 | 31 | ```kotlin 32 | canvas.drawCenterText(text, centerX, centerY, paint) 33 | canvas.drawCenterVerticalText(text, centerX, centerY, paint) 34 | ``` 35 | 36 | ## 触摸相关 37 | 38 | 获取当前触摸位置的子 View: 39 | 40 | ```kotlin 41 | val touchedView = findTouchedChild(ev.rawX, ev.rawY) 42 | ``` 43 | 44 | 判断某个 View 是不是在触摸位置上: 45 | ```kotlin 46 | if (view.isTouchedAt(ev.rawX, ev.rawY)) { 47 | // ... 48 | } 49 | ``` -------------------------------------------------------------------------------- /docs/usage/datetime.md: -------------------------------------------------------------------------------- 1 | # DateTime 用法 2 | 3 | 推荐用 Java8 的 `LocalDataTime`,后续会封装扩展方法简化用法。 4 | -------------------------------------------------------------------------------- /docs/usage/dialogs.md: -------------------------------------------------------------------------------- 1 | # Dialogs 用法 2 | 3 | 保留了 `Anko` 的用法并做了优化。 4 | 5 | ## Toasts 6 | 7 | 简单地显示 [Toast](https://developer.android.com/guide/topics/ui/notifiers/toasts.html) 消息,修复了 Android 7.x 的 `BadTokenException` 异常。 8 | 9 | ```kotlin 10 | toast("Hi there!") 11 | toast(R.string.message) 12 | longToast("Wow, such duration") 13 | ``` 14 | 15 | ## SnackBars 16 | 17 | 简单地显示 [SnackBar](https://developer.android.com/reference/android/support/design/widget/Snackbar.html) 消息。 18 | 19 | ```kotlin 20 | snackbar("Hi there!") 21 | snackbar(R.string.message) 22 | longSnackbar("Wow, such duration") 23 | indefiniteSnackbar("Wow, always show") 24 | snackbar("Action, reaction", "Click me!") { doStuff() } 25 | ``` 26 | 27 | ## Alerts 28 | 29 | 用 DSL 语法显示[对话框](https://developer.android.com/guide/topics/ui/dialogs.html). 30 | 31 | ```kotlin 32 | alert("Hi, I'm Roy", "Have you tried turning it off and on again?") { 33 | okButton { toast("Oh…") } 34 | cancelButton {} 35 | } 36 | ``` 37 | 38 | 上面的代码默认显示 `MaterialAlertDialog`,如果你想切换成默认使用 Appcompat 的`AlertDialog`,可以配置 `AlertFactory`: 39 | 40 | ```kotlin 41 | initAlertBuilderFactory(Appcompat) 42 | ``` 43 | 44 | 或者切换某一次对话框的样式: 45 | 46 | ```kotlin 47 | alert(Appcompat, "Some text message") 48 | ``` 49 | 50 | 默认提供 `Appcompat` 和 `Material` 可选,你可以实现 `AlertBuilderFactory` 接口进行自定义。后续会对更多的弹框样式进行支持。 51 | 52 | ## Selectors 53 | 54 | `selector()` 显示一个带有文本项列表的对话框: 55 | 56 | ```kotlin 57 | val countries = listOf("China", "Russia", "USA", "Australia") 58 | selector(countries, "Where are you from?") { dialog, i -> 59 | toast("So you're living in ${countries[i]}, right?") 60 | } 61 | ``` 62 | 63 | `singleChoiceSelector()` 显示一个单选列表的对话框: 64 | 65 | ```kotlin 66 | private var checkedCountry = "China" 67 | 68 | private fun selectCountry() { 69 | val countries = listOf("China", "Russia", "USA", "Australia") 70 | val checkedIndex = countries.indexOfFirst { it == checkedCountry } 71 | singleChoiceSelector(countries, checkedIndex, "Where are you from?") { dialog, i -> 72 | checkedCountry = countries[i] 73 | toast("You're living in ${checkedCountry}.") 74 | dialog.dismiss() 75 | } 76 | } 77 | ``` 78 | 79 | `multiChoiceSelector()` 显示一个多选列表的对话框: 80 | 81 | ```kotlin 82 | private val foods = listOf("Apple", "Banana", "Pear", "Peach") 83 | private val checkedItems = BooleanArray(foods.size) 84 | 85 | private fun selectFoods() { 86 | multiChoiceSelector(foods, checkedItems, "What do you want to eat?") { dialog, i, isChecked -> 87 | checkedItems[i] = isChecked 88 | }.doOnDismiss { 89 | toast("So you want to eat ${checkedItems.filter { it }.size} foods.") 90 | } 91 | } 92 | ``` 93 | 94 | 95 | -------------------------------------------------------------------------------- /docs/usage/fragment.md: -------------------------------------------------------------------------------- 1 | # Fragment 用法 2 | 3 | ## 创建带参数的 Fragment 4 | 5 | 传参给 Fragment 需要设置 Bundle 对象,通常 Bundle 对象每增加一个额外的参数,就需要增加一行代码。例如: 6 | 7 | ```kotlin 8 | val fragment = SomeFragment() 9 | val arguments = Bundle() 10 | arguments.putInt("id", 5) 11 | arguments.putString("title", title) 12 | fragment.arguments = arguments 13 | ``` 14 | 15 | 而 `Longan` 提供了更简单的方式实现上面的功能。 16 | 17 | ```kotlin 18 | val fragment = SomeFragment().withArguments("id" to 5, "title" to title) 19 | ``` 20 | 21 | ## Fragment 的 arguments 委托 22 | 23 | 使用 `arguments()` 委托获取传递给 Fragment 的数据。 24 | 25 | ```kotlin 26 | val name: String? by arguments(KEY_NAME) 27 | val count: Int by arguments(KEY_COUNT, default = 0) 28 | ``` 29 | 30 | 如果可以人为确保一定能获取到值,又不想传默认值,可以用 `safeArguments()` 进行委托。 31 | 32 | ```kotlin 33 | val phone: String by safeArguments(KEY_PHONE) 34 | ``` 35 | 36 | 创建带参数 Fragment 的推荐写法: 37 | 38 | ```kotlin 39 | class SomeFragment : Fragment() { 40 | private val id: String by safeArguments(KEY_ID) 41 | 42 | // ... 43 | 44 | companion object { 45 | fun newInstance(id: String) = SomeFragment().withArguments(KEY_ID to id) 46 | } 47 | } 48 | ``` 49 | 50 | ```kotlin 51 | val fragment = SomeFragment.newInstance(id) 52 | ``` 53 | 54 | 编写一个静态的 `newInstance()` 方法传入所需的参数并创建 Fragment,在 Fragment 内通过委托的方式获取值。调用静态方法可以防止传漏或传错参数。 55 | -------------------------------------------------------------------------------- /docs/usage/intents.md: -------------------------------------------------------------------------------- 1 | # Intents 用法 2 | 3 | 参考和保留了 `Anko` 部分功能。 4 | 5 | ## 创建 Intent 6 | 7 | 通常 Intent 每增加一个额外的参数或 flag,就需要增加一行代码。例如: 8 | 9 | ```kotlin 10 | val intent = Intent(this, SomeOtherActivity::class.java) 11 | intent.putExtra("id", 5) 12 | intent.setFlag(Intent.FLAG_ACTIVITY_SINGLE_TOP) 13 | startActivity(intent) 14 | ``` 15 | 16 | 而 `Longan` 提供了更简单的方式实现上面的功能。 17 | 18 | ```kotlin 19 | startActivity(intentOf("id" to 5).singleTop()) 20 | ``` 21 | 22 | ## 获取 Intent 的参数 23 | 24 | 使用 `intentExtras()` 委托获取 `Intent` 的数据。 25 | 26 | ```kotlin 27 | val name: String? by intentExtras(KEY_NAME) 28 | val count: Int by intentExtras(KEY_COUNT, default = 0) 29 | ``` 30 | 31 | 如果可以人为确保一定能获取到值,又不想传默认值,可以用 `safeIntentExtras()` 进行委托。 32 | 33 | ```kotlin 34 | val phone: String by safeIntentExtras(KEY_PHONE) 35 | ``` 36 | 37 | ## 常用的 Intent 操作 38 | 39 | 拨号(并未呼叫),无需权限: 40 | 41 | ```kotlin 42 | dial(number) 43 | ``` 44 | 45 | 拨打电话,需要 `CALL_PHONE` 权限: 46 | 47 | ```kotlin 48 | makeCall(number) 49 | ``` 50 | 51 | 发送短信: 52 | 53 | ```kotlin 54 | sendSMS(number, content) 55 | ``` 56 | 57 | 发送邮件: 58 | 59 | ```kotlin 60 | email(email, subject, text) 61 | ``` 62 | 63 | 安装 APK: 64 | 65 | ```kotlin 66 | installAPK(uri) 67 | ``` 68 | 69 | 以上方法如果发送了 `Intent`,则方法返回 true。 70 | 71 | ## 分享的 Intent 72 | 73 | 分享功能是用 `ShareCompat` 实现,无返回值。 74 | 75 | 分享文字: 76 | 77 | ```kotlin 78 | shareText(text) 79 | ``` 80 | 81 | 分享单张图片: 82 | 83 | ```kotlin 84 | shareImage(uri) 85 | ``` 86 | 87 | 分享多张图片: 88 | 89 | ```kotlin 90 | shareImages(uris) 91 | ``` 92 | 93 | 分享文字和单张图片: 94 | 95 | ```kotlin 96 | shareTextAndImage(text, uri) 97 | ``` 98 | 99 | 分享文字和多张图片: 100 | 101 | ```kotlin 102 | shareTextAndImages(text, uris) 103 | ``` 104 | 105 | 分享单个文件: 106 | 107 | ```kotlin 108 | shareFile(uri) 109 | ``` 110 | 111 | 112 | 分享多个文件: 113 | 114 | ```kotlin 115 | shareFiles(uris) 116 | ``` -------------------------------------------------------------------------------- /docs/usage/json.md: -------------------------------------------------------------------------------- 1 | # Json 用法 2 | 3 | 暂未对 Json 序列化进行封装,可以选择使用以下的库: 4 | 5 | - [kotlinx-serialization](https://github.com/Kotlin/kotlinx.serialization) 6 | - [moshi](https://github.com/square/moshi) 7 | 8 | 不推荐用 `Gson` 序列化。 -------------------------------------------------------------------------------- /docs/usage/keyboard.md: -------------------------------------------------------------------------------- 1 | # 键盘用法 2 | 3 | ## 显示或隐藏键盘 4 | 5 | 显示键盘: 6 | 7 | ```kotlin 8 | edtName.showKeyboard() 9 | ``` 10 | 11 | 隐藏键盘: 12 | 13 | ```kotlin 14 | edtName.hideKeyboard() 15 | ``` 16 | 17 | 切换键盘: 18 | 19 | ```kotlin 20 | edtName.toggleKeyboard() 21 | ``` 22 | 23 | 判断键盘是否显示: 24 | 25 | ```kotlin 26 | if (edtName.isKeyboardVisible) { 27 | // ... 28 | } 29 | ``` -------------------------------------------------------------------------------- /docs/usage/logger.md: -------------------------------------------------------------------------------- 1 | # 日志用法 2 | 3 | 参考了 `AnkoLogger` 并进行了优化和改进。 4 | 5 | ## 打印日志 6 | 7 | 相对于 [android.util.Log](https://developer.android.com/reference/android/util/Log.html) 会更加易用,不需要传 tag,默认 tag 是当前的类名。例如: 8 | 9 | ```kotlin 10 | class MainActivity : AppCompatActivity() { 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | logInfo("test") 15 | logDebug(5) // 执行 `.toString()` 后再打印 16 | logWarn(null) // 将会打印 "null" 17 | } 18 | } 19 | ``` 20 | 21 | | android.util.Log | Logger | 22 | | ---------------- | -------------- | 23 | | `v()` | `logVerbose()` | 24 | | `d()` | `logDebug()` | 25 | | `i()` | `logInfo()` | 26 | | `w()` | `logWarn()` | 27 | | `e()` | `logError()` | 28 | | `wtf()` | `logWtf()` | 29 | 30 | ## 修改 Tag 31 | 32 | 实现 `Logger` 接口,重写 `loggerTag` 属性,就能修改在该类下打印日志的 tag。 33 | 34 | ```kotlin 35 | class MainActivity : AppCompatActivity(), Logger { 36 | 37 | override val loggerTag: String get() = "new tag" 38 | 39 | override fun onCreate(savedInstanceState: Bundle?) { 40 | super.onCreate(savedInstanceState) 41 | logInfo("test") 42 | logDebug(5) 43 | logWarn(null) 44 | } 45 | } 46 | ``` 47 | 48 | 或者创建 `Logger` 对象去调用对应的打印方法。 49 | 50 | ```kotlin 51 | class MainActivity : AppCompatActivity() { 52 | 53 | private val logger = Logger() // 用其它类的类名作为 tag 54 | private val loggerWithSpecificTag = Logger("my_tag") 55 | 56 | override fun onCreate(savedInstanceState: Bundle?) { 57 | super.onCreate(savedInstanceState) 58 | logger.logInfo("test") 59 | loggerWithSpecificTag.logDebug(5) 60 | } 61 | } 62 | ``` 63 | 64 | ## 过滤日志 65 | 66 | 可以在初始化时配置是否打印日志。 67 | 68 | ```kotlin 69 | initLogger(BuildConfig.DEBUG) 70 | ``` 71 | 72 | 更复杂的过滤规则可以设置 `Logger.isLoggable`。 73 | 74 | ```kotlin 75 | Logger.isLoggable = { level, tag -> 76 | // 可根据打印等级和标签判断是否需要打印 77 | } 78 | ``` 79 | 80 | ## 自定义打印格式 81 | 82 | 创建一个类实现 `LoggerPrinter` 接口,实现打印方法。 83 | 84 | ```kotlin 85 | class CustomLoggerPrinter : LoggerPrinter { 86 | override fun log(level: LogLevel, tag: String, message: String, thr: Throwable?) { 87 | when (level) { 88 | LogLevel.VERBOSE -> //... 89 | LogLevel.DEBUG -> //... 90 | LogLevel.INFO -> //... 91 | LogLevel.WARN -> //... 92 | LogLevel.ERROR -> //... 93 | } 94 | } 95 | 96 | override fun logWtf(tag: String, message: String, thr: Throwable?) { 97 | //... 98 | } 99 | } 100 | ``` 101 | 102 | 初始化时设置 printer。 103 | 104 | ```kotlin 105 | initLogger(printer = CustomLoggerPrinter()) 106 | ``` 107 | 108 | 后续会对默认的打印格式进行升级。 -------------------------------------------------------------------------------- /docs/usage/mmkv.md: -------------------------------------------------------------------------------- 1 | # MMKV 用法 2 | 3 | 由于官方已经不推荐用 `SharedPreferences`,所以把之前封装的 `SharedPreferences` 工具类改成用 `MMKV` 实现。 4 | 5 | 考虑到有些人可能会用官方的 `DataStore`,就另写了一个库 [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) 作为可选项。 6 | 7 | ## Gradle 8 | 9 | 在根目录的 `build.gradle` 添加: 10 | 11 | ```groovy 12 | allprojects { 13 | repositories { 14 | //... 15 | maven { url 'https://www.jitpack.io' } 16 | } 17 | } 18 | ``` 19 | 20 | 在模块的 `build.gradle` 添加依赖: 21 | 22 | ```groovy 23 | dependencies { 24 | implementation 'com.github.DylanCaiCoding:MMKV-KTX:1.2.15' 25 | } 26 | ``` 27 | 28 | ## 基础用法 29 | 30 | 让一个类实现 `MMKVOwner` 接口,即可通过 `by mmkvXXXX()` 方法将属性委托给 `MMKV`,例如: 31 | 32 | ```kotlin 33 | object DataRepository : MMKVOwner { 34 | var isFirstLaunch by mmkvBool(default = true) 35 | var user by mmkvParcelable() 36 | } 37 | ``` 38 | 39 | 设置或获取属性的值会调用对应的 encode() 或 decode() 函数,**用属性名作为 key 值**。 40 | 41 | 支持以下类型: 42 | 43 | | 方法 | 默认值 | 44 | | ------------------ | ------ | 45 | | `mmkvInt()` | 0 | 46 | | `mmkvLong()` | 0L | 47 | | `mmkvBool()` | false | 48 | | `mmkvFloat()` | 0f | 49 | | `mmkvDouble()` | 0.0 | 50 | | `mmkvString()` | / | 51 | | `mmkvStringSet()` | / | 52 | | `mmkvBytes()` | / | 53 | | `mmkvParcelable()` | / | 54 | 55 | 1.2.15 版本新增 `mmkvXXXX().asLiveData()` 函数将属性委托给 `LiveData`,例如: 56 | 57 | ```kotlin 58 | object SettingRepository : MMKVOwner { 59 | val nightMode by mmkvBool().asLiveData() 60 | } 61 | 62 | SettingRepository.nightMode.observe(this) { 63 | checkBox.isChecked = it 64 | } 65 | 66 | SettingRepository.nightMode.value = true 67 | ``` 68 | 69 | 在 `MMKVOwner` 的实现类可以获取 `kv` 对象进行删除值或清理缓存等操作: 70 | 71 | ```kotlin 72 | kv.removeValueForKey(::isFirstLaunch.name) 73 | kv.clearAll() 74 | ``` 75 | 76 | ## 进阶用法 77 | 78 | ### 取消自动初始化 79 | 80 | 本库会自动调用 `MMKV.initialize(context)` 进行初始化,如果在用了 MMKV 的项目中使用本库,建议把自动初始化给取消了,多次初始化可能会导致数据异常。 81 | 82 | 需要添加 App Startup 的依赖: 83 | 84 | ```groovy 85 | implementation "androidx.startup:startup-runtime:1.1.0" 86 | ``` 87 | 88 | 然后在 `AndroidManifest.xml` 添加以下代码就能取消自动初始化操作: 89 | 90 | ```xml 91 | 92 | 97 | 100 | 101 | 102 | ``` 103 | 104 | ### 重写 kv 对象 105 | 106 | 有一些场景需要使用新的 MMKV 对象,此时可以重写 `kv` 属性。 107 | 108 | #### 区别存储 109 | 110 | 比如我们在组件化项目进行开发,各自负责的模块是不知道别人用了什么 key 值,重名了可能被覆盖。这就可以重写 `kv` 属性创建不同的 `MMKV` 实例来规避这个问题。 111 | 112 | ```kotlin 113 | object UserRepository : MMKVOwner { 114 | // ... 115 | 116 | override val kv: MMKV = MMKV.mmkvWithID("user") 117 | } 118 | ``` 119 | 120 | #### 多进程 121 | 122 | MMKV 默认是单进程模式,如果你需要多进程支持: 123 | 124 | ```kotlin 125 | object DataRepository : MMKVOwner { 126 | // ... 127 | 128 | override val kv: MMKV = MMKV.mmkvWithID("InterProcessKV", MMKV.MULTI_PROCESS_MODE) 129 | } 130 | ``` 131 | 132 | #### 加密 133 | 134 | MMKV 默认明文存储所有 key-value,依赖 Android 系统的沙盒机制保证文件加密。如果你担心信息泄露,你可以选择加密 MMKV。 135 | 136 | ```kotlin 137 | object DataRepository : MMKVOwner { 138 | // ... 139 | 140 | private const val cryptKey = "My-Encrypt-Key" 141 | 142 | override val kv: MMKV = MMKV.mmkvWithID("MyID", MMKV.SINGLE_PROCESS_MODE, cryptKey) 143 | } 144 | ``` 145 | 146 | ## 更新日志 147 | 148 | [Releases](https://github.com/DylanCaiCoding/MMKV-KTX/releases) -------------------------------------------------------------------------------- /docs/usage/permissions.md: -------------------------------------------------------------------------------- 1 | # 权限用法 2 | 3 | 基于 [Activity Result API](https://developer.android.com/training/basics/intents/result?hl=zh-cn) 进行封装。 4 | 5 | ## 请求单个权限 6 | 7 | ```kotlin 8 | private val requestPermissionLauncher = registerForRequestPermissionResult( 9 | onGranted = { 10 | // 已同意 11 | }, 12 | onDenied = { 13 | // 拒绝且不再询问,可弹框引导用户到设置里授权该权限 14 | // 弹框提示后可调用 launchAppSettings() 方法跳到设置页 15 | }, 16 | onShowRequestRationale = { 17 | // 拒绝了一次,可弹框解释为什么要获取该权限 18 | // 弹框提示后可调用 requestPermissionAgain() 方法重新请求 19 | }) 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | // ... 23 | requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) 24 | } 25 | ``` 26 | 27 | ## 请求多个权限 28 | 29 | ```kotlin 30 | private val requestMultiplePermissionsLauncher = requestMultiplePermissionsLauncher( 31 | onAllGranted = { 32 | // 已全部同意 33 | }, 34 | onDenied = { deniedList -> 35 | // 部分权限已拒绝且不再询问,可弹框引导用户到设置里授权该权限 36 | // 弹框提示后可调用 launchAppSettings() 方法跳到设置页 37 | }, 38 | onShowRequestRationale = { deniedList -> 39 | // 部分权限拒绝了一次,可弹框解释为什么要获取该权限 40 | // 弹框提示后可调用 requestDeniedPermissions() 方法请求拒绝的权限 41 | }) 42 | 43 | override fun onCreate(savedInstanceState: Bundle?) { 44 | // ... 45 | requestMultiplePermissionsLauncher.launch( 46 | Manifest.permission.ACCESS_FINE_LOCATION, 47 | Manifest.permission.READ_EXTERNAL_STORAGE, 48 | ) 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/usage/systembars.md: -------------------------------------------------------------------------------- 1 | # SystemBars 用法 2 | 3 | 使用最新的 `WindowInsets` 实现,兼容了 Android 10。 4 | 5 | ## SystemBars 6 | 7 | 应用全屏: 8 | 9 | ```kotlin 10 | isFullScreen = true 11 | ``` 12 | 13 | ## StatusBar 14 | 15 | 实现沉浸式状态栏,并且给标题栏的顶边距增加状态栏高度,可以适配刘海水滴屏: 16 | 17 | ```kotlin 18 | immerseStatusBar(lightMode = false) 19 | toolbar.addStatusBarHeightToMarginTop() 20 | // toolbar.addStatusBarHeightToPaddingTop() 21 | ``` 22 | 23 | 透明状态栏: 24 | 25 | ```kotlin 26 | transparentStatusBar() 27 | ``` 28 | 29 | 其它状态栏属性: 30 | 31 | - `statusBarColor`,设置或获取状态栏颜色 32 | - `isLightStatusBar`,设置或判断状态栏是否为浅色模式 33 | - `isStatusBarVisible`,设置或判断状态栏是否为显示 34 | - `statusBarHeight`,获取状态栏高度 35 | 36 | ## NavigationBar 37 | 38 | 给控件的底边距增加导航栏高度: 39 | 40 | ```kotlin 41 | view.addNavigationBarHeightToMarginBottom() 42 | // view.addNavigationBarHeightToPaddingBottom() 43 | ``` 44 | 45 | 其它状态栏属性: 46 | 47 | - `navigationBarColor`,设置或获取导航栏颜色 48 | - `isLightNavigationBar`,设置或判断导航栏是否为浅色模式 49 | - `isNavigationBarVisible`,设置或判断导航栏是否为显示 50 | - `navigationBarHeight`,获取导航栏高度 -------------------------------------------------------------------------------- /docs/usage/uri.md: -------------------------------------------------------------------------------- 1 | # Uri 用法 2 | 3 | ## 查询多媒体文件 4 | 5 | 查询多媒体视频的示例: 6 | 7 | ```kotlin 8 | // Container for information about each video. 9 | data class Video( 10 | val uri: Uri, 11 | val name: String, 12 | val duration: Int, 13 | val size: Int 14 | ) 15 | 16 | val videoList = mutableListOf