├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── README.md ├── build.gradle ├── demo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kt │ │ └── ktmvvm │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── kt │ │ │ └── ktmvvm │ │ │ ├── BindingAdapter.kt │ │ │ ├── Constants.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MainViewModel.kt │ │ │ ├── MyApp.kt │ │ │ ├── decoration │ │ │ └── StaggeredDividerItemDecoration.kt │ │ │ ├── download │ │ │ ├── DownloadActivity.kt │ │ │ ├── DownloadViewModel.kt │ │ │ └── manager │ │ │ │ ├── DownloadInfo.kt │ │ │ │ ├── DownloadManager.kt │ │ │ │ ├── DownloaderCallBack.kt │ │ │ │ └── ResponseProgressBody.kt │ │ │ ├── entity │ │ │ └── AlbumData.kt │ │ │ ├── inner │ │ │ ├── CameraExtensionModeType.kt │ │ │ └── CameraRatioType.kt │ │ │ ├── jetpack │ │ │ ├── adapter │ │ │ │ ├── RcvAdapter.kt │ │ │ │ ├── ViewPagerAdapter.kt │ │ │ │ └── ViewPagerVerticalAdapter.kt │ │ │ ├── camerax │ │ │ │ ├── CameraActivity.kt │ │ │ │ ├── CameraCallBack.kt │ │ │ │ ├── CameraParams.kt │ │ │ │ ├── CameraViewModel.kt │ │ │ │ └── controller │ │ │ │ │ ├── CameraXController.kt │ │ │ │ │ └── ICameraController.kt │ │ │ ├── coordinatorlayout │ │ │ │ ├── CoordinatorActivity.kt │ │ │ │ └── CoordinatorViewModel.kt │ │ │ ├── room │ │ │ │ ├── RoomActivity.kt │ │ │ │ ├── RoomViewModel.kt │ │ │ │ └── db │ │ │ │ │ ├── User.kt │ │ │ │ │ ├── UserDao.kt │ │ │ │ │ └── UserDataBase.kt │ │ │ ├── shapeableimageview │ │ │ │ ├── ShapeImageActivity.kt │ │ │ │ └── ShapeImageViewMode.kt │ │ │ └── viewpager │ │ │ │ ├── ScaleInTransformer.kt │ │ │ │ ├── ViewPager2Activity.kt │ │ │ │ └── ViewPager2ViewModel.kt │ │ │ ├── loader │ │ │ ├── AlbumDataLoader.kt │ │ │ └── MimeType.java │ │ │ ├── net │ │ │ └── DataService.kt │ │ │ ├── ui │ │ │ ├── KeyBordActivity.kt │ │ │ ├── KeyBordAdapter.kt │ │ │ ├── KeyBordViewModel.kt │ │ │ ├── MosaicActivity.kt │ │ │ └── MosaicViewModel.kt │ │ │ ├── utils │ │ │ ├── BannerUtils.kt │ │ │ ├── DisplayUtils.kt │ │ │ ├── KeyDataUtils.kt │ │ │ ├── PrefsUtil.kt │ │ │ └── StringUtils.kt │ │ │ └── widget │ │ │ ├── AutoTranslateView.kt │ │ │ ├── CameraPreView.kt │ │ │ ├── CameraTabView.java │ │ │ ├── FocusView.kt │ │ │ ├── GridView.kt │ │ │ ├── MyBottomSheetBehavior.java │ │ │ ├── PopWin.kt │ │ │ ├── RatioPop.kt │ │ │ ├── RecordButton.kt │ │ │ ├── RecordCountDownView.java │ │ │ ├── RingView.kt │ │ │ ├── TakePhotoView.kt │ │ │ ├── TimerHelper.kt │ │ │ ├── TopView.kt │ │ │ ├── TranslateView.kt │ │ │ ├── VerticalSeekBar.java │ │ │ ├── VerticalSeekBarWrapper.java │ │ │ └── mosic │ │ │ ├── DrawMosaicView.kt │ │ │ ├── MosaicPath.kt │ │ │ └── MosaicUtil.kt │ └── res │ │ ├── anim │ │ └── anim_fade_in.xml │ │ ├── color │ │ ├── color_selector.xml │ │ └── po_color_selector.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xxhdpi │ │ ├── bishua2.png │ │ ├── bishua3.png │ │ ├── bishua4.jpg │ │ ├── gird_off.png │ │ ├── gird_on.png │ │ ├── hdr_off.png │ │ ├── hdr_on.png │ │ ├── icon_bg_space.png │ │ ├── icon_bl.png │ │ ├── icon_camera_close_normal.png │ │ ├── icon_camera_close_pressed.png │ │ ├── icon_case.png │ │ ├── icon_delete.png │ │ ├── icon_reset_camera.png │ │ ├── icon_small_space.png │ │ ├── icon_switch_camera_normal.png │ │ ├── icon_switch_camera_pressed.png │ │ ├── icon_take_picture_down.png │ │ ├── icon_take_picture_normal.png │ │ ├── icon_take_picture_sticker_normal.png │ │ ├── icon_take_picture_sticker_pressed.png │ │ ├── icon_top_setting.png │ │ ├── light_check.png │ │ ├── light_normal.png │ │ ├── maoshua.jpg │ │ ├── splash_close.png │ │ ├── splash_open.png │ │ ├── timer_off.png │ │ └── timer_on.png │ │ ├── drawable │ │ ├── bg_black_shape.xml │ │ ├── close_camera_selector.xml │ │ ├── gray.xml │ │ ├── grid_selector.xml │ │ ├── hdr_selector.xml │ │ ├── ic_launcher_background.xml │ │ ├── light_selector.xml │ │ ├── progress.xml │ │ ├── selector_9_16.xml │ │ ├── selector_keyboard.xml │ │ ├── selector_text_color.xml │ │ ├── shape_9_16.xml │ │ ├── shape_9_16_fd87aa.xml │ │ ├── shape_select_bg.xml │ │ ├── shape_un_select_bg.xml │ │ ├── splash_selector.xml │ │ ├── switch_camera_selector.xml │ │ ├── switch_selector.xml │ │ ├── switch_thumb.xml │ │ ├── timer_selector.xml │ │ ├── white_c_15_shape.xml │ │ └── yellow_switch.xml │ │ ├── layout │ │ ├── activity_camera_layout.xml │ │ ├── activity_coordinator_layout.xml │ │ ├── activity_download_layout.xml │ │ ├── activity_main_new.xml │ │ ├── activity_mosaic_layout.xml │ │ ├── activity_shape_layout.xml │ │ ├── bottom_sheet_layout.xml │ │ ├── camera_preview.xml │ │ ├── keybord_item_layout.xml │ │ ├── keybord_layout.xml │ │ ├── popu_layout.xml │ │ ├── ratio_popu_layout.xml │ │ ├── rcv_item_layout.xml │ │ ├── room_activity.xml │ │ ├── take_photo_view.xml │ │ ├── top_factor_layout.xml │ │ ├── tranlate_view_layout.xml │ │ ├── viewpager2_layout.xml │ │ ├── viewpager_item_layout.xml │ │ └── viewpager_vertical_item_layout.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── kt │ └── ktmvvm │ └── ExampleUnitTest.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── ktmvvm ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kt │ │ └── ktmvvm │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── kt │ │ └── ktmvvm │ │ ├── basic │ │ ├── BaseActivity.kt │ │ ├── BaseFragment.kt │ │ ├── BaseViewModel.kt │ │ ├── IBaseView.kt │ │ ├── IBaseViewModel.kt │ │ └── SingleLiveEvent.kt │ │ └── net │ │ ├── ApiAddress.kt │ │ ├── ApiException.kt │ │ ├── ApiService.kt │ │ ├── BaseResponse.kt │ │ ├── BaseUrlConstants.kt │ │ ├── ExceptionUtil.kt │ │ ├── RetrofitClient.kt │ │ ├── TrustAllCerts.kt │ │ ├── dns │ │ └── OkHttpDNS.kt │ │ ├── event │ │ ├── OkHttpEvent.kt │ │ └── OkHttpEventListener.kt │ │ └── interceptor │ │ ├── HTTPDNSInterceptor.kt │ │ └── NoNetworkInterceptor.kt │ └── test │ └── java │ └── com │ └── kt │ └── ktmvvm │ └── ExampleUnitTest.kt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/vcs.xml 7 | /.idea/libraries 8 | .DS_Store 9 | /build 10 | /captures 11 | *.apk -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | 53 | 54 | 55 | 56 | 57 | 59 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KTMVVM 2 | 3 | Android MVVM 设计模式、kotlin+mvvm+retrofit+room+jetpack 4 | 5 | ### 整体结构 6 | 架构整体设计模式:MVVM(databindin\viewmodel\lifecycle\livedata) 7 | 网络框架:okhttp3\retrofit\kotlin 协程 8 | 存储框架:room\kotlin协程\flow 9 | Demo演示:ViewPager2\Room\Coordinatorlayout折叠栏\CameraX\马赛克\Shapeableimageview 10 | 11 | ### 对应页面 12 | 13 | | 功能 | 对应Activity| 14 | | ---- | ---- | 15 | | ViewPager2 | ViewPager2Activity | 16 | | Room数据库 | RoomActivity | 17 | | Coordinatorlayout折叠栏 | CoordinatorActivity | 18 | | CameraX | CameraActivity | 19 | | 马赛克 | MosaicActivity | 20 | | Shapeableimageview | ShapeImageActivity | 21 | 22 | 23 | ### 对应展示效果 24 | 25 | * **ViewPager2:** 26 | 27 | 28 | ![Screenshot_2022-08-16-14-15-35-03_af39b83e575829279cc287d559063a6c](https://user-images.githubusercontent.com/70507884/184810734-5d731d47-2ea0-4484-8e10-7c23df3dcc0d.jpg) 29 | 30 | 31 | * **Room数据库:** 32 | 33 | ![Screenshot_2022-08-16-14-23-45-50_af39b83e575829279cc287d559063a6c](https://user-images.githubusercontent.com/70507884/184811742-0e7c8b91-8623-47ad-86d9-cb0db74ab77a.jpg) 34 | 35 | 36 | 37 | * **CameraX仿一甜相机:** 38 | 39 | ![Screenshot_2022-08-16-11-55-41-03_af39b83e575829279cc287d559063a6c](https://user-images.githubusercontent.com/70507884/184812545-f47fa076-cfa1-4f14-88c8-e96b4bf36c49.jpg) 40 | ![Screenshot_2022-08-16-11-55-36-74_af39b83e575829279cc287d559063a6c](https://user-images.githubusercontent.com/70507884/184812567-cc2578be-0008-4631-8c7b-55472ab8f050.jpg) 41 | 42 | 43 | * **马赛克:** 44 | 45 | ![ezgif-4-5ae55beba8](https://user-images.githubusercontent.com/70507884/184813184-668f2d1a-b5c0-481e-804d-0a18ce453322.gif) 46 | 47 | * **多进程下载器:** 48 | 49 | ![ezgif-4-a5185f0bc8](https://user-images.githubusercontent.com/70507884/184813790-557aa24d-eb13-4226-89c9-bfe903da6991.gif) 50 | 51 | * **Shapeableimageview:** 52 | 53 | ![Screenshot_2022-08-16-14-39-46-51_af39b83e575829279cc287d559063a6c](https://user-images.githubusercontent.com/70507884/184814050-d74ac31f-b262-4184-8afb-9a1002cfc94a.jpg) 54 | 55 | 56 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | 4 | ext.kotlin_version ='1.7.0' 5 | dependencies { 6 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21" 7 | 8 | } 9 | } 10 | 11 | plugins { 12 | id 'com.android.application' version '7.1.3' apply false 13 | id 'com.android.library' version '7.1.3' apply false 14 | id 'org.jetbrains.kotlin.android' version '1.6.21' apply false 15 | // id 'org.jetbrains.kotlin:kotlin-gradle-plugin' version '1.7.0' apply false 16 | } 17 | 18 | task clean(type: Delete) { 19 | delete rootProject.buildDir 20 | } -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /demo/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | 3 | plugins { 4 | id 'com.android.application' 5 | id 'org.jetbrains.kotlin.android' 6 | } 7 | 8 | apply plugin: 'kotlin-android' 9 | apply plugin: 'kotlin-android-extensions' 10 | apply plugin: 'kotlin-kapt' 11 | 12 | kapt { 13 | generateStubs = true 14 | } 15 | android { 16 | compileSdk 32 17 | 18 | defaultConfig { 19 | applicationId "com.kt.ktmvvm" 20 | minSdk 21 21 | targetSdk 26 22 | versionCode 1 23 | versionName "1.0" 24 | 25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 26 | } 27 | 28 | buildTypes { 29 | release { 30 | minifyEnabled false 31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 32 | } 33 | } 34 | compileOptions { 35 | sourceCompatibility JavaVersion.VERSION_1_8 36 | targetCompatibility JavaVersion.VERSION_1_8 37 | } 38 | kotlinOptions { 39 | jvmTarget = '1.8' 40 | } 41 | 42 | buildFeatures{ 43 | dataBinding = true 44 | } 45 | } 46 | 47 | dependencies { 48 | 49 | implementation 'androidx.core:core-ktx:1.8.0' 50 | implementation 'androidx.appcompat:appcompat:1.4.2' 51 | implementation 'com.google.android.material:material:1.6.1' 52 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 53 | implementation project(path: ':ktmvvm') 54 | testImplementation 'junit:junit:4.13.2' 55 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 56 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 57 | kapt "androidx.room:room-compiler:2.4.2" // Kotlin 使用 kapt 58 | 59 | 60 | //camerax 61 | 62 | def camerax_version = "1.2.0-alpha04" 63 | implementation "androidx.camera:camera-core:${camerax_version}" 64 | implementation "androidx.camera:camera-camera2:${camerax_version}" 65 | implementation "androidx.camera:camera-lifecycle:${camerax_version}" 66 | implementation "androidx.camera:camera-video:${camerax_version}" 67 | implementation "androidx.camera:camera-view:${camerax_version}" 68 | implementation "androidx.camera:camera-extensions:${camerax_version}" 69 | implementation "androidx.concurrent:concurrent-futures-ktx:1.1.0" 70 | api 'com.blankj:utilcodex:1.31.0' //工具类 71 | 72 | } -------------------------------------------------------------------------------- /demo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /demo/src/androidTest/java/com/kt/ktmvvm/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.kt.ktmvvm", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 45 | 46 | 49 | 50 | 53 | 54 | 57 | 58 | 61 | 62 | 66 | 67 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm 2 | 3 | import android.os.Bundle 4 | import android.os.Handler 5 | import android.view.LayoutInflater 6 | import androidx.databinding.DataBindingUtil 7 | import com.kt.ktmvvm.basic.BaseActivity 8 | import com.kt.ktmvvm.databinding.ActivityMainNewBinding 9 | 10 | class MainActivity : BaseActivity() { 11 | 12 | 13 | override fun initParam() { 14 | } 15 | 16 | 17 | override fun initVariableId(): Int { 18 | return BR.model 19 | } 20 | 21 | 22 | override fun initContentView(savedInstanceState: Bundle?): Int { 23 | return R.layout.activity_main_new 24 | } 25 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm 2 | 3 | import android.app.Application 4 | import android.util.Log 5 | import com.kt.ktmvvm.basic.BaseViewModel 6 | import com.kt.ktmvvm.download.DownloadActivity 7 | import com.kt.ktmvvm.jetpack.camerax.CameraActivity 8 | import com.kt.ktmvvm.jetpack.coordinatorlayout.CoordinatorActivity 9 | import com.kt.ktmvvm.jetpack.room.RoomActivity 10 | import com.kt.ktmvvm.jetpack.shapeableimageview.ShapeImageActivity 11 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2Activity 12 | import com.kt.ktmvvm.net.ApiException 13 | import com.kt.ktmvvm.net.DataService 14 | import com.kt.ktmvvm.ui.KeyBordActivity 15 | import com.kt.ktmvvm.ui.MosaicActivity 16 | import java.util.* 17 | 18 | open class MainViewModel(application: Application) : BaseViewModel(application) { 19 | 20 | companion object { 21 | val TAG: String? = MainViewModel::class.simpleName 22 | } 23 | 24 | 25 | /** 26 | * 登录测试 27 | */ 28 | open fun getBookInfo() { 29 | 30 | 31 | launch({ 32 | val login = DataService.getBookInfo(3) 33 | 34 | }, onError = { 35 | 36 | Log.d(TAG, "the error is" + it.message) 37 | }) 38 | 39 | } 40 | 41 | 42 | /** 43 | * 历史上的今天 44 | */ 45 | open fun getHistoryDate() { 46 | 47 | launch({ 48 | val instance = Calendar.getInstance() 49 | 50 | val month = instance.get(Calendar.MONTH) + 1; 51 | 52 | val day = instance.get(Calendar.DATE); 53 | 54 | Log.d(TAG, "the date is$month/$day") 55 | val any = DataService.getHistoryDate(4, "$month/$day") 56 | 57 | any?.let { 58 | 59 | } ?: let { 60 | //数据为空 61 | } 62 | 63 | // if (login.getErrCode() == 200) { 64 | // var data = login.getData() 65 | // } else { 66 | // ApiException(-1, "返回结果出错") 67 | // } 68 | }, onError = { 69 | 70 | }) 71 | } 72 | 73 | /** 74 | * 任意地方调用 75 | */ 76 | open fun notViewModelLogin() { 77 | DataService.launch({ 78 | val login = DataService.login(1, "admin", "admin") 79 | 80 | if (login.getErrCode() == 200) { 81 | var data = login.getData() 82 | } else { 83 | ApiException(-1, "返回结果出错") 84 | } 85 | }, onError = { 86 | 87 | Log.d(TAG, "the error is" + it.message) 88 | }) 89 | } 90 | 91 | 92 | /** 93 | * 跳转viewpager2 94 | */ 95 | open fun goViewPager2() { 96 | startActivity(ViewPager2Activity::class.java) 97 | } 98 | 99 | 100 | /** 101 | * 进入room数据库 102 | */ 103 | open fun goRoom() { 104 | startActivity(RoomActivity::class.java) 105 | } 106 | 107 | /** 108 | * 进入coordinator 109 | */ 110 | open fun goCoordinator() { 111 | startActivity(CoordinatorActivity::class.java) 112 | } 113 | 114 | /** 115 | * 进入下载器 116 | */ 117 | open fun goDownloadManager() { 118 | startActivity(DownloadActivity::class.java) 119 | } 120 | 121 | /** 122 | * 马赛克 123 | */ 124 | open fun goMosaic() { 125 | startActivity(MosaicActivity::class.java) 126 | } 127 | 128 | 129 | /** 130 | * shape view 131 | */ 132 | open fun goShape() { 133 | startActivity(ShapeImageActivity::class.java) 134 | } 135 | 136 | /** 137 | * 进入相机 138 | */ 139 | 140 | open fun goCamera() { 141 | startActivity(CameraActivity::class.java) 142 | } 143 | 144 | /** 145 | * 进入自定义键盘 146 | */ 147 | open fun getKeyBord() { 148 | startActivity(KeyBordActivity::class.java) 149 | } 150 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/MyApp.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | import com.kt.ktmvvm.utils.PrefsUtil 6 | 7 | class MyApp : Application() { 8 | 9 | 10 | override fun onCreate() { 11 | super.onCreate() 12 | PrefsUtil.getInstance()?.init(this, "download_", Context.MODE_PRIVATE) 13 | instance = this 14 | } 15 | 16 | override fun attachBaseContext(base: Context?) { 17 | super.attachBaseContext(base) 18 | instance = this 19 | } 20 | 21 | 22 | companion object { 23 | private var instance: Application? = null 24 | fun get(): MyApp { 25 | return instance as MyApp 26 | } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/decoration/StaggeredDividerItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.decoration 2 | 3 | import android.content.Context 4 | import android.graphics.Rect 5 | import android.view.View 6 | import androidx.recyclerview.widget.RecyclerView 7 | import androidx.recyclerview.widget.RecyclerView.ItemDecoration 8 | import androidx.recyclerview.widget.StaggeredGridLayoutManager 9 | import com.kt.ktmvvm.utils.DisplayUtils 10 | 11 | class StaggeredDividerItemDecoration(internal: Int, context: Context) : ItemDecoration() { 12 | 13 | private var mInternal: Int = internal 14 | private var mHeight: Int? = 0 15 | private var mContext: Context? = context 16 | 17 | constructor(internal: Int, height: Int, context: Context) : this(internal, context) { 18 | mInternal = internal 19 | mHeight = height 20 | mContext = context 21 | } 22 | 23 | override fun getItemOffsets( 24 | outRect: Rect, 25 | view: View, 26 | parent: RecyclerView, 27 | state: RecyclerView.State 28 | ) { 29 | super.getItemOffsets(outRect, view, parent, state) 30 | 31 | if (parent.layoutManager is StaggeredGridLayoutManager) { 32 | val params = view.layoutParams as StaggeredGridLayoutManager.LayoutParams 33 | val spanIndex = params.spanIndex 34 | val viewLayoutPosition = params.viewLayoutPosition 35 | val column = spanIndex % 2 // view 所在的列 36 | // 中间间隔 37 | if (column == 1) { 38 | outRect.left = ((mInternal / 2f).toInt()) 39 | } else { 40 | outRect.right = ((mInternal / 2f).toInt()) 41 | } 42 | // 下方间隔 43 | outRect.bottom = 44 | if (mHeight == 0) DisplayUtils.dip2px(mContext, 9f) else mHeight!! 45 | 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/download/DownloadActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.download 2 | 3 | import android.os.Bundle 4 | import com.kt.ktmvvm.BR 5 | import com.kt.ktmvvm.R 6 | import com.kt.ktmvvm.basic.BaseActivity 7 | import com.kt.ktmvvm.databinding.ActivityDownloadLayoutBinding 8 | 9 | class DownloadActivity : BaseActivity() { 10 | override fun initVariableId(): Int { 11 | return BR.model 12 | } 13 | 14 | override fun initContentView(savedInstanceState: Bundle?): Int { 15 | return R.layout.activity_download_layout 16 | } 17 | 18 | override fun initParam() { 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/download/DownloadViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.download 2 | 3 | import android.app.Application 4 | import android.util.Log 5 | 6 | import androidx.databinding.ObservableField 7 | import com.kt.ktmvvm.Constants 8 | import com.kt.ktmvvm.basic.BaseViewModel 9 | import com.kt.ktmvvm.download.manager.DownloadInfo 10 | import com.kt.ktmvvm.download.manager.DownloadManager 11 | import com.kt.ktmvvm.download.manager.DownloaderCallBack 12 | 13 | import com.kt.ktmvvm.utils.BannerUtils 14 | import java.io.File 15 | 16 | class DownloadViewModel(application: Application) : BaseViewModel(application) { 17 | 18 | companion object { 19 | private val TAG: String? = DownloadViewModel::class.simpleName 20 | } 21 | 22 | var url1: ObservableField? = ObservableField(Constants.file1) 23 | var url2: ObservableField? = ObservableField(Constants.file2) 24 | var url3: ObservableField? = ObservableField(Constants.picture3) 25 | 26 | var process1: ObservableField? = ObservableField(0) 27 | var process2: ObservableField? = ObservableField(0) 28 | var process3: ObservableField? = ObservableField(0) 29 | 30 | private var downloadManager: DownloadManager? = null 31 | 32 | override fun onCreate() { 33 | super.onCreate() 34 | downloadManager = DownloadManager.get(getApplication()).setMaxRequests(3) 35 | 36 | 37 | } 38 | 39 | /** 40 | * 下载大文件 41 | */ 42 | fun downloadBigFile(index: Int?) { 43 | val url: String? 44 | val tag: Int? 45 | val name: String? 46 | when (index) { 47 | 1 -> { 48 | url = url1?.get() 49 | tag = 1 50 | name = "origen.zip" 51 | } 52 | 2 -> { 53 | url = url2?.get() 54 | tag = 2 55 | name = "opencv.zip" 56 | } 57 | 3 -> { 58 | url = url3?.get() 59 | tag = 3 60 | name = "three.jpg" 61 | } 62 | else -> { 63 | url = url1?.get() 64 | tag = 1 65 | name = "three.jpg" 66 | } 67 | } 68 | 69 | 70 | downloadManager?.download( 71 | url, 72 | BannerUtils.getSdPath(getApplication(), name), 73 | CallBack(), 74 | tag 75 | ) 76 | 77 | } 78 | 79 | /** 80 | *暂停某个任务 81 | */ 82 | fun pauseDownload(index: Int?) { 83 | 84 | val url: String? = when (index) { 85 | 1 -> url1?.get() 86 | 2 -> url2?.get() 87 | 3 -> url3?.get() 88 | else -> url1?.get() 89 | } 90 | downloadManager?.pause(url) 91 | } 92 | 93 | /** 94 | * 暂停某个下载 95 | */ 96 | fun cancelDownload(index: Int?) { 97 | val url: String? = when (index) { 98 | 1 -> url1?.get() 99 | 2 -> url2?.get() 100 | 3 -> url3?.get() 101 | else -> url1?.get() 102 | } 103 | downloadManager?.cancel(url) 104 | } 105 | 106 | 107 | inner class CallBack : DownloaderCallBack() { 108 | override fun onProgress(currentBytes: Long?, totalBytes: Long?, tag: Int?) { 109 | totalBytes?.let { 110 | val sum = currentBytes?.times(1f.div(totalBytes * 1f)) 111 | val process = sum?.times(100) ?: 0 112 | 113 | 114 | when (tag) { 115 | 1 -> process1?.set(process.toInt()) 116 | 2 -> process2?.set(process.toInt()) 117 | 3 -> process3?.set(process.toInt()) 118 | else -> process1?.set(process.toInt()) 119 | } 120 | 121 | Log.e(TAG, "the tag ==$tag+ sum ==$process") 122 | } 123 | 124 | 125 | } 126 | 127 | override fun onFinish(download_file: File?, tag: Int?) { 128 | Log.e(TAG, "download finish file path=" + download_file?.path) 129 | } 130 | 131 | override fun onPause(downloadInfo: DownloadInfo?) { 132 | Log.e(TAG, "download status is pause" + Thread.currentThread()) 133 | } 134 | 135 | override fun onCancel(downloadInfo: DownloadInfo?) { 136 | Log.e(TAG, "download status is cancel" + Thread.currentThread()) 137 | when (downloadInfo?.getTag()) { 138 | 1 -> process1?.set(0) 139 | 2 -> process2?.set(0) 140 | 3 -> process3?.set(0) 141 | else -> process1?.set(0) 142 | } 143 | 144 | } 145 | 146 | override fun onFailure(error_msg: String?) { 147 | Log.e(TAG, "download status is failure" + Thread.currentThread()) 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/download/manager/DownloadInfo.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.download.manager 2 | 3 | import java.io.Serializable 4 | 5 | class DownloadInfo(//下载路径 6 | private var url: String?,// 下載標識 7 | private var tag: Int 8 | ) : Serializable { 9 | private var targetUrl: String? = null//存储路径 10 | private var total: Long? = 0//总大小 11 | private var progress: Long? = 0 //当前进度 12 | 13 | private var fileName: String? = null //名称 14 | 15 | private var downloadState: Int? = 0 //下载状态 16 | 17 | 18 | fun getTag(): Int { 19 | return tag 20 | } 21 | 22 | fun setTag(tag: Int) { 23 | this.tag = tag 24 | } 25 | 26 | fun getUrl(): String? { 27 | return url 28 | } 29 | 30 | fun getFileName(): String? { 31 | return fileName 32 | } 33 | 34 | fun setFileName(fileName: String?) { 35 | this.fileName = fileName 36 | } 37 | 38 | fun getTotal(): Long? { 39 | return total 40 | } 41 | 42 | fun setTotal(total: Long?) { 43 | this.total = total 44 | } 45 | 46 | fun getProgress(): Long? { 47 | return progress 48 | } 49 | 50 | fun setProgress(progress: Long?) { 51 | this.progress = progress 52 | } 53 | 54 | fun getTargetUrl(): String? { 55 | return targetUrl 56 | } 57 | 58 | fun setTargetUrl(targetUrl: String?) { 59 | this.targetUrl = targetUrl 60 | } 61 | 62 | fun setDownloadState(downloadState: Int?) { 63 | this.downloadState = downloadState 64 | } 65 | 66 | fun getDownloadState(): Int? { 67 | return downloadState 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/download/manager/DownloaderCallBack.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.download.manager 2 | 3 | import java.io.File 4 | 5 | abstract class DownloaderCallBack { 6 | 7 | abstract fun onProgress(currentBytes: Long?, totalBytes: Long?, tag: Int?) 8 | abstract fun onFinish(download_file: File?, tag: Int?) 9 | abstract fun onPause(downloadInfo: DownloadInfo?) 10 | abstract fun onCancel(downloadInfo: DownloadInfo?) 11 | abstract fun onFailure(error_msg: String?) 12 | } 13 | 14 | -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/download/manager/ResponseProgressBody.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.download.manager 2 | 3 | import android.content.Context 4 | import com.kt.ktmvvm.utils.PrefsUtil 5 | import kotlinx.coroutines.flow.flow 6 | import kotlinx.coroutines.runBlocking 7 | import okhttp3.MediaType 8 | import okhttp3.ResponseBody 9 | import okio.* 10 | import java.io.IOException 11 | 12 | class ResponseProgressBody( 13 | private var mContext: Context?, 14 | private var mResponseBody: ResponseBody?, 15 | private var callBack: DownloaderCallBack?, 16 | private var info: DownloadInfo? 17 | ) : ResponseBody() { 18 | 19 | private var bufferedSource: BufferedSource? = null 20 | 21 | private var progress: Long = 0//开始前已下载进度 22 | 23 | private var downloadInfo: MutableMap? = null 24 | 25 | 26 | init { 27 | progress = info?.getProgress()!! 28 | downloadInfo = PrefsUtil.getInstance()?.getMap(DownloadManager.DOWNLOAD_MAPS) 29 | if (info?.getTotal()!! <= 0) { 30 | info?.setTotal(mResponseBody?.contentLength()) 31 | downloadInfo?.put(info?.getUrl(), info) 32 | PrefsUtil.getInstance()?.putMap(DownloadManager.DOWNLOAD_MAPS, downloadInfo) 33 | 34 | } 35 | } 36 | 37 | override fun contentType(): MediaType? { 38 | return mResponseBody?.contentType() 39 | } 40 | 41 | override fun contentLength(): Long { 42 | return mResponseBody?.contentLength()!! 43 | } 44 | 45 | override fun source(): BufferedSource { 46 | if (bufferedSource == null) { 47 | bufferedSource = 48 | mResponseBody?.source()?.let { source(it).let { it1 -> Okio.buffer(it1) } } 49 | } 50 | return bufferedSource!! 51 | } 52 | 53 | private fun source(source: Source): Source { 54 | return object : ForwardingSource(source) { 55 | var totalBytesRead: Long = 0 56 | 57 | @Throws(IOException::class) 58 | override fun read(sink: Buffer, byteCount: Long): Long { 59 | val bytesRead = super.read(sink, byteCount) 60 | totalBytesRead += if (bytesRead != -1L) bytesRead else 0 61 | info?.setProgress(totalBytesRead + progress) 62 | 63 | runBlocking { 64 | flow { emit(1) } 65 | .collect { 66 | callBack?.onProgress( 67 | info?.getProgress(), 68 | info?.getTotal(), 69 | info?.getTag() 70 | ) 71 | } 72 | } 73 | 74 | 75 | info?.setDownloadState(DownloadManager.DOWNLOAD_STATE_DOWNLOADING) 76 | downloadInfo!![info?.getUrl()] = info 77 | PrefsUtil.getInstance()?.putMap(DownloadManager.DOWNLOAD_MAPS, downloadInfo) 78 | 79 | return bytesRead 80 | } 81 | } 82 | } 83 | 84 | 85 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/entity/AlbumData.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.entity 2 | 3 | import android.annotation.SuppressLint 4 | import android.database.Cursor 5 | import android.net.Uri 6 | import android.os.Parcel 7 | import android.os.Parcelable 8 | import com.kt.ktmvvm.jetpack.camerax.CameraViewModel 9 | import java.io.Serializable 10 | 11 | class AlbumData : Serializable { 12 | 13 | 14 | companion object { 15 | val ALBUM_ID_ALL = "-1" 16 | val ALBUM_NAME_ALL = "All" 17 | 18 | private var mId: String? = null 19 | private var mCoverPath: Uri? = null 20 | private var mDisplayName: String? = null 21 | private var mCount: Long = 0 22 | 23 | @SuppressLint("Range") 24 | fun valueOf(cursor: Cursor): AlbumData { 25 | val index = cursor.getColumnIndex(CameraViewModel.COLUMN_URI) 26 | val count = cursor.getColumnIndex(CameraViewModel.COLUMN_COUNT) 27 | val uri = if (index >= 0) cursor.getString(index) else null 28 | return AlbumData( 29 | cursor.getString(cursor.getColumnIndex("bucket_id")), 30 | Uri.parse(uri ?: ""), 31 | cursor.getString(cursor.getColumnIndex("bucket_display_name")), 32 | if (count > 0) cursor.getLong(count) else 0 33 | ) 34 | } 35 | 36 | } 37 | 38 | 39 | constructor(id: String?, coverUri: Uri?, displayName: String?, count: Long) { 40 | mId = id 41 | mCoverPath = coverUri 42 | mDisplayName = displayName 43 | mCount = count 44 | } 45 | 46 | constructor(source: Parcel) { 47 | mId = source.readString() 48 | mCoverPath = source.readParcelable(Uri::class.java.classLoader) 49 | mDisplayName = source.readString() 50 | mCount = source.readLong() 51 | } 52 | 53 | 54 | fun getId(): String? { 55 | return mId 56 | } 57 | 58 | /** 59 | * 获取封面路径 60 | * @return 61 | */ 62 | fun getCoverUri(): Uri? { 63 | return mCoverPath 64 | } 65 | 66 | /** 67 | * 获取显示名称 68 | * @return 69 | */ 70 | fun getDisplayName(): String? { 71 | return if (isAll()) { 72 | "所有照片" 73 | } else mDisplayName 74 | } 75 | 76 | /** 77 | * 获取相册数量 78 | * @return 79 | */ 80 | fun getCount(): Long { 81 | return mCount 82 | } 83 | 84 | /** 85 | * 加入拍摄item 86 | */ 87 | fun addCaptureCount() { 88 | mCount++ 89 | } 90 | 91 | fun isAll(): Boolean { 92 | return ALBUM_ID_ALL == mId 93 | } 94 | 95 | fun isEmpty(): Boolean { 96 | return mCount == 0L 97 | } 98 | 99 | override fun toString(): String { 100 | return "AlbumData{" + 101 | "mId='" + mId + '\'' + 102 | ", mCoverPath='" + mCoverPath + '\'' + 103 | ", mDisplayName='" + mDisplayName + '\'' + 104 | ", mCount=" + mCount + 105 | '}' 106 | } 107 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/inner/CameraExtensionModeType.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.inner 2 | 3 | import androidx.annotation.IntDef 4 | 5 | @IntDef( 6 | flag = true, 7 | value = [ 8 | CameraExtensionModeType.NONE, 9 | CameraExtensionModeType.BOKEH, 10 | CameraExtensionModeType.HDR, 11 | CameraExtensionModeType.NIGHT, 12 | CameraExtensionModeType.FACE_RETOUCH, 13 | CameraExtensionModeType.AUTO] 14 | ) 15 | annotation class CameraExtensionModeType { 16 | 17 | companion object { 18 | /** 19 | * 无 20 | */ 21 | const val NONE = 0 22 | 23 | /** 24 | * 焦外成像 25 | */ 26 | const val BOKEH = 1 27 | 28 | /** 29 | * HDR高清 30 | */ 31 | const val HDR = 2 32 | 33 | /** 34 | * 夜景模式 35 | */ 36 | const val NIGHT = 3 37 | 38 | /** 39 | * 脸部修复 40 | */ 41 | const val FACE_RETOUCH = 4 42 | 43 | /** 44 | * 自动 45 | */ 46 | const val AUTO = 5 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/inner/CameraRatioType.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.inner 2 | 3 | import androidx.annotation.IntDef 4 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_1_1 5 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_3_4 6 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_9_16 7 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_FULL 8 | 9 | @IntDef(flag = true, value = [RATIO_3_4, RATIO_9_16, RATIO_1_1, RATIO_FULL]) 10 | annotation class CameraRatioType { 11 | companion object { 12 | const val RATIO_3_4: Int = 0 13 | const val RATIO_9_16: Int = 1 14 | const val RATIO_1_1: Int = 2 15 | const val RATIO_FULL: Int = 3 16 | } 17 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/adapter/RcvAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.adapter 2 | 3 | import android.view.Display 4 | import android.view.View 5 | import androidx.databinding.DataBindingUtil 6 | import androidx.databinding.ViewDataBinding 7 | import com.bumptech.glide.Glide 8 | import com.chad.library.adapter.base.BaseQuickAdapter 9 | import com.chad.library.adapter.base.viewholder.BaseViewHolder 10 | import com.kt.ktmvvm.R 11 | import com.kt.ktmvvm.databinding.RcvItemLayoutBinding 12 | import com.kt.ktmvvm.databinding.ViewpagerItemLayoutBinding 13 | import com.kt.ktmvvm.jetpack.coordinatorlayout.CoordinatorViewModel 14 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2ViewModel 15 | import com.kt.ktmvvm.utils.DisplayUtils 16 | 17 | class RcvAdapter(model: CoordinatorViewModel) : 18 | BaseQuickAdapter(R.layout.rcv_item_layout) { 19 | private var model: CoordinatorViewModel? = model 20 | 21 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { 22 | super.onBindViewHolder(holder, position) 23 | //随机高度 24 | val height: Int = if (holder.adapterPosition % 2 == 0) { 25 | DisplayUtils.dip2px(context, 250f) 26 | } else { 27 | DisplayUtils.dip2px(context, 350f) 28 | } 29 | 30 | 31 | holder.getView(R.id.img).apply { 32 | layoutParams.height = height 33 | layoutParams.width 34 | } 35 | } 36 | 37 | 38 | override fun convert(holder: BaseViewHolder, item: String) { 39 | if (DataBindingUtil.getBinding(holder.itemView) == null) { 40 | RcvItemLayoutBinding.bind(holder.itemView) 41 | } 42 | 43 | val binding = holder.getBinding() 44 | binding?.model = model 45 | 46 | 47 | Glide.with(context).asBitmap().load( 48 | getItem(holder.adapterPosition) 49 | ).into(binding?.img!!) 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/adapter/ViewPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.adapter 2 | 3 | import androidx.databinding.DataBindingUtil 4 | import androidx.databinding.ViewDataBinding 5 | import com.bumptech.glide.Glide 6 | import com.chad.library.adapter.base.BaseQuickAdapter 7 | import com.chad.library.adapter.base.viewholder.BaseViewHolder 8 | import com.kt.ktmvvm.R 9 | import com.kt.ktmvvm.databinding.ViewpagerItemLayoutBinding 10 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2ViewModel 11 | import com.kt.ktmvvm.utils.BannerUtils 12 | 13 | class ViewPagerAdapter(model: ViewPager2ViewModel) : 14 | BaseQuickAdapter(R.layout.viewpager_item_layout) { 15 | 16 | private var model: ViewPager2ViewModel? = model 17 | 18 | override fun convert(holder: BaseViewHolder, item: String) { 19 | try { 20 | if (DataBindingUtil.getBinding(holder.itemView) == null) { 21 | ViewpagerItemLayoutBinding.bind(holder.itemView) 22 | } 23 | 24 | val binding = holder.getBinding() 25 | binding?.model = model 26 | 27 | 28 | Glide.with(context).asBitmap().load( 29 | getItem(holder.adapterPosition) 30 | ).into(binding?.img!!) 31 | } catch (e: Exception) { 32 | } 33 | 34 | } 35 | 36 | 37 | override fun getDefItemCount(): Int { 38 | return Int.MAX_VALUE 39 | } 40 | 41 | override fun getItem(position: Int): String { 42 | return data[position % data.size] 43 | } 44 | 45 | override fun getItemViewType(position: Int): Int { 46 | var count = headerLayoutCount + data.size 47 | if (count <= 0) { 48 | count = 1 49 | } 50 | return super.getItemViewType(position % count) 51 | } 52 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/adapter/ViewPagerVerticalAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.adapter 2 | 3 | import android.view.View 4 | import androidx.core.view.updateLayoutParams 5 | import androidx.databinding.DataBindingUtil 6 | import androidx.databinding.ViewDataBinding 7 | import com.bumptech.glide.Glide 8 | import com.chad.library.adapter.base.BaseQuickAdapter 9 | import com.chad.library.adapter.base.viewholder.BaseViewHolder 10 | import com.kt.ktmvvm.R 11 | import com.kt.ktmvvm.databinding.ViewpagerItemLayoutBinding 12 | import com.kt.ktmvvm.databinding.ViewpagerVerticalItemLayoutBinding 13 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2ViewModel 14 | 15 | class ViewPagerVerticalAdapter(model: ViewPager2ViewModel) : 16 | BaseQuickAdapter(R.layout.viewpager_vertical_item_layout) { 17 | 18 | private var model: ViewPager2ViewModel? = model 19 | 20 | 21 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { 22 | super.onBindViewHolder(holder, position) 23 | 24 | } 25 | override fun convert(holder: BaseViewHolder, item: String) { 26 | try { 27 | if (DataBindingUtil.getBinding(holder.itemView) == null) { 28 | ViewpagerVerticalItemLayoutBinding.bind(holder.itemView) 29 | } 30 | 31 | val binding = holder.getBinding() 32 | binding?.model = model 33 | 34 | Glide.with(context).asBitmap().load(item 35 | ).into(binding?.img!!) 36 | } catch (e: Exception) { 37 | } 38 | 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/camerax/CameraCallBack.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.camerax 2 | 3 | interface CameraCallBack { 4 | 5 | fun ratioCallBack(ratio:Int?) 6 | fun takePictureStatus(success:Boolean,msg:String) 7 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/camerax/CameraParams.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.camerax 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import androidx.camera.extensions.ExtensionMode 6 | import com.kt.ktmvvm.download.manager.DownloadManager 7 | import com.kt.ktmvvm.inner.CameraRatioType 8 | 9 | class CameraParams(context: Context?) { 10 | 11 | companion object { 12 | @SuppressLint("StaticFieldLeak") 13 | private var instance: CameraParams? = null 14 | 15 | 16 | fun get(context: Context?): CameraParams { 17 | if (instance == null) { 18 | synchronized(CameraParams::class.java) { 19 | if (instance == null) { 20 | instance = CameraParams(context) 21 | } 22 | } 23 | } 24 | return instance!! 25 | } 26 | } 27 | 28 | var mFacingFront: Boolean = false //是否是前置摄像头 29 | var mRatioType: Int = CameraRatioType.RATIO_3_4//分辨率尺寸 30 | var mSplashOn: Boolean = false//闪光灯 31 | var torchSwitch: Boolean = false//补光 32 | var timer: Boolean = false//倒计时 33 | var grid: Boolean = false//网格线 34 | var hdr: Boolean = false//hdr 35 | var extensionMode: Int?= ExtensionMode.NONE 36 | 37 | init { 38 | extensionMode = ExtensionMode.NONE 39 | hdr = false 40 | grid = false 41 | timer = false 42 | torchSwitch = false 43 | mFacingFront = false 44 | mRatioType = CameraRatioType.RATIO_3_4 45 | mSplashOn = false 46 | } 47 | 48 | 49 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/camerax/controller/ICameraController.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.camerax.controller 2 | 3 | import com.kt.ktmvvm.inner.CameraRatioType 4 | 5 | interface ICameraController { 6 | /** 7 | * 打开相机 8 | */ 9 | fun openCameraPreView() 10 | 11 | /** 12 | * 录像 13 | */ 14 | fun takePhoto() 15 | 16 | /** 17 | * 拍照 18 | */ 19 | fun takeVideo() 20 | 21 | /** 22 | * 聚焦 23 | */ 24 | fun focus(x: Float, y: Float, auto: Boolean) 25 | 26 | /** 27 | * 切换镜头 28 | */ 29 | 30 | fun switchCamera() 31 | 32 | /** 33 | * 缩放 34 | */ 35 | fun zoom(out: Boolean): Float? 36 | 37 | /** 38 | * 设置分辨率 39 | */ 40 | fun setResolution() 41 | 42 | /** 43 | * 照明、补光 44 | */ 45 | fun torchSwitch() 46 | 47 | /** 48 | * 闪光灯 49 | */ 50 | fun splash() 51 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/coordinatorlayout/CoordinatorActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.coordinatorlayout 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.core.widget.NestedScrollView 6 | import com.google.android.material.bottomsheet.BottomSheetBehavior 7 | import com.kt.ktmvvm.BR 8 | import com.kt.ktmvvm.R 9 | import com.kt.ktmvvm.basic.BaseActivity 10 | import com.kt.ktmvvm.databinding.ActivityCoordinatorLayoutBinding 11 | import com.kt.ktmvvm.widget.MyBottomSheetBehavior 12 | 13 | class CoordinatorActivity : BaseActivity() { 14 | var bottomSheetBehavior: MyBottomSheetBehavior? = null 15 | var starDrawing: Boolean? = false 16 | override fun initVariableId(): Int { 17 | return BR.model 18 | } 19 | 20 | override fun initContentView(savedInstanceState: Bundle?): Int { 21 | return R.layout.activity_coordinator_layout 22 | } 23 | 24 | override fun initParam() { 25 | 26 | bottomSheetBehavior = MyBottomSheetBehavior.from(binding?.bottomSheelt?.nestedView!!) 27 | 28 | bottomSheetBehavior?.addBottomSheetCallback(object : 29 | MyBottomSheetBehavior.BottomSheetCallback() { 30 | override fun onStateChanged(bottomSheet: View, newState: Int) { 31 | 32 | if (newState == BottomSheetBehavior.STATE_EXPANDED) { 33 | bottomSheetBehavior?.isDraggable = false 34 | } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) { 35 | bottomSheetBehavior?.isDraggable = true 36 | } 37 | if (newState == BottomSheetBehavior.STATE_COLLAPSED) { 38 | starDrawing = false 39 | } 40 | } 41 | 42 | override fun onSlide(bottomSheet: View, slideOffset: Float) { 43 | try { 44 | 45 | } catch (e: Exception) { 46 | e.printStackTrace() 47 | } 48 | } 49 | }) 50 | 51 | } 52 | 53 | override fun initViewObservable() { 54 | super.initViewObservable() 55 | viewModel?.canVertically?.observe(this, observer = { 56 | if (it==1){ 57 | if (bottomSheetBehavior != null && bottomSheetBehavior?.state == MyBottomSheetBehavior.STATE_EXPANDED 58 | && bottomSheetBehavior?.state != MyBottomSheetBehavior.STATE_DRAGGING 59 | && bottomSheetBehavior?.state != MyBottomSheetBehavior.STATE_COLLAPSED && !starDrawing!! 60 | ) { 61 | starDrawing = true 62 | bottomSheetBehavior?.state = MyBottomSheetBehavior.STATE_COLLAPSED 63 | } 64 | }else{ 65 | if (bottomSheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) { 66 | bottomSheetBehavior?.isDraggable = true 67 | } 68 | } 69 | 70 | }) 71 | } 72 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/coordinatorlayout/CoordinatorViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.coordinatorlayout 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Application 5 | import android.view.MotionEvent 6 | import android.view.View 7 | import androidx.databinding.ObservableField 8 | import androidx.recyclerview.widget.RecyclerView 9 | import androidx.recyclerview.widget.StaggeredGridLayoutManager 10 | import com.kt.ktmvvm.Constants 11 | import com.kt.ktmvvm.R 12 | import com.kt.ktmvvm.basic.BaseViewModel 13 | import com.kt.ktmvvm.basic.SingleLiveEvent 14 | import com.kt.ktmvvm.decoration.StaggeredDividerItemDecoration 15 | import com.kt.ktmvvm.jetpack.adapter.RcvAdapter 16 | import com.kt.ktmvvm.utils.DisplayUtils 17 | 18 | class CoordinatorViewModel(application: Application) : BaseViewModel(application), 19 | View.OnTouchListener { 20 | 21 | var adapter: ObservableField? = ObservableField(RcvAdapter(this)) 22 | 23 | var layoutManager: ObservableField? = ObservableField( 24 | StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) 25 | ) 26 | 27 | var itemDecoration: ObservableField? = ObservableField( 28 | StaggeredDividerItemDecoration(DisplayUtils.dip2px(getApplication(), 10f), getApplication()) 29 | ) 30 | 31 | var mListener: ObservableField? = ObservableField(OnListener()) 32 | 33 | var canVertically: SingleLiveEvent = SingleLiveEvent() 34 | 35 | var touchListener: ObservableField? = ObservableField(this) 36 | 37 | override fun onCreate() { 38 | super.onCreate() 39 | layoutManager?.get()?.apply { 40 | gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE 41 | isAutoMeasureEnabled = true 42 | } 43 | 44 | adapter?.get()?.setNewInstance(Constants.pictures2) 45 | } 46 | 47 | 48 | fun notifyScroller(newState: Int?, recyclerView: RecyclerView?) { 49 | 50 | if (newState != 0) { 51 | //通知scrolling 52 | //SCROLLING 53 | // canVertically.postValue(0) 54 | } 55 | recyclerView?.parent?.requestDisallowInterceptTouchEvent(true) 56 | val canScrollVertically = recyclerView?.canScrollVertically(-1) 57 | if (!canScrollVertically!! && newState == RecyclerView.SCROLL_STATE_IDLE) { 58 | canVertically.postValue(1) 59 | //CAN_SCROLLVERTICALLY 60 | } 61 | } 62 | 63 | 64 | inner class OnListener : RecyclerView.OnScrollListener() { 65 | 66 | override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { 67 | super.onScrollStateChanged(recyclerView, newState) 68 | notifyScroller(newState, recyclerView) 69 | } 70 | 71 | override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { 72 | super.onScrolled(recyclerView, dx, dy) 73 | } 74 | } 75 | 76 | @SuppressLint("ClickableViewAccessibility") 77 | override fun onTouch(p0: View?, p1: MotionEvent?): Boolean { 78 | if (p0?.id == R.id.view) { 79 | canVertically.postValue(0) 80 | return true 81 | } 82 | return false 83 | } 84 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/room/RoomActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.room 2 | 3 | import android.os.Bundle 4 | import com.kt.ktmvvm.BR 5 | import com.kt.ktmvvm.R 6 | import com.kt.ktmvvm.basic.BaseActivity 7 | import com.kt.ktmvvm.databinding.RoomActivityBinding 8 | 9 | class RoomActivity : BaseActivity() { 10 | override fun initVariableId(): Int { 11 | return BR.model 12 | } 13 | 14 | override fun initContentView(savedInstanceState: Bundle?): Int { 15 | return R.layout.room_activity 16 | } 17 | 18 | override fun initParam() { 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/room/RoomViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.room 2 | 3 | import android.app.Application 4 | import android.util.Log 5 | import androidx.databinding.ObservableField 6 | import androidx.lifecycle.Observer 7 | import androidx.lifecycle.viewModelScope 8 | import com.kt.ktmvvm.basic.BaseViewModel 9 | import com.kt.ktmvvm.jetpack.room.db.User 10 | import com.kt.ktmvvm.jetpack.room.db.UserDataBase 11 | import com.kt.ktmvvm.jetpack.room.db.UserName 12 | import kotlinx.coroutines.Dispatchers 13 | import kotlinx.coroutines.launch 14 | import kotlin.random.Random 15 | 16 | class RoomViewModel(application: Application) : BaseViewModel(application) { 17 | 18 | 19 | var result: ObservableField? = ObservableField("") 20 | 21 | companion object { 22 | val TAG: String = RoomViewModel::class.java.simpleName 23 | } 24 | 25 | /** 26 | * 27 | */ 28 | fun createTable() { 29 | viewModelScope.launch(Dispatchers.IO) { 30 | UserDataBase.get(getApplication()) 31 | } 32 | } 33 | 34 | 35 | /** 36 | * 创建一张表 37 | */ 38 | fun insertTable() { 39 | 40 | viewModelScope.launch { 41 | val random = (1..10).random() 42 | val hotDog = UserDataBase.get(getApplication()).userDao().findById(random) 43 | 44 | hotDog?.let { 45 | Log.d(TAG, "已经有一条相同的数据啦") 46 | result?.set("已经有一条相同的数据啦") 47 | } ?: randomInsert(random) 48 | 49 | //先查询,如果没这条数据 就插入,有的话打印数据 50 | 51 | } 52 | } 53 | 54 | /** 55 | * 随机更新某条User数据 56 | */ 57 | fun updateRandomData() { 58 | //先查询 59 | val random = (1..10).random() 60 | 61 | viewModelScope.launch { 62 | val user = UserDataBase.get(getApplication()).userDao().findById(random) 63 | user?.let { 64 | //如果不为空,则更新 65 | UserDataBase.get(getApplication()).userDao() 66 | .updateUser(User(random, "我是更新整个user后的数据", "男")) 67 | Log.d(TAG, "更新整个user数据成功") 68 | result?.set("更新整个user数据成功") 69 | } ?: randomInsert(random) 70 | } 71 | } 72 | 73 | 74 | /** 75 | * 随机单独更新某个字段 76 | */ 77 | fun updateSingleData() { 78 | //先查询 79 | val random = (1..10).random() 80 | viewModelScope.launch { 81 | val user = UserDataBase.get(getApplication()).userDao().findById(random) 82 | user?.let { 83 | UserDataBase.get(getApplication()).userDao() 84 | .updateSingleName(UserName(random, "我是单独更新后的数据")) 85 | Log.d(TAG, "更新单独数据成功") 86 | result?.set("更新单独数据成功") 87 | } ?: randomInsert(random) 88 | } 89 | } 90 | 91 | 92 | /** 93 | * 删除数据 94 | */ 95 | fun deleteAllData() { 96 | viewModelScope.launch { 97 | val random = (1..10).random() 98 | val user = UserDataBase.get(getApplication()).userDao().findById(random) 99 | user?.let { 100 | UserDataBase.get(getApplication()).userDao().delete(user) 101 | Log.d(TAG, "删除某条数据成功") 102 | result?.set("删除某条数据成功") 103 | } ?: randomInsert(random) 104 | } 105 | } 106 | 107 | 108 | /** 109 | * 随机插入某条数据,方便测试 110 | */ 111 | private fun randomInsert(random: Int) { 112 | val mD = User(random, "热狗先生$random", "女") 113 | UserDataBase.get(getApplication()).userDao().insertAll(mD) 114 | Log.d(TAG, "插入数据成功") 115 | result?.set("插入数据成功") 116 | } 117 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/room/db/User.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.room.db 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | @Entity(tableName = "User") 8 | data class User( 9 | @PrimaryKey val uid: Int, 10 | @ColumnInfo(name = "name") val name: String?, 11 | @ColumnInfo(name = "sex") val sex: String?, 12 | ) 13 | 14 | data class UserName(val uid: Int, val name: String?) -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/room/db/UserDao.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.room.db 2 | 3 | import androidx.room.* 4 | 5 | @Dao 6 | interface UserDao { 7 | 8 | @Query("SELECT * FROM user") 9 | suspend fun getAll(): List? 10 | 11 | @Query("SELECT * FROM user WHERE uid IN (:userIds)") 12 | suspend fun loadAllByIds(userIds: IntArray): List? 13 | 14 | @Query("SELECT * FROM user WHERE name LIKE :name") 15 | suspend fun findByName(name: String): User? 16 | 17 | @Query("SELECT *FROM user WHERE uid LIKE:userId") 18 | suspend fun findById(userId: Int): User? 19 | 20 | @Update(entity = User::class) 21 | suspend fun updateSingleName(vararg name: UserName?) 22 | 23 | @Update 24 | suspend fun updateUser(vararg user: User) 25 | 26 | @Insert 27 | fun insertAll(vararg users: User) 28 | 29 | @Delete 30 | fun delete(user: User) 31 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/room/db/UserDataBase.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.room.db 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import androidx.room.Database 6 | import androidx.room.Room 7 | import androidx.room.RoomDatabase 8 | import androidx.room.migration.Migration 9 | import androidx.sqlite.db.SupportSQLiteDatabase 10 | 11 | @Database(entities = [User::class], version = 1,exportSchema =false) 12 | abstract class UserDataBase : RoomDatabase() { 13 | abstract fun userDao(): UserDao 14 | 15 | companion object { 16 | private var instance: UserDataBase? = null 17 | 18 | private val TAG: String? = UserDataBase::class.simpleName 19 | 20 | fun get(context: Context): UserDataBase { 21 | if (instance == null) { 22 | instance = Room.databaseBuilder(context, UserDataBase::class.java, "user_.db") 23 | .fallbackToDestructiveMigration() 24 | 25 | //是否允许在主线程进行查询 26 | .allowMainThreadQueries() 27 | .fallbackToDestructiveMigration() 28 | // .addMigrations(ADD_FIELD_MIGRATION_1_2) 29 | .addCallback(object : Callback() { 30 | override fun onCreate(db: SupportSQLiteDatabase) { 31 | super.onCreate(db) 32 | Log.e(TAG, "onCreate db_name is=" + db.path) 33 | } 34 | }) 35 | .build() 36 | 37 | 38 | } 39 | return instance!! 40 | } 41 | 42 | 43 | /** 44 | * 增加字段升级 45 | */ 46 | private val ADD_FIELD_MIGRATION_1_2 = object : Migration(1, 2) { 47 | override fun migrate(database: SupportSQLiteDatabase) { 48 | database.execSQL("ALTER TABLE User ADD COLUMN sex Text") 49 | 50 | } 51 | } 52 | 53 | /** 54 | * 删除表升级 55 | */ 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/shapeableimageview/ShapeImageActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.shapeableimageview 2 | 3 | import android.os.Bundle 4 | import com.kt.ktmvvm.BR 5 | import com.kt.ktmvvm.R 6 | import com.kt.ktmvvm.basic.BaseActivity 7 | import com.kt.ktmvvm.databinding.ActivityShapeLayoutBinding 8 | 9 | class ShapeImageActivity: BaseActivity() { 10 | override fun initVariableId(): Int { 11 | return BR.model 12 | } 13 | 14 | override fun initContentView(savedInstanceState: Bundle?): Int { 15 | return R.layout.activity_shape_layout 16 | } 17 | 18 | override fun initParam() { 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/shapeableimageview/ShapeImageViewMode.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.shapeableimageview 2 | 3 | import android.app.Application 4 | import androidx.databinding.ObservableField 5 | import com.kt.ktmvvm.Constants 6 | import com.kt.ktmvvm.basic.BaseViewModel 7 | 8 | class ShapeImageViewMode(application: Application) :BaseViewModel(application) { 9 | 10 | var imgUrl:ObservableField?= ObservableField(Constants.picture12) 11 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/viewpager/ScaleInTransformer.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.viewpager 2 | 3 | import android.view.View 4 | import androidx.viewpager2.widget.ViewPager2 5 | import java.lang.Math.abs 6 | 7 | class ScaleInTransformer: ViewPager2.PageTransformer { 8 | private val mMinScale = DEFAULT_MIN_SCALE 9 | override fun transformPage(view: View, position: Float) { 10 | view.elevation = -kotlin.math.abs(position) 11 | val pageWidth = view.width 12 | val pageHeight = view.height 13 | 14 | view.pivotY = (pageHeight / 2).toFloat() 15 | view.pivotX = (pageWidth / 2).toFloat() 16 | if (position < -1) { 17 | view.scaleX = mMinScale 18 | view.scaleY = mMinScale 19 | view.pivotX = pageWidth.toFloat() 20 | } else if (position <= 1) { 21 | if (position < 0) { 22 | val scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale 23 | view.scaleX = scaleFactor 24 | view.scaleY = scaleFactor 25 | view.pivotX = pageWidth * (DEFAULT_CENTER + DEFAULT_CENTER * -position) 26 | } else { 27 | val scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale 28 | view.scaleX = scaleFactor 29 | view.scaleY = scaleFactor 30 | view.pivotX = pageWidth * ((1 - position) * DEFAULT_CENTER) 31 | } 32 | } else { 33 | view.pivotX = 0f 34 | view.scaleX = mMinScale 35 | view.scaleY = mMinScale 36 | } 37 | } 38 | 39 | companion object { 40 | 41 | const val DEFAULT_MIN_SCALE = 0.85f 42 | const val DEFAULT_CENTER = 0.5f 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/viewpager/ViewPager2Activity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.viewpager 2 | 3 | import android.os.Bundle 4 | import com.kt.ktmvvm.BR 5 | import com.kt.ktmvvm.R 6 | import com.kt.ktmvvm.basic.BaseActivity 7 | import com.kt.ktmvvm.databinding.Viewpager2LayoutBinding 8 | 9 | class ViewPager2Activity: BaseActivity() { 10 | override fun initVariableId(): Int { 11 | return BR.model 12 | } 13 | 14 | override fun initContentView(savedInstanceState: Bundle?): Int { 15 | return R.layout.viewpager2_layout 16 | } 17 | 18 | override fun initParam() { 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/jetpack/viewpager/ViewPager2ViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.jetpack.viewpager 2 | 3 | import android.app.Application 4 | import android.util.Log 5 | import androidx.databinding.ObservableField 6 | import androidx.recyclerview.widget.LinearLayoutManager 7 | import androidx.viewpager2.widget.ViewPager2 8 | import com.kt.ktmvvm.Constants 9 | import com.kt.ktmvvm.basic.BaseViewModel 10 | import com.kt.ktmvvm.jetpack.adapter.ViewPagerAdapter 11 | import com.kt.ktmvvm.jetpack.adapter.ViewPagerVerticalAdapter 12 | import com.kt.ktmvvm.utils.BannerUtils 13 | 14 | class ViewPager2ViewModel(application: Application) : BaseViewModel(application) { 15 | 16 | var adapter: ObservableField? = ObservableField(ViewPagerAdapter(this)) 17 | var verticalAdapter: ObservableField? = 18 | ObservableField(ViewPagerVerticalAdapter(this)) 19 | var pageListener: ObservableField? = 20 | ObservableField(PageListener()) 21 | 22 | var pageCurrentItem: ObservableField? = ObservableField(0) 23 | 24 | 25 | 26 | 27 | override fun onCreate() { 28 | super.onCreate() 29 | 30 | adapter?.get()?.setNewInstance(Constants.pictures) 31 | verticalAdapter?.get()?.setNewInstance(Constants.pictures) 32 | setCurrentItem(0) 33 | } 34 | 35 | 36 | inner class PageListener : ViewPager2.OnPageChangeCallback() { 37 | 38 | override fun onPageSelected(position: Int) { 39 | super.onPageSelected(position) 40 | val size: Int? = adapter?.get()?.data?.size 41 | var currentPosition = size?.let { 42 | BannerUtils.getRealPosition( 43 | isCanLoop(), position, 44 | it 45 | ) 46 | } 47 | Log.e(TAG, "the size is$position") 48 | if (size!! > 0 && isCanLoop() && position == 0 || position == Int.MAX_VALUE - 1) { 49 | currentPosition?.let { setCurrentItem(it) } 50 | } 51 | 52 | } 53 | 54 | 55 | } 56 | 57 | 58 | /** 59 | * 是否可以滑动 60 | */ 61 | fun isCanLoop(): Boolean { 62 | return true 63 | } 64 | 65 | 66 | private fun setCurrentItem(item: Int) { 67 | if (isCanLoop() && adapter?.get()?.data?.size!! > 1) { 68 | pageCurrentItem?.set(Int.MAX_VALUE / 2 - (Int.MAX_VALUE / 2 % adapter?.get()?.data?.size!!) ) 69 | } else { 70 | pageCurrentItem?.set(item) 71 | } 72 | } 73 | 74 | companion object { 75 | val TAG: String? = ViewPager2ViewModel::class.simpleName 76 | } 77 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/loader/MimeType.java: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.loader; 2 | 3 | import androidx.collection.ArraySet; 4 | 5 | import java.util.Arrays; 6 | import java.util.EnumSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * 项目支持的媒体类型 11 | */ 12 | public enum MimeType { 13 | 14 | // 图片类型 15 | JPEG("image/jpeg", arraySetOf( 16 | "jpeg" 17 | )), 18 | JPG("image/jpg", arraySetOf( 19 | "jpg" 20 | )), 21 | BMP("image/bmp", arraySetOf( 22 | "bmp" 23 | )), 24 | PNG("image/png", arraySetOf( 25 | "png" 26 | )), 27 | GIF("image/gif", arraySetOf( 28 | "gif" 29 | )), 30 | 31 | // 视频类型 32 | MPEG("video/mpeg", arraySetOf( 33 | "mpeg", 34 | "mpg" 35 | )), 36 | MP4("video/mp4", arraySetOf( 37 | "mp4", 38 | "m4v" 39 | )), 40 | GPP("video/3gpp", arraySetOf( 41 | "3gpp" 42 | )), 43 | MKV("video/x-matroska", arraySetOf( 44 | "mkv" 45 | )), 46 | AVI("video/avi", arraySetOf( 47 | "avi" 48 | )); 49 | 50 | private final String mMimeType; 51 | private final Set mExtensions; 52 | 53 | MimeType(String mimeType, Set extensions) { 54 | mMimeType = mimeType; 55 | mExtensions = extensions; 56 | } 57 | 58 | public static Set ofAll() { 59 | return EnumSet.allOf(MimeType.class); 60 | } 61 | 62 | public static Set of(MimeType type, MimeType...rest) { 63 | return EnumSet.of(type, rest); 64 | } 65 | 66 | // 图片 67 | public static Set ofImage() { 68 | return EnumSet.of(JPEG, JPG, PNG, BMP, GIF); 69 | } 70 | 71 | // 视频 72 | public static Set ofVideo() { 73 | return EnumSet.of(MPEG, MP4, GPP, MKV, AVI); 74 | } 75 | 76 | public static boolean isImage(String mimeType) { 77 | if (mimeType == null) return false; 78 | return mimeType.startsWith("image"); 79 | } 80 | 81 | public static boolean isVideo(String mimeType) { 82 | if (mimeType == null) return false; 83 | return mimeType.startsWith("video"); 84 | } 85 | 86 | private static Set arraySetOf(String... suffixes) { 87 | return new ArraySet<>(Arrays.asList(suffixes)); 88 | } 89 | 90 | public Set getExtensions() { 91 | return mExtensions; 92 | } 93 | 94 | public String getMimeType() { 95 | return mMimeType; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/net/DataService.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(DelicateCoroutinesApi::class) 2 | 3 | package com.kt.ktmvvm.net 4 | 5 | import com.kt.ktmvvm.MyApp 6 | import kotlinx.coroutines.* 7 | 8 | /** 9 | * 请求管理类 10 | */ 11 | class DataService { 12 | 13 | 14 | companion object { 15 | 16 | /** 17 | * 测试登录样例 18 | */ 19 | suspend fun login(host: Int, account: String, password: String): BaseResponse { 20 | return RetrofitClient.getInstance(MyApp.get()).getDefault(ApiService::class.java, host) 21 | .login(account, password) 22 | } 23 | 24 | /** 25 | * 获取图书馆信息 26 | */ 27 | suspend fun getBookInfo(host: Int): Any? { 28 | return RetrofitClient.getInstance(MyApp.get()).getDefault(ApiService::class.java, host) 29 | .onePiece("","1ddc040748725331b8b841b27977fb82") 30 | } 31 | 32 | 33 | /** 34 | * 历史的今天 35 | */ 36 | suspend fun getHistoryDate(host: Int,date:String): Any?{ 37 | return RetrofitClient.getInstance(MyApp.get()).getDefault(ApiService::class.java, host) 38 | .history(date,"454fe2a1b8dcf7a0c185ba441de56509") 39 | } 40 | 41 | 42 | fun launch( 43 | block: suspend CoroutineScope.() -> Unit, 44 | onError: (e: Throwable) -> Unit = { _: Throwable -> }, 45 | onComplete: () -> Unit = {} 46 | ) { 47 | GlobalScope.launch( 48 | CoroutineExceptionHandler { _, throwable -> 49 | run { 50 | // 这里统一处理错误 51 | ExceptionUtil.catchException(throwable) 52 | onError(throwable) 53 | } 54 | } 55 | ) { 56 | try { 57 | block.invoke(this) 58 | } finally { 59 | onComplete() 60 | } 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/ui/KeyBordActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.ui 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.MotionEvent 7 | import android.view.View 8 | import androidx.recyclerview.widget.RecyclerView 9 | import com.kt.ktmvvm.BR 10 | import com.kt.ktmvvm.R 11 | import com.kt.ktmvvm.basic.BaseActivity 12 | import com.kt.ktmvvm.databinding.KeybordLayoutBinding 13 | import kotlinx.android.synthetic.main.keybord_layout.* 14 | 15 | class KeyBordActivity : BaseActivity() { 16 | override fun initVariableId(): Int { 17 | return BR.model 18 | } 19 | 20 | override fun initContentView(savedInstanceState: Bundle?): Int { 21 | return R.layout.keybord_layout 22 | } 23 | 24 | @SuppressLint("ClickableViewAccessibility") 25 | override fun initParam() { 26 | recycler.setOnTouchListener(View.OnTouchListener { view, motionEvent -> 27 | if (motionEvent.action == MotionEvent.ACTION_UP) { 28 | val x = motionEvent.x 29 | val y = motionEvent.y 30 | val findItem = findItem(x, y, recycler) 31 | Log.i("KEYBORD=", "x="+x+"y="+y) 32 | Log.i("KEYBORD=", findItem.toString()) 33 | } 34 | false 35 | }) 36 | } 37 | 38 | 39 | private fun findItem(x: Float, y: Float, recyclerView: RecyclerView): Int { 40 | val findChildViewUnder = recyclerView.findChildViewUnder(x, y) 41 | findChildViewUnder?.let { 42 | val childViewHolder = recyclerView.getChildViewHolder(findChildViewUnder) 43 | childViewHolder?.let { 44 | return childViewHolder.adapterPosition 45 | } 46 | } 47 | return -1 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/ui/KeyBordAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.ui 2 | 3 | import android.view.View 4 | import android.view.ViewGroup 5 | import android.widget.ImageView 6 | import com.chad.library.adapter.base.BaseQuickAdapter 7 | import com.chad.library.adapter.base.viewholder.BaseViewHolder 8 | import com.kt.ktmvvm.R 9 | 10 | class KeyBordAdapter : BaseQuickAdapter(R.layout.keybord_item_layout) { 11 | 12 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { 13 | super.onBindViewHolder(holder, position) 14 | 15 | val imgIcon = holder.getView(R.id.img_icon) 16 | val desView = holder.getView(R.id.tv_des) 17 | when (position) { 18 | 29 -> { 19 | 20 | //大小写 21 | 22 | imgIcon.apply { 23 | layoutParams.width = 85 24 | layoutParams.height = 65 25 | visibility = View.GONE 26 | // setImageResource(R.drawable.icon_case) 27 | } 28 | 29 | desView.visibility = View.VISIBLE 30 | 31 | 32 | // holder.getItemView() 33 | // .setBackgroundResource(if (isBig) R.drawable.shape_select_bg else R.drawable.shape_un_select_bg) 34 | } 35 | 30 -> { 36 | 37 | imgIcon.apply { 38 | visibility = View.VISIBLE 39 | setImageResource(R.drawable.icon_small_space) 40 | layoutParams.width = 100 41 | layoutParams.height = 50 42 | } 43 | desView.visibility = View.GONE 44 | 45 | 46 | } 47 | data.size - 1 -> { 48 | imgIcon.apply { 49 | visibility = View.VISIBLE 50 | setImageResource(R.drawable.icon_delete) 51 | layoutParams.width = 60 52 | layoutParams.height = 60 53 | } 54 | 55 | desView.visibility = View.GONE 56 | 57 | } 58 | else -> { 59 | imgIcon.visibility = View.GONE 60 | desView.visibility = View.VISIBLE 61 | } 62 | } 63 | } 64 | 65 | override fun convert(holder: BaseViewHolder, item: String) { 66 | holder.setText(R.id.tv_des, item) 67 | } 68 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/ui/KeyBordViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.ui 2 | 3 | import android.app.Application 4 | import androidx.databinding.ObservableField 5 | import androidx.recyclerview.widget.GridLayoutManager 6 | import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup 7 | import com.kt.ktmvvm.basic.BaseViewModel 8 | import com.kt.ktmvvm.utils.KeyDataUtils 9 | 10 | class KeyBordViewModel(application: Application) : BaseViewModel(application) { 11 | 12 | var adapter: ObservableField? = ObservableField(KeyBordAdapter()) 13 | 14 | var manager: ObservableField? = 15 | ObservableField(GridLayoutManager(getApplication(), 20)) 16 | 17 | override fun onCreate() { 18 | super.onCreate() 19 | manager?.get()?.spanSizeLookup = object : SpanSizeLookup() { 20 | override fun getSpanSize(position: Int): Int { 21 | return when (position) { 22 | 20 -> { 23 | 2 24 | } 25 | 30 -> { 26 | 3 27 | } 28 | KeyDataUtils.getLetter().size - 1 -> { 29 | 3 30 | } 31 | else -> { 32 | 2 33 | } 34 | } 35 | } 36 | } 37 | 38 | adapter?.get()?.setNewInstance(KeyDataUtils.getLetter()) 39 | } 40 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/ui/MosaicActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.ui 2 | 3 | import android.annotation.SuppressLint 4 | import android.graphics.Bitmap 5 | import android.os.Bundle 6 | import android.util.Log 7 | import androidx.lifecycle.Observer 8 | import androidx.lifecycle.lifecycleScope 9 | import com.bumptech.glide.Glide 10 | import com.bumptech.glide.request.target.SimpleTarget 11 | import com.bumptech.glide.request.transition.Transition 12 | import com.kt.ktmvvm.BR 13 | import com.kt.ktmvvm.Constants 14 | import com.kt.ktmvvm.R 15 | import com.kt.ktmvvm.basic.BaseActivity 16 | import com.kt.ktmvvm.databinding.ActivityMosaicLayoutBinding 17 | import com.kt.ktmvvm.utils.BannerUtils 18 | import com.kt.ktmvvm.utils.DisplayUtils 19 | import com.kt.ktmvvm.widget.mosic.DrawMosaicView 20 | import com.kt.ktmvvm.widget.mosic.MosaicUtil 21 | import kotlinx.android.synthetic.main.bottom_sheet_layout.* 22 | import kotlinx.coroutines.Dispatchers 23 | import kotlinx.coroutines.flow.collect 24 | import kotlinx.coroutines.launch 25 | 26 | class MosaicActivity : BaseActivity() { 27 | override fun initVariableId(): Int { 28 | return BR.model 29 | } 30 | 31 | override fun initContentView(savedInstanceState: Bundle?): Int { 32 | return R.layout.activity_mosaic_layout 33 | } 34 | 35 | @SuppressLint("CheckResult") 36 | override fun initParam() { 37 | 38 | 39 | viewModel?.bitmapValue?.observe(this, Observer { 40 | it?.let { 41 | binding?.mosaic?.apply { 42 | 43 | layoutParams.width = it.width 44 | layoutParams.height = it.height 45 | setMosaicBackgroundResource(it, true) 46 | val bit = MosaicUtil.getMosaic(it, MosaicUtil.MosaicFormType.RECT) 47 | 48 | if (bit?.isRecycled == false) { 49 | binding?.mosaic?.setMosaicResource(bit) 50 | binding?.mosaic?.setMosaicBrushWidth(50) 51 | binding?.mosaic?.setOnMosaicStateListener(viewModel!!) 52 | } 53 | } 54 | } 55 | }) 56 | 57 | 58 | viewModel?.undo?.observe(this) { 59 | binding?.mosaic?.undoMosaic() 60 | } 61 | 62 | 63 | viewModel?.mosaicType?.observe(this) { it1 -> 64 | val backLayer = binding?.mosaic?.getBackLayer() 65 | var bit: Bitmap? 66 | backLayer?.let { 67 | bit = when (it1) { 68 | 0 -> { 69 | //方形马赛克 70 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.RECT) 71 | } 72 | 1 -> { 73 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.CIRCLE) 74 | } 75 | 2 -> { 76 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.HEXAGONS) 77 | } 78 | else -> { 79 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.RECT) 80 | } 81 | 82 | } 83 | bit?.let { 84 | if (bit?.isRecycled == false) { 85 | binding?.mosaic?.setMosaicResource(bit) 86 | } 87 | } 88 | 89 | 90 | } 91 | 92 | } 93 | } 94 | 95 | 96 | override fun onDestroy() { 97 | super.onDestroy() 98 | binding?.mosaic?.destroy() 99 | } 100 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/ui/MosaicViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.ui 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | import android.graphics.Bitmap 6 | import android.util.Log 7 | import android.view.View 8 | import android.widget.AdapterView 9 | import androidx.databinding.ObservableField 10 | import androidx.lifecycle.viewModelScope 11 | import com.bumptech.glide.Glide 12 | import com.bumptech.glide.request.target.SimpleTarget 13 | import com.bumptech.glide.request.transition.Transition 14 | import com.kt.ktmvvm.Constants 15 | import com.kt.ktmvvm.basic.BaseViewModel 16 | import com.kt.ktmvvm.basic.SingleLiveEvent 17 | import com.kt.ktmvvm.utils.BannerUtils 18 | import com.kt.ktmvvm.utils.DisplayUtils 19 | import com.kt.ktmvvm.widget.mosic.DrawMosaicView 20 | import com.kt.ktmvvm.widget.mosic.MosaicUtil 21 | import kotlinx.coroutines.flow.* 22 | import kotlinx.coroutines.launch 23 | 24 | class MosaicViewModel(application: Application) : BaseViewModel(application), 25 | DrawMosaicView.OnMosaicStateListener, AdapterView.OnItemSelectedListener { 26 | 27 | 28 | var bitmapValue: SingleLiveEvent? = SingleLiveEvent() 29 | var undo: SingleLiveEvent? = SingleLiveEvent() 30 | var listener: ObservableField? = ObservableField(this) 31 | var mosaicType:SingleLiveEvent?= SingleLiveEvent() 32 | 33 | override fun onCreate() { 34 | super.onCreate() 35 | 36 | Glide.with(getApplication() as Context).asBitmap() 37 | .load(Constants.pic2) 38 | .into(object : SimpleTarget() { 39 | override fun onResourceReady(resource: Bitmap, transition: Transition?) { 40 | if (!resource.isRecycled){ 41 | viewModelScope.launch { 42 | flow { 43 | emit(resource) 44 | }.map { 45 | BannerUtils.uniformScale( 46 | it, 47 | DisplayUtils.getScreenHeight(getApplication()), 48 | getApplication() 49 | ) 50 | }.collect { 51 | bitmapValue?.postValue(it) 52 | } 53 | } 54 | 55 | } 56 | 57 | 58 | } 59 | }) 60 | } 61 | 62 | 63 | /** 64 | * 撤销 65 | */ 66 | fun undo() { 67 | undo?.postValue(true) 68 | } 69 | 70 | 71 | override fun mosaicAmount(amountSize: Int?) { 72 | 73 | } 74 | 75 | 76 | override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { 77 | Log.e("TAG", "the po2 is$p2") 78 | mosaicType?.postValue(p2) 79 | } 80 | 81 | override fun onNothingSelected(p0: AdapterView<*>?) { 82 | 83 | } 84 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/utils/DisplayUtils.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.utils 2 | 3 | import android.content.Context 4 | import android.util.DisplayMetrics 5 | import android.view.WindowManager 6 | 7 | object DisplayUtils { 8 | 9 | /** 10 | * 将px值转换为dip或dp值,保证尺寸大小不变 11 | * 12 | * @param pxValue (DisplayMetrics类中属性density) 13 | * @return 14 | */ 15 | fun px2dip(context: Context, pxValue: Float): Int { 16 | val scale: Float = context.resources.displayMetrics.density 17 | return (pxValue / scale + 0.5f).toInt() 18 | } 19 | 20 | /** 21 | * 将dip或dp值转换为px值,保证尺寸大小不变 22 | * 23 | * @param dipValue (DisplayMetrics类中属性density) 24 | * @return 25 | */ 26 | fun dip2px(context: Context?, dipValue: Float): Int { 27 | val scale = context?.resources?.displayMetrics?.density 28 | scale?.let { 29 | 30 | return (dipValue * scale + 0.5f).toInt() 31 | } 32 | return 0 33 | } 34 | 35 | 36 | fun getScreenWidth(context: Context?): Int { 37 | val wm = context?.getSystemService(Context.WINDOW_SERVICE) as WindowManager 38 | val dm = DisplayMetrics() 39 | wm.defaultDisplay.getMetrics(dm) 40 | return dm.widthPixels 41 | } 42 | 43 | 44 | fun getScreenHeight(context: Context?): Int { 45 | val wm = context?.getSystemService(Context.WINDOW_SERVICE) as WindowManager 46 | val dm = DisplayMetrics() 47 | wm.defaultDisplay.getMetrics(dm) 48 | return dm.heightPixels 49 | } 50 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/utils/KeyDataUtils.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.utils 2 | 3 | object KeyDataUtils { 4 | 5 | /** 6 | * 获取小写字母按键 7 | * @return 8 | */ 9 | fun getLetter(): MutableList { 10 | val list: MutableList = ArrayList() 11 | list.add("1") 12 | list.add("2") 13 | list.add("3") 14 | list.add("4") 15 | list.add("5") 16 | list.add("6") 17 | list.add("7") 18 | list.add("8") 19 | list.add("9") 20 | list.add("0") 21 | list.add("q") 22 | list.add("w") 23 | list.add("e") 24 | list.add("r") 25 | list.add("t") 26 | list.add("y") 27 | list.add("u") 28 | list.add("i") 29 | list.add("o") 30 | list.add("p") 31 | list.add("a") 32 | list.add("s") 33 | list.add("d") 34 | list.add("f") 35 | list.add("g") 36 | list.add("h") 37 | list.add("j") 38 | list.add("k") 39 | list.add("l") 40 | list.add("完成") 41 | list.add("空格") 42 | list.add("z") 43 | list.add("x") 44 | list.add("c") 45 | list.add("v") 46 | list.add("b") 47 | list.add("n") 48 | list.add("m") 49 | list.add("删除") 50 | return list 51 | } 52 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/AutoTranslateView.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.animation.ValueAnimator 4 | import android.annotation.SuppressLint 5 | import android.content.Context 6 | import android.util.AttributeSet 7 | import android.util.Log 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.animation.AccelerateDecelerateInterpolator 11 | import android.widget.FrameLayout 12 | import androidx.constraintlayout.widget.Constraints.TAG 13 | import androidx.transition.AutoTransition 14 | import androidx.transition.TransitionManager 15 | import com.kt.ktmvvm.R 16 | import com.kt.ktmvvm.inner.CameraRatioType 17 | import kotlinx.android.synthetic.main.tranlate_view_layout.view.* 18 | import kotlin.math.roundToInt 19 | 20 | class AutoTranslateView : FrameLayout { 21 | 22 | private var isInit = true 23 | 24 | 25 | constructor(context: Context) : super(context) { 26 | 27 | } 28 | 29 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { 30 | 31 | 32 | } 33 | 34 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( 35 | context, 36 | attrs, 37 | defStyleAttr 38 | ) { 39 | 40 | 41 | } 42 | 43 | @SuppressLint("Recycle") 44 | fun startTranslate(height: Int, type: Int) { 45 | Log.d(TAG, "measuredHeight=" + this.height + "height" + height) 46 | val animator: ValueAnimator = 47 | if ((this.height > height)) { 48 | ValueAnimator.ofInt(this.height, height) 49 | } else if (height == 0 && this.height > 0) { 50 | ValueAnimator.ofInt(this.height, height) 51 | } else if (height > 0 && this.height == 0) { 52 | ValueAnimator.ofInt(this.height, height) 53 | } else if (this.height != 0 && this.height < height) { 54 | ValueAnimator.ofInt(this.height, height) 55 | } else { 56 | ValueAnimator.ofInt(height, this.height) 57 | } 58 | 59 | 60 | 61 | 62 | 63 | animator.addUpdateListener { 64 | val animatedValue = it.animatedValue as Int 65 | Log.d(TAG, "animatedValue=$animatedValue") 66 | this.layoutParams?.height = animatedValue 67 | 68 | requestLayout() 69 | } 70 | 71 | 72 | if (isInit) { 73 | isInit = false 74 | animator.duration = 0 75 | } else { 76 | animator.duration = 200 77 | } 78 | //开始动画 79 | animator.start() 80 | } 81 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/FocusView.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.animation.ObjectAnimator 4 | import android.annotation.SuppressLint 5 | import android.content.Context 6 | import android.graphics.Canvas 7 | import android.graphics.Color 8 | import android.graphics.Paint 9 | import android.graphics.RectF 10 | import android.util.AttributeSet 11 | import android.view.MotionEvent 12 | import android.view.View 13 | 14 | class FocusView : View { 15 | 16 | private var paint: Paint? = null 17 | private val mRectF = RectF() 18 | private var mRectWidth: Float = 10f 19 | 20 | companion object { 21 | const val ANIMATION_SMALL = 500 22 | } 23 | 24 | constructor(context: Context) : super(context) { 25 | initView(context, null) 26 | } 27 | 28 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { 29 | initView(context, attributeSet) 30 | } 31 | 32 | 33 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super( 34 | context, 35 | attributeSet, 36 | defStyleAttr 37 | ) { 38 | 39 | 40 | } 41 | 42 | 43 | 44 | 45 | private fun initView(context: Context, attributeSet: AttributeSet?) { 46 | 47 | paint = Paint() 48 | paint?.isAntiAlias = true 49 | paint?.color = Color.WHITE 50 | paint?.style = Paint.Style.STROKE 51 | paint?.strokeWidth = 3f 52 | 53 | 54 | } 55 | 56 | override fun onDraw(canvas: Canvas?) { 57 | super.onDraw(canvas) 58 | val width = measuredWidth 59 | val height = measuredHeight 60 | 61 | mRectF.set( 62 | 0f + mRectWidth, 63 | 0f + mRectWidth, 64 | width.toFloat() - mRectWidth, 65 | height.toFloat() - mRectWidth 66 | ) 67 | mRectWidth = 10f 68 | canvas?.drawRoundRect(mRectF, 10f, 10f, paint!!) 69 | } 70 | 71 | 72 | /** 73 | * 聚焦动画 74 | */ 75 | 76 | fun focusAnimate() { 77 | val lastRectWidth = mRectWidth + 80f 78 | 79 | val rectSizeAnimator = ObjectAnimator.ofFloat( 80 | this, "rectWidth", 81 | mRectWidth, lastRectWidth 82 | ).setDuration(ANIMATION_SMALL.toLong()) 83 | 84 | 85 | rectSizeAnimator.start() 86 | } 87 | 88 | /** 89 | * 设置中心矩阵的宽度 90 | * 91 | * @param rectWidth 92 | */ 93 | fun setRectWidth(rectWidth: Float) { 94 | mRectWidth = rectWidth 95 | invalidate() 96 | } 97 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/GridView.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.content.Context 4 | import android.graphics.Canvas 5 | import android.graphics.Color 6 | import android.graphics.Paint 7 | import android.util.AttributeSet 8 | import android.view.View 9 | import com.kt.ktmvvm.R 10 | 11 | class GridView : View { 12 | 13 | constructor(context: Context) : super(context) { 14 | 15 | } 16 | 17 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { 18 | 19 | initView(context) 20 | 21 | } 22 | 23 | 24 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( 25 | context, 26 | attrs, 27 | defStyleAttr 28 | ) { 29 | 30 | 31 | } 32 | 33 | var paint: Paint? = null 34 | 35 | 36 | private fun initView(context: Context) { 37 | //初始化画笔 38 | 39 | paint = Paint() 40 | paint?.isAntiAlias = true 41 | paint?.style = Paint.Style.STROKE 42 | paint?.strokeWidth = 1f 43 | paint?.color =context.resources.getColor(R.color.color_c5c5c5) 44 | 45 | } 46 | 47 | override fun onDraw(canvas: Canvas?) { 48 | super.onDraw(canvas) 49 | val mHeight = height 50 | val mWidth = width 51 | var verLine = 1 / 3f 52 | var horLine = 1 / 3f 53 | 54 | for (i in 0 until 2) { 55 | //绘制横线 第一条在1/3 height上, 56 | canvas?.drawLine(0f, verLine * mHeight, mWidth * 1f, verLine * mHeight, paint!!) 57 | //绘制纵线 58 | 59 | canvas?.drawLine(mWidth * horLine, 0f, mWidth * horLine, mHeight * 1f, paint!!) 60 | 61 | horLine = 2 / 3f 62 | verLine = 2 / 3f 63 | 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/PopWin.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.content.Context 4 | import android.graphics.drawable.ColorDrawable 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.view.animation.DecelerateInterpolator 9 | import android.widget.CompoundButton 10 | import android.widget.PopupWindow 11 | import androidx.camera.extensions.ExtensionMode 12 | import androidx.databinding.DataBindingUtil 13 | import androidx.transition.AutoTransition 14 | import androidx.transition.TransitionManager 15 | import com.kt.ktmvvm.R 16 | import com.kt.ktmvvm.databinding.PopuLayoutBinding 17 | import com.kt.ktmvvm.jetpack.camerax.CameraParams 18 | 19 | class PopWin(context: Context?) : PopupWindow(context), View.OnClickListener { 20 | 21 | 22 | private var listener: OnPopCheckListener? = null 23 | private var mContext = context 24 | var binding: PopuLayoutBinding? = null 25 | var cameraParams: CameraParams? = null 26 | 27 | init { 28 | binding = DataBindingUtil.inflate( 29 | LayoutInflater.from(context), 30 | R.layout.popu_layout, 31 | null, 32 | false 33 | 34 | ) 35 | 36 | cameraParams = CameraParams.get(context) 37 | 38 | isClippingEnabled = false 39 | contentView = binding?.root 40 | width = ViewGroup.LayoutParams.MATCH_PARENT 41 | height = ViewGroup.LayoutParams.WRAP_CONTENT 42 | isFocusable = false 43 | setBackgroundDrawable(ColorDrawable(0)) 44 | } 45 | 46 | 47 | private fun dip2px(context: Context?, dipValue: Float): Int { 48 | val scale = context!!.resources.displayMetrics.density 49 | return (dipValue * scale + 0.5f).toInt() 50 | } 51 | 52 | fun hidePop() { 53 | if (isShowing) { 54 | dismiss() 55 | } 56 | } 57 | 58 | /** 59 | * 显示Pop 60 | */ 61 | fun showPop(view: View?) { 62 | if (isShowing) { 63 | dismiss() 64 | } else { 65 | showAsDropDown(view) 66 | binding?.lightLayout?.setOnClickListener(this) 67 | binding?.timerLayout?.setOnClickListener(this) 68 | binding?.spashLayout?.setOnClickListener(this) 69 | binding?.gridLayou?.setOnClickListener(this) 70 | binding?.hdrLayout?.setOnClickListener(this) 71 | 72 | } 73 | } 74 | 75 | fun setOnPopCheckListener(listener: OnPopCheckListener?) { 76 | this.listener = listener 77 | } 78 | 79 | 80 | interface OnPopCheckListener { 81 | fun lightCheck() 82 | fun delay() 83 | fun splash() 84 | fun grid() 85 | fun hdr() 86 | } 87 | 88 | 89 | override fun onClick(p0: View?) { 90 | 91 | when (p0?.id) { 92 | R.id.light_layout -> { 93 | cameraParams?.torchSwitch = !cameraParams?.torchSwitch!! 94 | binding?.ivLight?.isSelected = cameraParams?.torchSwitch!! 95 | binding?.nightLight?.isSelected = cameraParams?.torchSwitch!! 96 | listener?.lightCheck() 97 | } 98 | R.id.timer_layout -> { 99 | cameraParams?.timer = !cameraParams?.timer!! 100 | binding?.ivTimer?.isSelected = cameraParams?.timer!! 101 | binding?.timer?.isSelected = cameraParams?.timer!! 102 | listener?.delay() 103 | } 104 | R.id.spash_layout -> { 105 | cameraParams?.mSplashOn = !cameraParams?.mSplashOn!! 106 | binding?.ivSplash?.isSelected=cameraParams?.mSplashOn!! 107 | binding?.splashLine?.isSelected=cameraParams?.mSplashOn!! 108 | listener?.splash() 109 | } 110 | R.id.grid_layou -> { 111 | cameraParams?.grid = !cameraParams?.grid!! 112 | binding?.ivGrid?.isSelected=cameraParams?.grid!! 113 | binding?.gridLine?.isSelected=cameraParams?.grid!! 114 | listener?.grid() 115 | } 116 | R.id.hdr_layout -> { 117 | cameraParams?.hdr = !cameraParams?.hdr!! 118 | binding?.ivHdr?.isSelected=cameraParams?.hdr!! 119 | binding?.hdr?.isSelected=cameraParams?.hdr!! 120 | if (cameraParams?.hdr==true){ 121 | cameraParams?.extensionMode=ExtensionMode.HDR 122 | }else{ 123 | cameraParams?.extensionMode=ExtensionMode.NONE 124 | } 125 | listener?.hdr() 126 | } 127 | } 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/RecordCountDownView.java: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.util.AttributeSet; 7 | import android.view.Gravity; 8 | import android.view.animation.Animation; 9 | import android.view.animation.AnimationUtils; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | import androidx.appcompat.widget.AppCompatTextView; 14 | 15 | 16 | import com.kt.ktmvvm.R; 17 | 18 | import java.lang.ref.WeakReference; 19 | 20 | /** 21 | * 录制倒计时显示控件 22 | */ 23 | public class RecordCountDownView extends AppCompatTextView { 24 | 25 | private static final int COUNT_DOWN = 0x001; 26 | 27 | private static final int COUNT_DURATION = 1000; 28 | private int mCountDown = 3; 29 | 30 | // 是否处于倒计时阶段 31 | private volatile boolean isCountDowning; 32 | 33 | private OnCountDownListener mListener; 34 | private final CountDownHandler mHandler; 35 | 36 | public RecordCountDownView(Context context) { 37 | this(context, null); 38 | } 39 | 40 | public RecordCountDownView(Context context, @Nullable AttributeSet attrs) { 41 | this(context, attrs, 0); 42 | } 43 | 44 | public RecordCountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 45 | super(context, attrs, defStyleAttr); 46 | setGravity(Gravity.CENTER); 47 | mHandler = new CountDownHandler(this); 48 | } 49 | 50 | /** 51 | * 设置倒计时时长 52 | * @param countDown 53 | */ 54 | public void setCountDown(int countDown) { 55 | mCountDown = countDown; 56 | } 57 | 58 | /** 59 | * 取消倒计时 60 | */ 61 | public void cancel() { 62 | mHandler.removeCallbacksAndMessages(null); 63 | setText(""); 64 | if (mListener != null) { 65 | mListener.onCountDownCancel(); 66 | } 67 | isCountDowning = false; 68 | } 69 | 70 | /** 71 | * 开始倒计时 72 | */ 73 | public void start() { 74 | isCountDowning = true; 75 | mHandler.sendMessage(mHandler.obtainMessage(COUNT_DOWN, mCountDown, 0)); 76 | } 77 | 78 | /** 79 | * 判断是否正处于倒计时阶段 80 | * @return 81 | */ 82 | public boolean isCountDowning() { 83 | return isCountDowning; 84 | } 85 | 86 | /** 87 | * 更新文字的动画 88 | */ 89 | private void updateTextAnimate() { 90 | Animation enterAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_fade_in); 91 | startAnimation(enterAnimation); 92 | } 93 | 94 | public interface OnCountDownListener { 95 | 96 | void onCountDownEnd(); 97 | 98 | void onCountDownCancel(); 99 | } 100 | 101 | public void addOnCountDownListener(OnCountDownListener listener) { 102 | mListener = listener; 103 | } 104 | 105 | private static class CountDownHandler extends Handler { 106 | 107 | private final WeakReference mWeakCountDownView; 108 | 109 | public CountDownHandler(@NonNull RecordCountDownView countDownView) { 110 | mWeakCountDownView = new WeakReference<>(countDownView); 111 | } 112 | 113 | @Override 114 | public void handleMessage(Message msg) { 115 | if (mWeakCountDownView.get() == null) { 116 | return; 117 | } 118 | RecordCountDownView countDownView = mWeakCountDownView.get(); 119 | switch (msg.what) { 120 | case COUNT_DOWN: 121 | if (msg.arg1 > 0) { 122 | countDownView.setText(String.valueOf(msg.arg1)); 123 | countDownView.updateTextAnimate(); 124 | sendMessageDelayed(obtainMessage(COUNT_DOWN, msg.arg1 - 1, 0), COUNT_DURATION); 125 | } else { 126 | countDownView.setText(""); 127 | if (countDownView.mListener != null) { 128 | countDownView.mListener.onCountDownEnd(); 129 | } 130 | countDownView.isCountDowning = false; 131 | } 132 | break; 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/TakePhotoView.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.animation.AnimatorSet 4 | import android.animation.ObjectAnimator 5 | import android.annotation.SuppressLint 6 | import android.content.Context 7 | import android.util.AttributeSet 8 | import android.view.LayoutInflater 9 | import android.view.MotionEvent 10 | import android.view.View 11 | import android.widget.RelativeLayout 12 | import androidx.databinding.DataBindingUtil 13 | import com.kt.ktmvvm.R 14 | import com.kt.ktmvvm.databinding.TakePhotoViewBinding 15 | import kotlin.math.abs 16 | 17 | class TakePhotoView : RelativeLayout { 18 | 19 | private var listener: OnBottomTabClick? = null 20 | private var binding: TakePhotoViewBinding? = null 21 | private var isDown = false 22 | constructor(context: Context) : super(context) { 23 | 24 | } 25 | 26 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { 27 | 28 | initView(context, attributeSet) 29 | } 30 | 31 | 32 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super( 33 | context, 34 | attributeSet, 35 | defStyleAttr 36 | ) { 37 | 38 | 39 | } 40 | 41 | @SuppressLint("ClickableViewAccessibility") 42 | private fun initView(context: Context, attributeSet: AttributeSet) { 43 | 44 | binding = DataBindingUtil.inflate( 45 | LayoutInflater.from(context), 46 | R.layout.take_photo_view, 47 | this, 48 | true 49 | ) 50 | 51 | // binding?.takePicture?.setOnTouchListener { v: View?, event: MotionEvent -> 52 | // when (event.action) { 53 | // MotionEvent.ACTION_DOWN -> { 54 | // if (!isDown) { 55 | // binding?.takePicture?.setBackgroundResource(R.drawable.icon_take_picture_down) 56 | // } 57 | // isDown = true 58 | // return@setOnTouchListener true 59 | // } 60 | // MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { 61 | // binding?.takePicture?.setBackgroundResource(R.drawable.icon_take_picture_normal) 62 | // isDown = false 63 | // if (listener != null) { 64 | // listener?.takePicture() 65 | // } 66 | // return@setOnTouchListener true 67 | // } 68 | // } 69 | // false 70 | // } 71 | binding?.takePicture?.setOnClickListener { 72 | if (isFastClick()) { 73 | return@setOnClickListener 74 | } 75 | startTakePictureAnimation() 76 | listener?.takePicture() 77 | } 78 | 79 | 80 | } 81 | 82 | 83 | /** 84 | * 开启按钮动效 85 | */ 86 | private fun startTakePictureAnimation() { 87 | binding?.takePicture?.let { 88 | val animatorX = 89 | ObjectAnimator.ofFloat(binding?.takePicture, "scaleX", 1.0f, 0.8f, 0.8f, 1.0f) 90 | val animatorY = 91 | ObjectAnimator.ofFloat(binding?.takePicture, "scaleY", 1.0f, 0.8f, 0.8f, 1.0f) 92 | val set = AnimatorSet() 93 | set.play(animatorX).with(animatorY) 94 | set.duration = 50 95 | set.start() 96 | } 97 | 98 | } 99 | 100 | 101 | companion object { 102 | private var CLEAN_DELAY_CLICK_FAST = 0L 103 | 104 | fun isFastClick(): Boolean { 105 | val curClickTime = System.currentTimeMillis() 106 | //500ms不让重复点击 避免用户先把时间跳到后几天在调回来时点不动按钮的问题 107 | val timeInterval: Long = 108 | abs(curClickTime - CLEAN_DELAY_CLICK_FAST) 109 | return if (timeInterval <= 800) { 110 | true 111 | } else { 112 | CLEAN_DELAY_CLICK_FAST = curClickTime 113 | false 114 | } 115 | } 116 | } 117 | 118 | fun setOnBottomTabClick(bottomTabClick: OnBottomTabClick) { 119 | this.listener = bottomTabClick 120 | } 121 | 122 | interface OnBottomTabClick { 123 | fun reset() 124 | fun takePicture() 125 | fun closeDown() 126 | } 127 | 128 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/TimerHelper.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.animation.Animator 4 | import android.animation.AnimatorListenerAdapter 5 | import android.animation.ValueAnimator 6 | import android.view.animation.LinearInterpolator 7 | import com.blankj.utilcode.util.StringUtils 8 | import com.kt.ktmvvm.R 9 | 10 | 11 | /** 12 | * 计时器 13 | */ 14 | class TimerHelper { 15 | private var animator: ValueAnimator? = null 16 | private var currentTime: Long = 0 17 | private var onTimerHelperListener: OnTimerHelperListener? = null 18 | 19 | 20 | fun startTimer(time: Long) { 21 | if (time <= 0) { 22 | return 23 | } 24 | stopTimer() 25 | currentTime = time 26 | if (animator == null) { 27 | animator = ValueAnimator.ofInt(60, 0) 28 | } 29 | if (animator?.isRunning == true) return 30 | animator?.interpolator = LinearInterpolator() 31 | animator?.duration = 1000 32 | animator?.repeatCount = ValueAnimator.INFINITE 33 | animator?.repeatMode = ValueAnimator.RESTART 34 | animator?.addUpdateListener { animation: ValueAnimator -> 35 | val progress = animation.animatedValue as Int 36 | val progressText = covertTime(currentTime, progress) 37 | if (onTimerHelperListener != null) { 38 | onTimerHelperListener?.onProgress(progressText) 39 | } 40 | } 41 | animator?.addListener(object : AnimatorListenerAdapter() { 42 | override fun onAnimationRepeat(animation: Animator) { 43 | currentTime -= 1000 44 | if (currentTime <= 0) { 45 | stopTimer() 46 | if (onTimerHelperListener != null) { 47 | onTimerHelperListener?.onOverTimer() 48 | } 49 | } 50 | } 51 | }) 52 | animator?.start() 53 | } 54 | 55 | 56 | fun stopTimer() { 57 | if (animator != null) { 58 | animator?.cancel() 59 | animator = null 60 | } 61 | } 62 | 63 | fun setOnTimerHelperListener(listener: OnTimerHelperListener?) { 64 | onTimerHelperListener = listener 65 | } 66 | 67 | private fun covertTime(time: Long, suffix: Int): String { 68 | if (time <= 0) { 69 | return "00:00:00" 70 | } 71 | val total = (time / 1000).toInt() 72 | val minute = total / 60 73 | val second = total % 60 74 | return if (minute <= 0) { 75 | StringUtils.getString(R.string.second_format, second, suffix) 76 | } else { 77 | val len = minute.toString().length 78 | if (len < 3) { 79 | StringUtils.getString(R.string.minute_second_format, minute, second, suffix) 80 | } else { 81 | StringUtils.getString(R.string.minute_second_format1, minute, second, suffix) 82 | } 83 | } 84 | } 85 | 86 | interface OnTimerHelperListener { 87 | fun onProgress(progress: String?) {} 88 | fun onOverTimer() 89 | } 90 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/TopView.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.util.AttributeSet 6 | import android.view.LayoutInflater 7 | import android.view.MotionEvent 8 | import android.view.View 9 | import android.widget.RelativeLayout 10 | import androidx.databinding.DataBindingUtil 11 | import com.kt.ktmvvm.R 12 | import com.kt.ktmvvm.databinding.TopFactorLayoutBinding 13 | 14 | class TopView : RelativeLayout { 15 | 16 | 17 | private var popWinListener: PopWin.OnPopCheckListener? = null 18 | private var ratioListener: RatioPop.OnRatioViewListener? = null 19 | private var listener: OnTopViewListener? = null 20 | private var popWin: PopWin? = null 21 | private var ratioPop: RatioPop? = null 22 | 23 | constructor(context: Context) : super(context) { 24 | 25 | } 26 | 27 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { 28 | 29 | initView(context, attributeSet) 30 | } 31 | 32 | 33 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super( 34 | context, 35 | attributeSet, 36 | defStyleAttr 37 | ) { 38 | 39 | 40 | } 41 | 42 | 43 | private fun initView(context: Context, attributeSet: AttributeSet) { 44 | 45 | val binding = DataBindingUtil.inflate( 46 | LayoutInflater.from(context), 47 | R.layout.top_factor_layout, 48 | this, 49 | true 50 | ) 51 | 52 | 53 | binding.flBackPage.setOnClickListener { 54 | addClickScale(binding.flBackPage) 55 | listener?.backCamera() 56 | } 57 | 58 | binding.flSetting.setOnClickListener { 59 | addClickScale(binding.flSetting) 60 | if (popWin == null) { 61 | popWin = PopWin(context) 62 | } 63 | popWin?.setOnPopCheckListener(popWinListener) 64 | ratioPop?.hidePop() 65 | popWin?.showPop(binding?.top) 66 | } 67 | 68 | binding.flBl.setOnClickListener { 69 | addClickScale(binding.flBl) 70 | if (ratioPop == null) { 71 | ratioPop = RatioPop(context) 72 | } 73 | ratioPop?.setOnRatioViewListener(ratioListener) 74 | popWin?.hidePop() 75 | ratioPop?.showPop(binding.top) 76 | } 77 | 78 | } 79 | 80 | fun hideSettingPop(){ 81 | popWin?.hidePop() 82 | } 83 | fun hideRatioPop(){ 84 | ratioPop?.hidePop() 85 | } 86 | 87 | fun setOnPopCheckListener(listener: PopWin.OnPopCheckListener) { 88 | this.popWinListener = listener 89 | } 90 | 91 | fun setOnRatioViewListener(listener: RatioPop.OnRatioViewListener) { 92 | this.ratioListener = listener 93 | } 94 | 95 | fun setOnTopViewListener(listener: OnTopViewListener) { 96 | this.listener = listener 97 | } 98 | 99 | interface OnTopViewListener { 100 | fun backCamera() 101 | 102 | } 103 | 104 | @SuppressLint("ClickableViewAccessibility") 105 | fun addClickScale(view: View, scale: Float = 0.8f, duration: Long = 100) { 106 | view.setOnTouchListener { _, event -> 107 | when (event.action) { 108 | MotionEvent.ACTION_DOWN -> { 109 | view.animate().scaleX(scale).scaleY(scale).setDuration(duration).start() 110 | } 111 | MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { 112 | view.animate().scaleX(1f).scaleY(1f).setDuration(duration).start() 113 | } 114 | } 115 | // 点击事件处理,交给View自身 116 | view.onTouchEvent(event) 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/TranslateView.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.MotionEvent 6 | import android.widget.RelativeLayout 7 | 8 | class TranslateView : RelativeLayout { 9 | private var listener: OnTranslateTouchListener? = null 10 | 11 | constructor(context: Context) : super(context) { 12 | 13 | } 14 | 15 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) { 16 | 17 | 18 | } 19 | 20 | 21 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super( 22 | context, 23 | attributeSet, 24 | defStyleAttr 25 | ) { 26 | 27 | 28 | } 29 | 30 | override fun onTouchEvent(event: MotionEvent?): Boolean { 31 | listener?.touchTrans() 32 | return super.onTouchEvent(event) 33 | } 34 | 35 | fun setOnTranslateTouchListener(listener: OnTranslateTouchListener) { 36 | this.listener = listener 37 | } 38 | 39 | interface OnTranslateTouchListener { 40 | fun touchTrans() 41 | } 42 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/kt/ktmvvm/widget/mosic/MosaicPath.kt: -------------------------------------------------------------------------------- 1 | package com.kt.ktmvvm.widget.mosic 2 | 3 | import android.graphics.Path 4 | 5 | class MosaicPath{ 6 | 7 | /** 8 | * 绘画路径 9 | */ 10 | var drawPath: Path? = null 11 | 12 | /** 13 | * 绘画粗细 14 | */ 15 | var paintWidth = 0 16 | } -------------------------------------------------------------------------------- /demo/src/main/res/anim/anim_fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /demo/src/main/res/color/color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/color/po_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/bishua2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/bishua2.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/bishua3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/bishua3.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/bishua4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/bishua4.jpg -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/gird_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/gird_off.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/gird_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/gird_on.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/hdr_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/hdr_off.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/hdr_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/hdr_on.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_bg_space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_bg_space.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_bl.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_camera_close_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_camera_close_normal.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_camera_close_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_camera_close_pressed.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_case.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_case.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_delete.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_reset_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_reset_camera.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_small_space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_small_space.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_switch_camera_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_switch_camera_normal.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_switch_camera_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_switch_camera_pressed.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_take_picture_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_down.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_take_picture_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_normal.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_normal.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_pressed.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/icon_top_setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_top_setting.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/light_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/light_check.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/light_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/light_normal.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/maoshua.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/maoshua.jpg -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/splash_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/splash_close.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/splash_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/splash_open.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/timer_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/timer_off.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/timer_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/timer_on.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable/bg_black_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/close_camera_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/grid_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/hdr_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/light_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/selector_9_16.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/selector_keyboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/selector_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/shape_9_16.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/shape_9_16_fd87aa.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/shape_select_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/shape_un_select_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/splash_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/switch_camera_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/switch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/switch_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/timer_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/white_c_15_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/yellow_switch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_coordinator_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 16 | 17 | 18 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_main_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 18 | 19 | 20 |