├── .gitignore
├── .idea
├── .name
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── gradle.xml
├── jarRepositories.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── Larger
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── starot
│ │ └── larger
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── starot
│ │ │ └── larger
│ │ │ ├── Larger.kt
│ │ │ ├── act
│ │ │ ├── CustomLargerAct.kt
│ │ │ └── LargerAct.kt
│ │ │ ├── adapter
│ │ │ └── FgPageAdapter.kt
│ │ │ ├── anim
│ │ │ ├── AnimBgHelper.kt
│ │ │ ├── AnimDragHelper.kt
│ │ │ ├── AnimEnterHelper.kt
│ │ │ ├── AnimExitHelper.kt
│ │ │ ├── AnimParentHelper.kt
│ │ │ └── impl
│ │ │ │ ├── AnimListener.kt
│ │ │ │ ├── OnAnimatorIntercept.kt
│ │ │ │ └── OnDragAnimListener.kt
│ │ │ ├── bean
│ │ │ └── LargerBean.kt
│ │ │ ├── builder
│ │ │ ├── LargerBuilder.kt
│ │ │ ├── config
│ │ │ │ ├── ImageMultiConfig.kt
│ │ │ │ ├── ImageSingleConfig.kt
│ │ │ │ ├── VideoMultiConfig.kt
│ │ │ │ └── VideoSingleConfig.kt
│ │ │ └── impl
│ │ │ │ ├── CommandConfig.kt
│ │ │ │ ├── ImageConfig.kt
│ │ │ │ ├── MultiConfig.kt
│ │ │ │ ├── SingleConfig.kt
│ │ │ │ └── VideoConfig.kt
│ │ │ ├── config
│ │ │ └── Config.kt
│ │ │ ├── enums
│ │ │ ├── AnimStatus.kt
│ │ │ ├── AnimType.kt
│ │ │ ├── BackEnum.kt
│ │ │ ├── LargerDataEnum.kt
│ │ │ ├── LargerEnum.kt
│ │ │ ├── LoadImageStatus.kt
│ │ │ └── Orientation.kt
│ │ │ ├── fragment
│ │ │ ├── BaseLargerFragment.kt
│ │ │ ├── ImageFg.kt
│ │ │ └── VideoFg.kt
│ │ │ ├── impl
│ │ │ ├── OnImageLoadListener.kt
│ │ │ ├── OnLargerConfigListener.kt
│ │ │ ├── OnLargerListener.kt
│ │ │ ├── OnLargerType.kt
│ │ │ ├── OnLifecycleListener.kt
│ │ │ ├── OnLoadProgressListener.kt
│ │ │ └── OnVideoLoadListener.kt
│ │ │ ├── livedata
│ │ │ └── UnViscousLiveData.kt
│ │ │ ├── status
│ │ │ └── LargerStatus.kt
│ │ │ ├── utils
│ │ │ ├── ColorTool.kt
│ │ │ ├── LogUtils.kt
│ │ │ ├── PageChange.kt
│ │ │ └── StatusBarTools.kt
│ │ │ └── view
│ │ │ ├── image
│ │ │ ├── Compat.java
│ │ │ ├── CustomGestureDetector.java
│ │ │ ├── LargerImageView.java
│ │ │ ├── OnGestureListener.java
│ │ │ ├── OnLargerDragListener.kt
│ │ │ ├── OnLargerScaleListener.kt
│ │ │ ├── OnMatrixChangedListener.java
│ │ │ ├── OnOutsidePhotoTapListener.java
│ │ │ ├── OnPhotoTapListener.java
│ │ │ ├── OnScaleChangedListener.java
│ │ │ ├── OnSingleFlingListener.java
│ │ │ ├── OnViewDragListener.java
│ │ │ ├── OnViewTapListener.java
│ │ │ ├── PhotoViewAttacher.java
│ │ │ └── Util.java
│ │ │ └── progress
│ │ │ ├── CircleProgressView.kt
│ │ │ ├── ImageProgressLoader.kt
│ │ │ └── ProgresssLoader.kt
│ └── res
│ │ ├── layout
│ │ ├── activity_larger_base.xml
│ │ └── fg_image.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── starot
│ └── larger
│ └── ExampleUnitTest.kt
├── LargerGlide
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── allens
│ │ └── largerglide
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── allens
│ │ └── largerglide
│ │ ├── GlideImageLoader.kt
│ │ ├── body
│ │ └── ProgressResponseBody.kt
│ │ ├── impl
│ │ ├── CustomRequestListener.kt
│ │ └── ProgressListener.kt
│ │ ├── interceptor
│ │ └── ProgressInterceptor.kt
│ │ └── module
│ │ └── MyGlideModule.kt
│ └── test
│ └── java
│ └── com
│ └── allens
│ └── largerglide
│ └── ExampleUnitTest.kt
├── LargerLoadVideo
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── largerloadvideo
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── largerloadvideo
│ │ │ ├── LargerDrag.kt
│ │ │ ├── LargerVideoLoad.kt
│ │ │ └── MyVideoView.java
│ └── res
│ │ ├── layout
│ │ ├── item_larger_video.xml
│ │ └── layout_jzstd_notitle.xml
│ │ └── values
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── largerloadvideo
│ └── ExampleUnitTest.kt
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── starot
│ │ └── wechat
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── starot
│ │ │ └── wechat
│ │ │ ├── MainActivity.kt
│ │ │ ├── activity
│ │ │ ├── BaseAct.kt
│ │ │ ├── HybridListAct.kt
│ │ │ ├── ImageListAct.kt
│ │ │ ├── SingleAudioAct.kt
│ │ │ ├── SingleImageAct.kt
│ │ │ └── VideoListAct.kt
│ │ │ ├── adapter
│ │ │ ├── HybridListAdapter.kt
│ │ │ ├── ImageListAdapter.kt
│ │ │ └── VideoListAdapter.kt
│ │ │ ├── bean
│ │ │ ├── ImageBean.kt
│ │ │ └── VideoBean.kt
│ │ │ └── utils
│ │ │ └── Urls.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_image_list.xml
│ │ ├── activity_image_single.xml
│ │ ├── activity_main.xml
│ │ ├── activity_single.xml
│ │ ├── item_custom_image.xml
│ │ └── item_image.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── network_security_config.xml
│ └── test
│ └── java
│ └── com
│ └── starot
│ └── wechat
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | WeChat
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | xmlns:android
33 |
34 | ^$
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | xmlns:.*
44 |
45 | ^$
46 |
47 |
48 | BY_NAME
49 |
50 |
51 |
52 |
53 |
54 |
55 | .*:id
56 |
57 | http://schemas.android.com/apk/res/android
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | .*:name
67 |
68 | http://schemas.android.com/apk/res/android
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | name
78 |
79 | ^$
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | style
89 |
90 | ^$
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | .*
100 |
101 | ^$
102 |
103 |
104 | BY_NAME
105 |
106 |
107 |
108 |
109 |
110 |
111 | .*
112 |
113 | http://schemas.android.com/apk/res/android
114 |
115 |
116 | ANDROID_ATTRIBUTE_ORDER
117 |
118 |
119 |
120 |
121 |
122 |
123 | .*
124 |
125 | .*
126 |
127 |
128 | BY_NAME
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Larger/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/Larger/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.2"
9 |
10 | defaultConfig {
11 | minSdkVersion 19
12 | targetSdkVersion 30
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: "libs", include: ["*.jar"])
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
31 | implementation 'androidx.core:core-ktx:1.3.1'
32 | implementation 'androidx.appcompat:appcompat:1.2.0'
33 | testImplementation 'junit:junit:4.13'
34 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
35 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
36 |
37 |
38 |
39 | implementation 'androidx.viewpager2:viewpager2:1.0.0'
40 | implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
41 |
42 |
43 |
44 |
45 |
46 | }
--------------------------------------------------------------------------------
/Larger/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/Larger/consumer-rules.pro
--------------------------------------------------------------------------------
/Larger/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
--------------------------------------------------------------------------------
/Larger/src/androidTest/java/com/starot/larger/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger
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.starot.larger.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/Larger/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/Larger.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger
2 |
3 | import com.starot.larger.builder.LargerBuilder
4 | import com.starot.larger.builder.config.ImageMultiConfig
5 | import com.starot.larger.builder.config.ImageSingleConfig
6 | import com.starot.larger.builder.config.VideoMultiConfig
7 | import com.starot.larger.builder.config.VideoSingleConfig
8 | import com.starot.larger.config.LargerConfig
9 | import com.starot.larger.enums.LargerEnum
10 |
11 | object Larger {
12 |
13 | var largerConfig: LargerConfig? = null
14 |
15 | fun create(): Builder {
16 | return Builder()
17 | }
18 |
19 | class Builder() {
20 |
21 |
22 | fun withImageMulti(): ImageMultiConfig {
23 | largerConfig = LargerConfig()
24 | return ImageMultiConfig(largerConfig)
25 | }
26 |
27 | fun withImageSingle(): ImageSingleConfig {
28 | largerConfig = LargerConfig()
29 | return ImageSingleConfig(largerConfig)
30 | }
31 |
32 |
33 | fun withVideoMulti(): VideoMultiConfig {
34 | largerConfig = LargerConfig()
35 | return VideoMultiConfig(largerConfig)
36 | }
37 |
38 | fun withVideoSingle(): VideoSingleConfig {
39 | largerConfig = LargerConfig()
40 | return VideoSingleConfig(largerConfig)
41 | }
42 |
43 |
44 | //列表类型
45 | fun withListType(): LargerBuilder {
46 | largerConfig = LargerConfig()
47 | return LargerBuilder(largerConfig?.apply {
48 | largerType = LargerEnum.LISTS
49 | })
50 | }
51 |
52 |
53 | }
54 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/act/CustomLargerAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.act
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.starot.larger.bean.LargerBean
5 | import com.starot.larger.enums.LargerDataEnum
6 | import com.starot.larger.fragment.ImageFg
7 | import com.starot.larger.fragment.VideoFg
8 |
9 | class CustomLargerAct : LargerAct() {
10 | override fun createFragment(position: Int, data: LargerBean): Fragment {
11 | if (data.getType() == LargerDataEnum.IMAGE) {
12 | return ImageFg().newInstance(data, position)
13 | } else if (data.getType() == LargerDataEnum.Video) {
14 | return VideoFg().newInstance(data, position)
15 | }
16 | return Fragment()
17 |
18 | }
19 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/act/LargerAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.act
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.starot.larger.Larger
6 | import com.starot.larger.R
7 | import com.starot.larger.adapter.FgPageAdapter
8 | import com.starot.larger.enums.AnimStatus
9 | import com.starot.larger.enums.BackEnum
10 | import com.starot.larger.impl.OnLargerConfigListener
11 | import com.starot.larger.impl.OnLargerType
12 | import com.starot.larger.status.LargerStatus
13 | import com.starot.larger.utils.LogUtils
14 | import com.starot.larger.utils.PageChange
15 | import com.starot.larger.utils.StatusBarTools
16 | import kotlinx.android.synthetic.main.activity_larger_base.*
17 |
18 | abstract class LargerAct : AppCompatActivity(),
19 | PageChange.PageChangeListener,
20 | OnLargerConfigListener,
21 | FgPageAdapter.OnCreateFragmentListener {
22 |
23 | //当前的index
24 | private var mCurrentIndex = 0
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | //取消动画
28 | overridePendingTransition(0, 0)
29 | super.onCreate(savedInstanceState)
30 | setContentView(R.layout.activity_larger_base)
31 | //沉寂式
32 | StatusBarTools.setStatusBar(this)
33 |
34 | //当前的index
35 | mCurrentIndex = getIndex()
36 |
37 | //添加到了lifecycle
38 | val videoLoad = Larger.largerConfig?.videoLoad
39 | val imageLoad = Larger.largerConfig?.imageLoad
40 | if (imageLoad != null) {
41 | lifecycle.addObserver(imageLoad)
42 | }
43 | if (videoLoad != null) {
44 | lifecycle.addObserver(videoLoad)
45 | }
46 | lifecycle.addObserver(LargerStatus)
47 |
48 | //设置适配器
49 | larger_viewpager.adapter =
50 | FgPageAdapter(supportFragmentManager, lifecycle, getData(), this)
51 | //不需要平滑过渡了
52 | larger_viewpager.setCurrentItem(mCurrentIndex, false)
53 | //viewpager 滑动 index 更改
54 | PageChange().register(viewPager2 = larger_viewpager, listener = this)
55 |
56 |
57 | //竖着滑动
58 | larger_viewpager.orientation = getOrientation()
59 |
60 |
61 | //viewpager2 默认没有懒加载 这里给设置 1 提高滑动时候的体验
62 | larger_viewpager.offscreenPageLimit = 1
63 |
64 | //检查状态判断是否可以滑动viewpager
65 | LargerStatus.status.observe(this, {
66 | LogUtils.i("动画状态 $it")
67 | when (it) {
68 | AnimStatus.ENTER_START, AnimStatus.EXIT_START, AnimStatus.DRAG_START, AnimStatus.SCALE_START -> {
69 | larger_viewpager.isUserInputEnabled = false //true:滑动,false:禁止滑动
70 | LogUtils.i("viewPager--------禁止滑动")
71 | }
72 | AnimStatus.ENTER_END, AnimStatus.SCALE_END -> {
73 | larger_viewpager.isUserInputEnabled = true //true:滑动,false:禁止滑动
74 | LogUtils.i("viewPager-------滑动")
75 | }
76 | AnimStatus.EXIT_END -> {
77 | LogUtils.i("viewPager-------滑动")
78 | larger_viewpager.isUserInputEnabled = true //true:滑动,false:禁止滑动
79 | finish()
80 | overridePendingTransition(0, 0)
81 | }
82 | }
83 | })
84 |
85 | }
86 |
87 | //数据源
88 | private fun getData(): List? {
89 | return Larger.largerConfig?.data as List?
90 | }
91 |
92 |
93 | //当前的图片index
94 | private fun getIndex(): Int {
95 | return Larger.largerConfig?.position ?: 0
96 | }
97 |
98 |
99 | //viewpager 滑动监听
100 | override fun onPageChange(pos: Int) {
101 | mCurrentIndex = pos
102 | LogUtils.i("viewPager change:$pos")
103 | LargerStatus.pos.value = pos
104 | }
105 |
106 |
107 | override fun onDestroy() {
108 | super.onDestroy()
109 | //清理资源
110 | Larger.largerConfig = null
111 | }
112 |
113 | override fun onBackPressed() {
114 | if (LargerStatus.back.value == BackEnum.BACK_NOME) {
115 | LargerStatus.back.value = BackEnum.BACK_PREPARE
116 | }
117 | }
118 |
119 |
120 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/adapter/FgPageAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.adapter
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentManager
5 | import androidx.lifecycle.Lifecycle
6 | import androidx.viewpager2.adapter.FragmentStateAdapter;
7 |
8 | class FgPageAdapter(
9 | fg: FragmentManager,
10 | lifecycle: Lifecycle,
11 | private val data: List?,
12 | private val listener: OnCreateFragmentListener
13 | ) :
14 | FragmentStateAdapter(fg, lifecycle) {
15 | override fun getItemCount(): Int {
16 | return data?.size ?: 0
17 | }
18 |
19 | override fun createFragment(position: Int): Fragment {
20 | if(data?.get(position) == null){
21 | return Fragment()
22 | }
23 | return listener.createFragment(position, data[position])
24 | }
25 |
26 |
27 | interface OnCreateFragmentListener {
28 | fun createFragment(position: Int, data: T): Fragment
29 | }
30 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/AnimBgHelper.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim
2 |
3 | import android.animation.ValueAnimator
4 | import android.graphics.Color
5 | import android.view.View
6 | import com.starot.larger.impl.OnLargerConfigListener
7 | import com.starot.larger.utils.ColorTool
8 |
9 | object AnimBgHelper : OnLargerConfigListener {
10 | //修改进入的时候背景 渐变 黑色
11 | fun enter(
12 | parent: View,
13 | originalScale: Float,
14 | duration: Long
15 | ) {
16 | val valueAnimator = ValueAnimator()
17 | valueAnimator.duration = duration
18 | valueAnimator.setFloatValues(originalScale, 1f)
19 | valueAnimator.addUpdateListener { animation ->
20 | parent.setBackgroundColor(
21 | ColorTool.getColorWithAlpha(getBackGroundColor(), (animation.animatedValue as Float))
22 | )
23 | }
24 | valueAnimator.start()
25 | }
26 |
27 |
28 | //修改退出的时候背景 渐变 黑色
29 | fun exit(
30 | parent: View,
31 | start: Float,
32 | duration: Long
33 | ) {
34 | startWithRange(start, 0f, parent, duration)
35 | }
36 |
37 |
38 | private fun startWithRange(
39 | start: Float,
40 | end: Float,
41 | parent: View,
42 | duration: Long
43 | ) {
44 | val valueAnimator = ValueAnimator()
45 | valueAnimator.duration = duration
46 | valueAnimator.setFloatValues(start, end)
47 | valueAnimator.addUpdateListener { animation ->
48 | parent.setBackgroundColor(
49 | ColorTool.getColorWithAlpha(getBackGroundColor(), (animation.animatedValue as Float))
50 | )
51 | }
52 | valueAnimator.start()
53 | }
54 |
55 |
56 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/AnimDragHelper.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim
2 |
3 | import android.os.Build
4 | import android.transition.*
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.view.animation.DecelerateInterpolator
8 | import android.widget.ImageView
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.starot.larger.anim.impl.OnAnimatorIntercept
11 | import com.starot.larger.anim.impl.OnAnimatorListener
12 | import com.starot.larger.enums.AnimType
13 | import com.starot.larger.impl.OnImageLoadReadyListener
14 | import com.starot.larger.utils.LogUtils
15 |
16 | object AnimDragHelper : OnAnimatorIntercept {
17 |
18 | var currentScale: Float = 0f
19 |
20 | private var thumbnailView: View? = null
21 |
22 | // override fun beforeTransition(
23 | // type: AnimType,
24 | // itemView: View,
25 | // fullView: View,
26 | // thumbnailView: View?,
27 | // listener: OnAnimatorListener
28 | // ) {
29 | // this.thumbnailView = thumbnailView
30 | // if (thumbnailView == null) {
31 | // LogUtils.i("beforeTransition thumbnailView is null")
32 | // return
33 | // }
34 | // listener.onTranslatorBefore(type, fullView, thumbnailView)
35 | //
36 | // }
37 |
38 | override fun beforeTransition(
39 | type: AnimType,
40 | itemView: View,
41 | fullView: View,
42 | thumbnailView: View?,
43 | listener: OnAnimatorListener,
44 | onImageLoadReadyListener: OnImageLoadReadyListener?
45 | ) {
46 | this.thumbnailView = thumbnailView
47 | if (thumbnailView == null) {
48 | LogUtils.i("beforeTransition thumbnailView is null")
49 | return
50 | }
51 | listener.onTranslatorBefore(type, fullView, thumbnailView)
52 | }
53 |
54 |
55 | override fun startTransition(
56 | type: AnimType,
57 | fullView: View,
58 | thumbnailView: View?,
59 | listener: OnAnimatorListener
60 | ) {
61 | if (thumbnailView == null) {
62 | LogUtils.i("startTransition thumbnailView is null")
63 | return
64 | }
65 | listener.onTranslatorStart(type, fullView, thumbnailView)
66 | fullView.translationX = (0f)
67 | fullView.translationY = (0f)
68 | fullView.scaleX = (1f)
69 | fullView.scaleY = (1f)
70 | }
71 |
72 | override fun transitionSet(durationTime: Long): Transition {
73 | return TransitionSet().apply {
74 | if (thumbnailView == null) {
75 | addTransition(AutoTransition())
76 | } else {
77 | addTransition(ChangeBounds())
78 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
79 | addTransition(ChangeImageTransform())
80 | addTransition(ChangeTransform())
81 | }
82 | }
83 | duration = durationTime
84 | interpolator = DecelerateInterpolator()
85 | }
86 | }
87 |
88 |
89 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/AnimEnterHelper.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim
2 |
3 | import android.os.Build
4 | import android.transition.*
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.view.animation.DecelerateInterpolator
8 | import com.starot.larger.anim.impl.OnAnimatorIntercept
9 | import com.starot.larger.anim.impl.OnAnimatorListener
10 | import com.starot.larger.enums.AnimType
11 | import com.starot.larger.impl.OnImageLoadReadyListener
12 | import com.starot.larger.utils.LogUtils
13 |
14 | object AnimEnterHelper : OnAnimatorIntercept {
15 |
16 |
17 | override fun start(
18 | type: AnimType,
19 | duration: Long,
20 | fullView: View,
21 | thumbnailView: View?,
22 | listener: OnAnimatorListener
23 | ) {
24 | beforeTransition(
25 | type,
26 | fullView,
27 | fullView,
28 | thumbnailView,
29 | listener,
30 | object : OnImageLoadReadyListener {
31 | override fun onLoadFailed() {
32 |
33 | }
34 |
35 | override fun onReady() {
36 | fullView.post {
37 | TransitionManager.beginDelayedTransition(
38 | fullView.parent as ViewGroup,
39 | getTransition(type, duration, listener)
40 | )
41 | startTransition(type, fullView, thumbnailView, listener)
42 | }
43 | }
44 | })
45 |
46 |
47 | }
48 |
49 | // override fun beforeTransition(
50 | // type: AnimType,
51 | // itemView: View,
52 | // fullView: View,
53 | // thumbnailView: View?,
54 | // listener: OnAnimatorListener
55 | // ) {
56 | // if (thumbnailView == null) {
57 | // LogUtils.i("beforeTransition thumbnailView is null")
58 | // return
59 | // }
60 | // listener.onTranslatorBefore(type, fullView, thumbnailView)
61 | // fullView.layoutParams = fullView.layoutParams.apply {
62 | // width = thumbnailView.width
63 | // height = thumbnailView.height
64 | // AnimParentHelper.parentAnim(this, thumbnailView, fullView)
65 | // }
66 | //
67 | // }
68 |
69 | override fun beforeTransition(
70 | type: AnimType,
71 | itemView: View,
72 | fullView: View,
73 | thumbnailView: View?,
74 | listener: OnAnimatorListener,
75 | onImageLoadReadyListener: OnImageLoadReadyListener?
76 | ) {
77 | if (thumbnailView == null) {
78 | LogUtils.i("beforeTransition thumbnailView is null")
79 | return
80 | }
81 | listener.onTranslatorBefore(type, fullView, thumbnailView, onImageLoadReadyListener)
82 | fullView.layoutParams = fullView.layoutParams.apply {
83 | width = thumbnailView.width
84 | height = thumbnailView.height
85 | AnimParentHelper.parentAnim(this, thumbnailView, fullView)
86 | }
87 | }
88 |
89 | override fun startTransition(
90 | type: AnimType,
91 | fullView: View,
92 | thumbnailView: View?,
93 | listener: OnAnimatorListener
94 | ) {
95 | if (thumbnailView == null) {
96 | LogUtils.i("startTransition thumbnailView is null")
97 | return
98 | }
99 | listener.onTranslatorStart(type, fullView, thumbnailView)
100 | fullView.layoutParams = fullView.layoutParams.apply {
101 | width = ViewGroup.LayoutParams.MATCH_PARENT
102 | height = ViewGroup.LayoutParams.MATCH_PARENT
103 | if (this is ViewGroup.MarginLayoutParams) {
104 | marginStart = 0
105 | topMargin = 0
106 | }
107 | }
108 | }
109 |
110 | override fun transitionSet(durationTime: Long): Transition {
111 | return TransitionSet().apply {
112 | addTransition(ChangeBounds())
113 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
114 | addTransition(ChangeImageTransform())
115 | }
116 | duration = durationTime
117 | interpolator = DecelerateInterpolator()
118 | }
119 | }
120 |
121 |
122 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/AnimExitHelper.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim
2 |
3 | import android.os.Build
4 | import android.transition.*
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.view.animation.DecelerateInterpolator
8 | import android.widget.ImageView
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.starot.larger.anim.impl.OnAnimatorIntercept
11 | import com.starot.larger.anim.impl.OnAnimatorListener
12 | import com.starot.larger.enums.AnimType
13 | import com.starot.larger.impl.OnImageLoadReadyListener
14 | import com.starot.larger.utils.LogUtils
15 |
16 | object AnimExitHelper : OnAnimatorIntercept {
17 |
18 | private var thumbnailView: View? = null
19 |
20 | // override fun beforeTransition(
21 | // type: AnimType,
22 | // itemView: View,
23 | // fullView: View,
24 | // thumbnailView: View?,
25 | // listener: OnAnimatorListener
26 | // ) {
27 | // this.thumbnailView = thumbnailView
28 | // if (thumbnailView == null) {
29 | // LogUtils.i("beforeTransition thumbnailView is null")
30 | // return
31 | // }
32 | // listener.onTranslatorBefore(type, fullView, thumbnailView)
33 | //
34 | // }
35 |
36 | override fun beforeTransition(
37 | type: AnimType,
38 | itemView: View,
39 | fullView: View,
40 | thumbnailView: View?,
41 | listener: OnAnimatorListener,
42 | onImageLoadReadyListener: OnImageLoadReadyListener?
43 | ) {
44 | this.thumbnailView = thumbnailView
45 | if (thumbnailView == null) {
46 | LogUtils.i("beforeTransition thumbnailView is null")
47 | return
48 | }
49 | listener.onTranslatorBefore(type, fullView, thumbnailView)
50 | }
51 |
52 |
53 | override fun startTransition(
54 | type: AnimType,
55 | fullView: View,
56 | thumbnailView: View?,
57 | listener: OnAnimatorListener
58 | ) {
59 | if (thumbnailView == null) {
60 | LogUtils.i("startTransition thumbnailView is null")
61 | fullView.visibility = View.GONE
62 | return
63 | }
64 | listener.onTranslatorStart(type, fullView, thumbnailView)
65 | fullView.translationX = 0f
66 | fullView.translationY = 0f
67 | fullView.scaleX = 1f
68 | fullView.scaleY = 1f
69 | fullView.layoutParams = fullView.layoutParams.apply {
70 | width = thumbnailView.width
71 | height = thumbnailView.height
72 | AnimParentHelper.parentAnim(this, thumbnailView, fullView)
73 | }
74 | }
75 |
76 | override fun transitionSet(durationTime: Long): Transition {
77 | return TransitionSet().apply {
78 | if (thumbnailView == null) {
79 | addTransition(AutoTransition())
80 | } else {
81 | addTransition(ChangeBounds())
82 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
83 | addTransition(ChangeImageTransform())
84 | addTransition(ChangeTransform())
85 | }
86 | }
87 | duration = durationTime
88 | interpolator = DecelerateInterpolator()
89 | }
90 | }
91 |
92 |
93 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/AnimParentHelper.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim
2 |
3 | import android.view.View
4 | import android.view.ViewGroup
5 | import android.widget.ImageView
6 | import androidx.constraintlayout.widget.ConstraintLayout
7 | import androidx.constraintlayout.widget.ConstraintSet
8 |
9 | object AnimParentHelper {
10 |
11 | fun parentAnim(
12 | parent: ViewGroup.LayoutParams,
13 | thumbnailView: View,
14 | fullView: View
15 | ) {
16 | val location = AnimEnterHelper.getLocationOnScreen(thumbnailView)
17 | when (fullView.parent) {
18 | is ConstraintLayout -> {
19 | val constraintSet = ConstraintSet().apply {
20 | clone(fullView.parent as ConstraintLayout)
21 | clear(fullView.id, ConstraintSet.START)
22 | clear(fullView.id, ConstraintSet.TOP)
23 | clear(fullView.id, ConstraintSet.BOTTOM)
24 | clear(fullView.id, ConstraintSet.RIGHT)
25 | //重新建立约束
26 | connect(
27 | fullView.id, ConstraintSet.TOP, ConstraintSet.PARENT_ID,
28 | ConstraintSet.TOP, location[1]
29 | )
30 | connect(
31 | fullView.id, ConstraintSet.START, ConstraintSet.PARENT_ID,
32 | ConstraintSet.START, location[0]
33 | )
34 | }
35 | constraintSet.applyTo(fullView.parent as ConstraintLayout)
36 | }
37 | else -> {
38 | if (parent is ViewGroup.MarginLayoutParams) {
39 | parent.marginStart = location[0]
40 | parent.topMargin = location[1]
41 | }
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/impl/AnimListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim.impl
2 |
3 | import android.view.View
4 | import com.starot.larger.anim.AnimBgHelper
5 | import com.starot.larger.anim.AnimDragHelper
6 | import com.starot.larger.anim.AnimEnterHelper
7 | import com.starot.larger.anim.AnimExitHelper
8 | import com.starot.larger.enums.AnimType
9 | import com.starot.larger.utils.LogUtils
10 |
11 | //动画的逻辑
12 | interface AnimListener : OnAnimatorListener, OnDragAnimListener {
13 |
14 |
15 | fun enterAnimStart(
16 | parentView: View,
17 | duration: Long,
18 | fullView: View?,
19 | thumbnailView: View?
20 | ) {
21 | LogUtils.i("入场动画 start")
22 | if (fullView == null) {
23 | return
24 | }
25 | AnimEnterHelper.start(
26 | AnimType.ENTER,
27 | duration,
28 | fullView,
29 | thumbnailView,
30 | this,
31 | )
32 | //背景颜色变化
33 | AnimBgHelper.enter(parentView, 0f, duration)
34 | }
35 |
36 | fun dragResumeAnimStart(
37 | start: Float,
38 | parentView: View,
39 | duration: Long,
40 | fullView: View?,
41 | thumbnailView: View?
42 | ) {
43 | LogUtils.i("drag动画 start")
44 | if (fullView == null) {
45 | return
46 | }
47 | AnimDragHelper.start(
48 | AnimType.DRAG_RESUME,
49 | duration,
50 | fullView,
51 | thumbnailView,
52 | this,
53 | )
54 | //背景颜色变化
55 | AnimBgHelper.enter(parentView, start, duration)
56 | }
57 |
58 |
59 | fun exitAnimStart(
60 | parentView: View,
61 | duration: Long,
62 | fullView: View?,
63 | thumbnailView: View?,
64 | ) {
65 | exitAnimStart(AnimType.EXIT, 1.0f, parentView, duration, fullView, thumbnailView)
66 | }
67 |
68 | fun exitAnimStart(
69 | type: AnimType,
70 | start: Float,
71 | parentView: View,
72 | duration: Long,
73 | fullView: View?,
74 | thumbnailView: View?,
75 | ) {
76 | LogUtils.i("退场动画 start")
77 | if (fullView == null) {
78 | LogUtils.i("退场动画 start fullView == null")
79 | return
80 | }
81 | AnimExitHelper.start(
82 | type,
83 | duration,
84 | fullView,
85 | thumbnailView,
86 | this
87 | )
88 | //背景颜色变化
89 | AnimBgHelper.exit(parentView, start, duration)
90 | }
91 |
92 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/impl/OnAnimatorIntercept.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim.impl
2 |
3 |
4 | import android.transition.Transition
5 | import android.transition.TransitionManager
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import com.starot.larger.enums.AnimType
9 | import com.starot.larger.impl.OnImageLoadReadyListener
10 |
11 |
12 | interface OnAnimatorListener {
13 |
14 |
15 | //变化开始之前
16 | fun onTranslatorBefore(
17 | type: AnimType,
18 | fullView: View,
19 | thumbnailView: View,
20 | onImageLoadReadyListener: OnImageLoadReadyListener? = null
21 | )
22 |
23 | // fun onTranslatorBefore(
24 | // type: AnimType,
25 | // fullView: View,
26 | // thumbnailView: View
27 | // )
28 |
29 | //开始变化
30 | fun onTranslatorStart(
31 | type: AnimType,
32 | fullView: View,
33 | thumbnailView: View
34 | )
35 |
36 | //动画开始
37 | fun onAnimatorStart(type: AnimType)
38 |
39 | //动画结束
40 | fun onAnimatorEnd(type: AnimType)
41 |
42 | //动画取消
43 | fun onAnimatorCancel(type: AnimType)
44 |
45 |
46 | }
47 |
48 |
49 | interface OnAnimatorIntercept {
50 |
51 |
52 | fun start(
53 | type: AnimType,
54 | duration: Long,
55 | fullView: View,
56 | thumbnailView: View?,
57 | listener: OnAnimatorListener
58 | ) {
59 |
60 | beforeTransition(type, fullView, fullView, thumbnailView, listener)
61 |
62 | fullView.post {
63 | TransitionManager.beginDelayedTransition(
64 | fullView.parent as ViewGroup,
65 | getTransition(type, duration, listener)
66 | )
67 | startTransition(type, fullView, thumbnailView, listener)
68 | }
69 | }
70 |
71 |
72 | fun getTransition(
73 | type: AnimType,
74 | duration: Long,
75 | listener: OnAnimatorListener
76 | ): Transition {
77 | return transitionSet(duration).apply {
78 | addListener(object : Transition.TransitionListener {
79 | override fun onTransitionEnd(transition: Transition?) {
80 | listener.onAnimatorEnd(type)
81 | }
82 |
83 | override fun onTransitionResume(transition: Transition?) {
84 | }
85 |
86 | override fun onTransitionPause(transition: Transition?) {
87 | }
88 |
89 | override fun onTransitionCancel(transition: Transition?) {
90 | listener.onAnimatorCancel(type)
91 | }
92 |
93 | override fun onTransitionStart(transition: Transition?) {
94 | listener.onAnimatorStart(type)
95 | }
96 | })
97 | }
98 | }
99 |
100 | // fun beforeTransition(
101 | // type: AnimType,
102 | // itemView: View,
103 | // fullView: View,
104 | // thumbnailView: View?,
105 | // listener: OnAnimatorListener
106 | // )
107 |
108 | fun beforeTransition(
109 | type: AnimType,
110 | itemView: View,
111 | fullView: View,
112 | thumbnailView: View?,
113 | listener: OnAnimatorListener,
114 | onImageLoadReadyListener: OnImageLoadReadyListener? = null
115 | )
116 |
117 |
118 | fun startTransition(
119 | type: AnimType,
120 | fullView: View,
121 | thumbnailView: View?,
122 | listener: OnAnimatorListener
123 | )
124 |
125 | fun transitionSet(durationTime: Long): Transition
126 |
127 |
128 | fun getLocationOnScreen(thumbnailView: View): IntArray {
129 | val location = IntArray(2)
130 | thumbnailView.getLocationOnScreen(location)
131 | return location
132 | }
133 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/anim/impl/OnDragAnimListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.anim.impl
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.view.View
6 | import com.starot.larger.Larger
7 | import com.starot.larger.anim.AnimBgHelper
8 | import com.starot.larger.anim.AnimDragHelper
9 | import com.starot.larger.anim.AnimExitHelper
10 | import com.starot.larger.enums.AnimType
11 | import com.starot.larger.impl.OnLargerConfigListener
12 | import com.starot.larger.utils.ColorTool
13 | import com.starot.larger.utils.LogUtils
14 | import kotlin.math.abs
15 | import kotlin.math.max
16 | import kotlin.math.min
17 |
18 | interface OnDragAnimListener : OnLargerConfigListener {
19 |
20 | //开始移动
21 | fun startDrag(parent: View, view: View?, x: Float, y: Float) {
22 | if (view == null) {
23 | return
24 | }
25 |
26 | //图片的缩放 和位置变化
27 | val fixedOffsetY = y - 0
28 | val fraction = abs(max(-1f, min(1f, fixedOffsetY / view.height)))
29 | val fakeScale = 1 - min(0.4f, fraction)
30 | view.scaleX = fakeScale
31 | view.scaleY = fakeScale
32 | view.translationY = fixedOffsetY
33 | view.translationX = x
34 |
35 |
36 | //如果将upCanMove 设置成true 就给他改变颜色
37 | val upCanMove = Larger.largerConfig?.upCanMove
38 | if (upCanMove == null || upCanMove == false) {
39 | //已经向上了 就黑色背景 不需要改动了
40 | if (y > 0) {
41 | //背景的颜色 变化
42 | val scale: Float = abs(y) / getWindowHeight(view.context)
43 | AnimDragHelper.currentScale = 1 - scale
44 | parent.setBackgroundColor(
45 | ColorTool.getColorWithAlpha(getBackGroundColor(), 1 - scale)
46 | )
47 | }
48 | } else {
49 | val scale: Float = abs(y) / getWindowHeight(view.context)
50 | AnimDragHelper.currentScale = 1 - scale
51 | parent.setBackgroundColor(
52 | ColorTool.getColorWithAlpha(getBackGroundColor(), 1 - scale)
53 | )
54 | }
55 |
56 | }
57 |
58 | fun endDrag(view: View?) {
59 | if (view == null) {
60 | LogUtils.i("endDrag view is null")
61 | return
62 | }
63 | if (abs(view.translationY) < view.height * 0.4f) {
64 | onDragResume(AnimDragHelper.currentScale, view)
65 | } else {
66 | onDragExit(AnimDragHelper.currentScale, view)
67 |
68 | }
69 | }
70 |
71 | fun onDragExit(scale: Float, fullView: View)
72 |
73 | fun onDragResume(scale: Float, fullView: View)
74 |
75 |
76 | //手机屏幕 高度
77 | fun getWindowHeight(context: Context): Int {
78 | return context.applicationContext.resources.displayMetrics.heightPixels
79 | }
80 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/bean/LargerBean.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.bean
2 |
3 | import com.starot.larger.enums.LargerDataEnum
4 | import com.starot.larger.impl.OnLargerType
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | abstract class LargerBean : OnLargerType {
8 | var thumbnailsUrl: String? = null
9 | var fullUrl: String? = null
10 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/LargerBuilder.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.widget.ImageView
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.starot.larger.Larger
8 | import com.starot.larger.act.CustomLargerAct
9 | import com.starot.larger.config.LargerConfig
10 | import com.starot.larger.enums.Orientation
11 | import com.starot.larger.impl.*
12 | import com.starot.larger.view.progress.CircleProgressView
13 | import com.starot.larger.view.progress.ImageProgressLoader
14 |
15 | class LargerBuilder(private val listConfig: LargerConfig?) {
16 |
17 | //pos
18 | fun setIndex(pos: Int): LargerBuilder {
19 | listConfig?.position = pos
20 | return this
21 | }
22 |
23 | //设置持续时间
24 | fun setDuration(duration: Long): LargerBuilder {
25 | listConfig?.duration = duration
26 | return this
27 | }
28 |
29 | //是否自动加载
30 | fun setAutomatic(automatic: Boolean): LargerBuilder {
31 | listConfig?.automatic = automatic
32 | return this
33 | }
34 |
35 | //withSingle 模式下 设置imageView
36 | fun setImagesWithSingle(images: List): LargerBuilder {
37 | listConfig?.images = images
38 | return this
39 | }
40 |
41 | //设置数据源
42 | fun setData(data: List): LargerBuilder {
43 | listConfig?.data = data
44 | return this
45 | }
46 |
47 |
48 | //开始
49 | fun start(context: Context) {
50 | val intent = Intent(context, CustomLargerAct::class.java)
51 | context.startActivity(intent)
52 | }
53 |
54 | //跳转到自定义的act
55 | fun start(context: Context, cls: Class<*>) {
56 | val intent = Intent(context, cls)
57 | context.startActivity(intent)
58 | }
59 |
60 |
61 | //列表的情况需要将 recyclerview 也传入
62 | fun setRecyclerView(recyclerView: RecyclerView): LargerBuilder {
63 | listConfig?.recyclerView = recyclerView
64 | return this
65 | }
66 |
67 |
68 | //是否直接向上就能够拖动,微信直接向上不可以拖动,这里默认false
69 | fun setUpCanMove(canMove: Boolean): LargerBuilder {
70 | listConfig?.upCanMove = canMove
71 | return this
72 | }
73 |
74 | //是否自动加载下一页大图,默认不自动加载下一页
75 | fun setLoadNextFragment(auto:Boolean): LargerBuilder {
76 | listConfig?.loadNextFragment = auto
77 | return this
78 | }
79 |
80 | //是否打印日志
81 | fun setDebug(debug: Boolean): LargerBuilder {
82 | listConfig?.debug = debug
83 | return this
84 | }
85 |
86 | //设置背景颜色
87 | fun setBackgroundColor(color: Int): LargerBuilder {
88 | listConfig?.backgroundColor = color
89 | return this
90 | }
91 |
92 | //设置图片加载器
93 | fun setImageLoad(imageLoad: OnImageLoadListener): LargerBuilder {
94 | listConfig?.imageLoad = imageLoad
95 | return this
96 | }
97 |
98 | //设置加载的进度
99 | fun setProgressType(progressType: ImageProgressLoader.ProgressType): LargerBuilder {
100 | listConfig?.progressType = progressType
101 | return this
102 | }
103 |
104 | //设置是否显示加载框
105 | fun setProgressLoaderUse(use: Boolean): LargerBuilder {
106 | listConfig?.progressLoaderUse = use
107 | return this
108 | }
109 |
110 | //设置加载方向
111 | fun setOrientation(orientation: Orientation): LargerBuilder {
112 | listConfig?.orientation = orientation
113 | return this
114 | }
115 |
116 | //设置视屏加载器
117 | fun setVideoLoad(videoLoad: OnVideoLoadListener): LargerBuilder {
118 | listConfig?.videoLoad = videoLoad
119 | return this
120 | }
121 |
122 | //自定义布局
123 | fun setCustomListener(
124 | layoutId: Int,
125 | fullViewId: Int,
126 | listener: OnCustomImageLoadListener? = null
127 | ): LargerBuilder {
128 | listConfig?.layoutId = layoutId
129 | listConfig?.fullViewId = fullViewId
130 | listConfig?.customImageLoadListener = listener
131 | return this
132 | }
133 |
134 | fun setCustomListener(
135 | layoutId: Int,
136 | fullViewId: Int,
137 | progressId: Int,
138 | listener: OnCustomImageLoadListener? = null
139 | ): LargerBuilder {
140 | listConfig?.layoutId = layoutId
141 | listConfig?.progressId = progressId
142 | listConfig?.fullViewId = fullViewId
143 | listConfig?.customImageLoadListener = listener
144 | return this
145 | }
146 |
147 | //最大的比例
148 | fun setMaxScale(maxScale: Float): LargerBuilder {
149 | listConfig?.maxScale = maxScale
150 | return this
151 | }
152 |
153 | //设置双击中间的比例 可以和 max 相同 但是不能大于max
154 | fun setMediumScale(mediumScale: Float): LargerBuilder {
155 | listConfig?.mediumScale = mediumScale
156 | return this
157 | }
158 |
159 |
160 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/config/ImageMultiConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.config
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import androidx.recyclerview.widget.RecyclerView
6 | import com.starot.larger.act.CustomLargerAct
7 | import com.starot.larger.act.LargerAct
8 | import com.starot.larger.builder.impl.ImageConfig
9 | import com.starot.larger.builder.impl.MultiConfig
10 | import com.starot.larger.config.LargerConfig
11 | import com.starot.larger.enums.LargerEnum
12 | import com.starot.larger.enums.Orientation
13 | import com.starot.larger.impl.OnCustomImageLoadListener
14 | import com.starot.larger.impl.OnImageLoadListener
15 | import com.starot.larger.impl.OnLargerType
16 | import com.starot.larger.view.progress.ImageProgressLoader
17 |
18 | class ImageMultiConfig(private val largerConfig: LargerConfig?) :
19 | MultiConfig, ImageConfig {
20 |
21 | init {
22 | largerConfig?.largerType = LargerEnum.LISTS
23 | }
24 |
25 | override fun setRecyclerView(recyclerView: RecyclerView): ImageMultiConfig {
26 | largerConfig?.recyclerView = recyclerView
27 | return this
28 | }
29 |
30 | override fun setData(data: List): ImageMultiConfig {
31 | largerConfig?.data = data
32 | return this
33 | }
34 |
35 | override fun setAutomatic(automatic: Boolean): ImageMultiConfig {
36 | largerConfig?.automatic = automatic
37 | return this
38 | }
39 |
40 | override fun setMaxScale(maxScale: Float): ImageMultiConfig {
41 | largerConfig?.maxScale = maxScale
42 | return this
43 | }
44 |
45 | override fun setMediumScale(mediumScale: Float): ImageMultiConfig {
46 | largerConfig?.mediumScale = mediumScale
47 | return this
48 | }
49 |
50 | override fun setImageLoad(imageLoad: OnImageLoadListener): ImageMultiConfig {
51 | largerConfig?.imageLoad = imageLoad
52 | return this
53 | }
54 |
55 | override fun setProgressType(progressType: ImageProgressLoader.ProgressType): ImageMultiConfig {
56 | largerConfig?.progressType = progressType
57 | return this
58 | }
59 |
60 | override fun setProgressLoaderUse(use: Boolean): ImageMultiConfig {
61 | largerConfig?.progressLoaderUse = use
62 | return this
63 | }
64 |
65 | override fun setCustomListener(
66 | layoutId: Int,
67 | fullViewId: Int,
68 | listener: OnCustomImageLoadListener?
69 | ): ImageMultiConfig {
70 | largerConfig?.layoutId = layoutId
71 | largerConfig?.fullViewId = fullViewId
72 | largerConfig?.customImageLoadListener = listener
73 | return this
74 | }
75 |
76 | override fun setCustomListener(
77 | layoutId: Int,
78 | fullViewId: Int,
79 | progressId: Int,
80 | listener: OnCustomImageLoadListener?
81 | ): ImageMultiConfig {
82 | largerConfig?.progressId = progressId
83 | largerConfig?.layoutId = layoutId
84 | largerConfig?.fullViewId = fullViewId
85 | largerConfig?.customImageLoadListener = listener
86 | return this
87 | }
88 |
89 | override fun setUpCanMove(canMove: Boolean): ImageMultiConfig {
90 | largerConfig?.upCanMove = canMove
91 | return this
92 | }
93 |
94 | override fun setLoadNextFragment(auto: Boolean): ImageMultiConfig {
95 | largerConfig?.loadNextFragment = auto
96 | return this
97 | }
98 |
99 | override fun setDebug(debug: Boolean): ImageMultiConfig {
100 | largerConfig?.debug = debug
101 | return this
102 | }
103 |
104 | override fun setBackgroundColor(color: Int): ImageMultiConfig {
105 | largerConfig?.backgroundColor = color
106 | return this
107 | }
108 |
109 | override fun setOrientation(orientation: Orientation): ImageMultiConfig {
110 | largerConfig?.orientation = orientation
111 | return this
112 | }
113 |
114 | override fun setIndex(pos: Int): ImageMultiConfig {
115 | largerConfig?.position = pos
116 | return this
117 | }
118 |
119 | override fun setDuration(duration: Long): ImageMultiConfig {
120 | largerConfig?.duration = duration
121 | return this
122 | }
123 |
124 |
125 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/config/ImageSingleConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.config
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.widget.ImageView
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.starot.larger.act.CustomLargerAct
8 | import com.starot.larger.act.LargerAct
9 | import com.starot.larger.builder.impl.ImageConfig
10 | import com.starot.larger.builder.impl.MultiConfig
11 | import com.starot.larger.builder.impl.SingleConfig
12 | import com.starot.larger.config.LargerConfig
13 | import com.starot.larger.enums.LargerEnum
14 | import com.starot.larger.enums.Orientation
15 | import com.starot.larger.impl.OnCustomImageLoadListener
16 | import com.starot.larger.impl.OnImageLoadListener
17 | import com.starot.larger.impl.OnLargerType
18 | import com.starot.larger.view.progress.ImageProgressLoader
19 |
20 | class ImageSingleConfig(private val largerConfig: LargerConfig?) :
21 | SingleConfig, ImageConfig {
22 |
23 | init {
24 | largerConfig?.largerType = LargerEnum.SINGLES
25 | }
26 |
27 | override fun setAutomatic(automatic: Boolean): ImageSingleConfig {
28 | largerConfig?.automatic = automatic
29 | return this
30 | }
31 |
32 | override fun setMaxScale(maxScale: Float): ImageSingleConfig {
33 | largerConfig?.maxScale = maxScale
34 | return this
35 | }
36 |
37 | override fun setMediumScale(mediumScale: Float): ImageSingleConfig {
38 | largerConfig?.mediumScale = mediumScale
39 | return this
40 | }
41 |
42 | override fun setImageLoad(imageLoad: OnImageLoadListener): ImageSingleConfig {
43 | largerConfig?.imageLoad = imageLoad
44 | return this
45 | }
46 |
47 | override fun setProgressType(progressType: ImageProgressLoader.ProgressType): ImageSingleConfig {
48 | largerConfig?.progressType = progressType
49 | return this
50 | }
51 |
52 | override fun setProgressLoaderUse(use: Boolean): ImageSingleConfig {
53 | largerConfig?.progressLoaderUse = use
54 | return this
55 | }
56 |
57 | override fun setCustomListener(
58 | layoutId: Int,
59 | fullViewId: Int,
60 | listener: OnCustomImageLoadListener?
61 | ): ImageSingleConfig {
62 | largerConfig?.layoutId = layoutId
63 | largerConfig?.fullViewId = fullViewId
64 | largerConfig?.customImageLoadListener = listener
65 | return this
66 | }
67 |
68 | override fun setCustomListener(
69 | layoutId: Int,
70 | fullViewId: Int,
71 | progressId: Int,
72 | listener: OnCustomImageLoadListener?
73 | ): ImageSingleConfig {
74 | largerConfig?.progressId = progressId
75 | largerConfig?.layoutId = layoutId
76 | largerConfig?.fullViewId = fullViewId
77 | largerConfig?.customImageLoadListener = listener
78 | return this
79 | }
80 |
81 | override fun setUpCanMove(canMove: Boolean): ImageSingleConfig {
82 | largerConfig?.upCanMove = canMove
83 | return this
84 | }
85 |
86 | override fun setLoadNextFragment(auto: Boolean): ImageSingleConfig {
87 | largerConfig?.loadNextFragment = auto
88 | return this
89 | }
90 |
91 | override fun setDebug(debug: Boolean): ImageSingleConfig {
92 | largerConfig?.debug = debug
93 | return this
94 | }
95 |
96 | override fun setBackgroundColor(color: Int): ImageSingleConfig {
97 | largerConfig?.backgroundColor = color
98 | return this
99 | }
100 |
101 | override fun setOrientation(orientation: Orientation): ImageSingleConfig {
102 | largerConfig?.orientation = orientation
103 | return this
104 | }
105 |
106 |
107 | override fun setDuration(duration: Long): ImageSingleConfig {
108 | largerConfig?.duration = duration
109 | return this
110 | }
111 |
112 | override fun setImage(image: ImageView): ImageSingleConfig {
113 | largerConfig?.images = arrayListOf(image)
114 | return this
115 | }
116 |
117 | override fun setData(data: OnLargerType): ImageSingleConfig {
118 | largerConfig?.data = arrayListOf(data)
119 | return this
120 | }
121 |
122 |
123 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/config/VideoMultiConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.config
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import androidx.recyclerview.widget.RecyclerView
6 | import com.starot.larger.act.CustomLargerAct
7 | import com.starot.larger.act.LargerAct
8 | import com.starot.larger.builder.impl.ImageConfig
9 | import com.starot.larger.builder.impl.MultiConfig
10 | import com.starot.larger.builder.impl.VideoConfig
11 | import com.starot.larger.config.LargerConfig
12 | import com.starot.larger.enums.LargerEnum
13 | import com.starot.larger.enums.Orientation
14 | import com.starot.larger.impl.OnCustomImageLoadListener
15 | import com.starot.larger.impl.OnImageLoadListener
16 | import com.starot.larger.impl.OnLargerType
17 | import com.starot.larger.impl.OnVideoLoadListener
18 | import com.starot.larger.view.progress.ImageProgressLoader
19 |
20 | class VideoMultiConfig(private val largerConfig: LargerConfig?) :
21 | MultiConfig, VideoConfig {
22 |
23 | init {
24 | largerConfig?.largerType = LargerEnum.LISTS
25 | }
26 |
27 | override fun setRecyclerView(recyclerView: RecyclerView): VideoMultiConfig {
28 | largerConfig?.recyclerView = recyclerView
29 | return this
30 | }
31 |
32 | override fun setData(data: List): VideoMultiConfig {
33 | largerConfig?.data = data
34 | return this
35 | }
36 |
37 |
38 | override fun setImageLoad(imageLoad: OnImageLoadListener): VideoMultiConfig {
39 | largerConfig?.imageLoad = imageLoad
40 | return this
41 | }
42 |
43 |
44 | override fun setUpCanMove(canMove: Boolean): VideoMultiConfig {
45 | largerConfig?.upCanMove = canMove
46 | return this
47 | }
48 |
49 | override fun setLoadNextFragment(auto: Boolean): VideoMultiConfig {
50 | largerConfig?.loadNextFragment = auto
51 | return this
52 | }
53 |
54 | override fun setDebug(debug: Boolean): VideoMultiConfig {
55 | largerConfig?.debug = debug
56 | return this
57 | }
58 |
59 | override fun setBackgroundColor(color: Int): VideoMultiConfig {
60 | largerConfig?.backgroundColor = color
61 | return this
62 | }
63 |
64 | override fun setOrientation(orientation: Orientation): VideoMultiConfig {
65 | largerConfig?.orientation = orientation
66 | return this
67 | }
68 |
69 | override fun setIndex(pos: Int): VideoMultiConfig {
70 | largerConfig?.position = pos
71 | return this
72 | }
73 |
74 | override fun setDuration(duration: Long): VideoMultiConfig {
75 | largerConfig?.duration = duration
76 | return this
77 | }
78 |
79 | override fun setVideoLoad(videoLoader: OnVideoLoadListener): VideoMultiConfig {
80 | largerConfig?.videoLoad = videoLoader
81 | return this
82 | }
83 |
84 |
85 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/config/VideoSingleConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.config
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.widget.ImageView
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.starot.larger.act.CustomLargerAct
8 | import com.starot.larger.act.LargerAct
9 | import com.starot.larger.builder.impl.ImageConfig
10 | import com.starot.larger.builder.impl.MultiConfig
11 | import com.starot.larger.builder.impl.SingleConfig
12 | import com.starot.larger.builder.impl.VideoConfig
13 | import com.starot.larger.config.LargerConfig
14 | import com.starot.larger.enums.LargerEnum
15 | import com.starot.larger.enums.Orientation
16 | import com.starot.larger.impl.OnCustomImageLoadListener
17 | import com.starot.larger.impl.OnImageLoadListener
18 | import com.starot.larger.impl.OnLargerType
19 | import com.starot.larger.impl.OnVideoLoadListener
20 | import com.starot.larger.view.progress.ImageProgressLoader
21 |
22 | class VideoSingleConfig(private val largerConfig: LargerConfig?) :
23 | SingleConfig, VideoConfig {
24 |
25 | init {
26 | largerConfig?.largerType = LargerEnum.SINGLES
27 | }
28 |
29 |
30 | override fun setImageLoad(imageLoad: OnImageLoadListener): VideoSingleConfig {
31 | largerConfig?.imageLoad = imageLoad
32 | return this
33 | }
34 |
35 |
36 | override fun setUpCanMove(canMove: Boolean): VideoSingleConfig {
37 | largerConfig?.upCanMove = canMove
38 | return this
39 | }
40 |
41 | override fun setLoadNextFragment(auto: Boolean): VideoSingleConfig {
42 | largerConfig?.loadNextFragment = auto
43 | return this
44 | }
45 |
46 | override fun setDebug(debug: Boolean): VideoSingleConfig {
47 | largerConfig?.debug = debug
48 | return this
49 | }
50 |
51 | override fun setBackgroundColor(color: Int): VideoSingleConfig {
52 | largerConfig?.backgroundColor = color
53 | return this
54 | }
55 |
56 | override fun setOrientation(orientation: Orientation): VideoSingleConfig {
57 | largerConfig?.orientation = orientation
58 | return this
59 | }
60 |
61 |
62 | override fun setDuration(duration: Long): VideoSingleConfig {
63 | largerConfig?.duration = duration
64 | return this
65 | }
66 |
67 | override fun setImage(image: ImageView): VideoSingleConfig {
68 | largerConfig?.images = arrayListOf(image)
69 | return this
70 | }
71 |
72 | override fun setData(data: OnLargerType): VideoSingleConfig {
73 | largerConfig?.data = arrayListOf(data)
74 | return this
75 | }
76 |
77 | override fun setVideoLoad(videoLoader: OnVideoLoadListener): VideoSingleConfig {
78 | largerConfig?.videoLoad = videoLoader
79 | return this
80 | }
81 |
82 |
83 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/impl/CommandConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.impl
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import com.starot.larger.act.CustomLargerAct
6 | import com.starot.larger.config.LargerConfig
7 | import com.starot.larger.enums.Orientation
8 | import com.starot.larger.impl.OnLargerType
9 |
10 |
11 | interface CommandConfig {
12 |
13 | //是否直接向上就能够拖动,微信直接向上不可以拖动,这里默认false
14 | fun setUpCanMove(canMove: Boolean): T
15 |
16 | //是否自动加载下一页大图,默认不自动加载下一页
17 | fun setLoadNextFragment(auto: Boolean): T
18 |
19 | //是否打印日志
20 | fun setDebug(debug: Boolean): T
21 |
22 |
23 | //设置背景颜色
24 | fun setBackgroundColor(color: Int): T
25 |
26 | //设置加载方向
27 | fun setOrientation(orientation: Orientation): T
28 |
29 | //设置持续时间
30 | fun setDuration(duration: Long): T
31 |
32 | //开始
33 | fun start(context: Context) {
34 | val intent = Intent(context, CustomLargerAct::class.java)
35 | context.startActivity(intent)
36 | }
37 |
38 | //跳转到自定义的act
39 | fun start(context: Context, cls: Class<*>) {
40 | val intent = Intent(context, cls)
41 | context.startActivity(intent)
42 | }
43 |
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/impl/ImageConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.impl
2 |
3 | import com.starot.larger.config.LargerConfig
4 | import com.starot.larger.impl.OnCustomImageLoadListener
5 | import com.starot.larger.impl.OnImageLoadListener
6 | import com.starot.larger.view.progress.ImageProgressLoader
7 |
8 |
9 | interface ImageConfig : CommandConfig {
10 | //是否自动加载
11 | fun setAutomatic(automatic: Boolean): T
12 |
13 | //最大的比例
14 | fun setMaxScale(maxScale: Float): T
15 |
16 | //设置双击中间的比例 可以和 max 相同 但是不能大于max
17 | fun setMediumScale(mediumScale: Float): T
18 |
19 | //设置图片加载器
20 | fun setImageLoad(imageLoad: OnImageLoadListener): T
21 |
22 | //设置加载的进度
23 | fun setProgressType(progressType: ImageProgressLoader.ProgressType): T
24 |
25 | //设置是否显示加载框
26 | fun setProgressLoaderUse(use: Boolean): T
27 |
28 | //自定义布局
29 | fun setCustomListener(
30 | layoutId: Int,
31 | fullViewId: Int,
32 | listener: OnCustomImageLoadListener? = null
33 | ): T
34 |
35 | //自定义布局
36 | fun setCustomListener(
37 | layoutId: Int,
38 | fullViewId: Int,
39 | progressId: Int,
40 | listener: OnCustomImageLoadListener? = null
41 | ): T
42 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/impl/MultiConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.impl
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import com.starot.larger.config.LargerConfig
5 | import com.starot.larger.impl.OnLargerType
6 |
7 | interface MultiConfig {
8 | //列表的情况需要将 recyclerview 也传入
9 | fun setRecyclerView(recyclerView: RecyclerView): T
10 |
11 | //pos
12 | fun setIndex(pos: Int): T
13 |
14 | //设置数据源
15 | fun setData(data: List): T
16 |
17 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/impl/SingleConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.impl
2 |
3 | import android.widget.ImageView
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.starot.larger.builder.config.ImageMultiConfig
6 | import com.starot.larger.impl.OnLargerType
7 |
8 | interface SingleConfig {
9 |
10 | //withSingle 模式下 设置imageView
11 | fun setImage(image: ImageView): T
12 |
13 | //设置数据源
14 | fun setData(data: OnLargerType): T
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/builder/impl/VideoConfig.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.builder.impl
2 |
3 | import com.starot.larger.config.LargerConfig
4 | import com.starot.larger.impl.OnCustomImageLoadListener
5 | import com.starot.larger.impl.OnImageLoadListener
6 | import com.starot.larger.impl.OnVideoLoadListener
7 | import com.starot.larger.view.progress.ImageProgressLoader
8 |
9 |
10 | interface VideoConfig : CommandConfig {
11 |
12 |
13 | //设置图片加载器
14 | fun setImageLoad(imageLoad: OnImageLoadListener): T
15 |
16 | fun setVideoLoad(videoLoader: OnVideoLoadListener): T
17 |
18 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/config/Config.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.config
2 |
3 | import android.graphics.Color
4 | import android.view.View
5 | import android.widget.ImageView
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.starot.larger.enums.LargerEnum
8 | import com.starot.larger.enums.Orientation
9 | import com.starot.larger.impl.*
10 | import com.starot.larger.view.progress.ImageProgressLoader
11 |
12 |
13 | class DefConfig() {
14 |
15 | companion object {
16 | var def_duration = 300L
17 | var def_max_scale = 3.0f
18 | var def_max_scale_last_size = 1.0f
19 | var def_medium_scale = 1.5f
20 | var def_min_scale = 0.2f
21 | var def_back_color = Color.BLACK
22 | var def_automatic = true
23 | var def_debug = false
24 | var def_progress_type = ImageProgressLoader.ProgressType.FULL
25 | var def_up_can_move = false
26 | var def_loadNextFragment = false
27 | var def_progress_use = true
28 | var orientation = Orientation.ORIENTATION_HORIZONTAL
29 | }
30 | }
31 |
32 |
33 | data class LargerConfig(
34 |
35 | //是否直接向上就能够拖动,微信直接向上不可以拖动,这里默认false
36 | var upCanMove: Boolean = DefConfig.def_up_can_move,
37 |
38 | //是否自动加载下一页,默认不自动加载下一页
39 | var loadNextFragment :Boolean = DefConfig.def_loadNextFragment,
40 |
41 | //是否打印日志
42 | var debug: Boolean = DefConfig.def_debug,
43 |
44 | //单个或者多个图片
45 | var images: List? = null,
46 |
47 | //列表
48 | var recyclerView: RecyclerView? = null,
49 |
50 | //使用的类型
51 | var largerType: LargerEnum = LargerEnum.LISTS,
52 |
53 | //持续时间
54 | var duration: Long = DefConfig.def_duration,
55 |
56 | //是否自动加载大图
57 | var automatic: Boolean = DefConfig.def_automatic,
58 |
59 | //最大缩放比例 (2 - f)
60 | var maxScale: Float = DefConfig.def_max_scale,
61 |
62 | //双击中间的大小 需要小于等于 max
63 | var mediumScale: Float = DefConfig.def_medium_scale,
64 |
65 | //最小缩放比例 (0.1f-0.7f)
66 | var minScale: Float = DefConfig.def_min_scale,
67 |
68 | //数据集合
69 | var data: List? = null,
70 |
71 | //当前的下标
72 | var position: Int = 0,
73 |
74 | //列表的布局
75 | var layoutId: Int? = null,
76 |
77 | //大图的ImageViewID
78 | var fullViewId: Int? = null,
79 |
80 | //获取加载框的id
81 | var progressId: Int? = null,
82 |
83 | //默认的背景颜色
84 | var backgroundColor: Int = DefConfig.def_back_color,
85 |
86 | //自定义
87 | var customImageLoadListener: OnCustomImageLoadListener? = null,
88 |
89 | //图片加载器
90 | var imageLoad: OnImageLoadListener? = null,
91 |
92 | //加载y样式
93 | var progressType: ImageProgressLoader.ProgressType = DefConfig.def_progress_type,
94 |
95 | //是否使用加载框
96 | var progressLoaderUse: Boolean = DefConfig.def_progress_use,
97 |
98 | //设置滑动方向
99 | var orientation: Orientation = DefConfig.orientation,
100 |
101 | //视屏加载器
102 | var videoLoad: OnVideoLoadListener? = null
103 | )
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/AnimStatus.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class AnimStatus {
4 |
5 | NOME,
6 |
7 | ENTER_START,
8 | ENTER_END,
9 |
10 | EXIT_START,
11 | EXIT_END,
12 |
13 | DRAG_START,
14 | DRAG_END,
15 |
16 | SCALE_START,
17 | SCALE_END
18 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/AnimType.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class AnimType {
4 | ENTER,
5 | EXIT,
6 | DRAG_RESUME,
7 | DRAG_EXIT,
8 |
9 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/BackEnum.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class BackEnum {
4 | BACK_NOME,
5 | BACK_PREPARE,
6 | BACK_START,
7 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/LargerDataEnum.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class LargerDataEnum {
4 | IMAGE,
5 | Video
6 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/LargerEnum.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class LargerEnum {
4 | //列表类型
5 | LISTS,
6 | //多个或者单个图片类型
7 | SINGLES
8 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/LoadImageStatus.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class LoadImageStatus {
4 |
5 | //显示出加载框状态
6 | LOAD_SHOW,
7 | //开始下载大图
8 | LOAD_START,
9 | //大图下载成功
10 | LOAD_SUCCESS,
11 | //大图加载失败
12 | LOAD_FAILED
13 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/enums/Orientation.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.enums
2 |
3 | enum class Orientation {
4 | ORIENTATION_VERTICAL,
5 | ORIENTATION_HORIZONTAL
6 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/fragment/VideoFg.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.fragment
2 |
3 | import android.view.View
4 | import android.widget.ImageView
5 | import androidx.viewpager2.widget.ViewPager2
6 | import com.starot.larger.Larger
7 | import com.starot.larger.bean.LargerBean
8 | import com.starot.larger.enums.AnimStatus
9 | import com.starot.larger.enums.AnimType
10 | import com.starot.larger.view.image.OnLargerDragListener
11 | import com.starot.larger.impl.OnImageLoadReadyListener
12 | import com.starot.larger.status.LargerStatus
13 | import com.starot.larger.utils.LogUtils
14 | import kotlin.math.abs
15 |
16 | class VideoFg : BaseLargerFragment(), OnLargerDragListener {
17 |
18 | private lateinit var videoView: View
19 |
20 |
21 | private var isLoadVideo = false
22 |
23 | override fun getLayoutId(): Int {
24 | return Larger.largerConfig?.layoutId ?: Larger.largerConfig?.videoLoad?.getVideoLayoutId()
25 | ?: -1
26 | }
27 |
28 |
29 | // override fun onTranslatorBefore(type: AnimType, fullView: View, thumbnailView: View) {
30 | // val imageView = getPoster(fragmentView)
31 | // if (imageView != null && thumbnailView is ImageView && type == AnimType.ENTER) {
32 | // val data = getData() ?: return
33 | // val thumbnailsUrl = data.thumbnailsUrl
34 | // if (thumbnailsUrl.isNullOrEmpty()) {
35 | // return
36 | // }
37 | // Larger.largerConfig?.imageLoad?.load(thumbnailsUrl, position, false, imageView)
38 | // imageView.scaleType = thumbnailView.scaleType
39 | // }
40 | // }
41 |
42 | override fun onTranslatorBefore(
43 | type: AnimType,
44 | fullView: View,
45 | thumbnailView: View,
46 | onImageLoadReadyListener: OnImageLoadReadyListener?
47 | ) {
48 | val imageView = getPoster(fragmentView)
49 | if (imageView != null && thumbnailView is ImageView && type == AnimType.ENTER) {
50 | val data = getData() ?: return
51 | val thumbnailsUrl = data.thumbnailsUrl
52 | if (thumbnailsUrl.isNullOrEmpty()) {
53 | return
54 | }
55 | Larger.largerConfig?.imageLoad?.load(
56 | thumbnailsUrl,
57 | position,
58 | imageView,
59 | onImageLoadReadyListener
60 | )
61 | imageView.scaleType = thumbnailView.scaleType
62 | }
63 | }
64 |
65 | override fun onTranslatorStart(type: AnimType, fullView: View, thumbnailView: View) {
66 | val imageView = getPoster(fragmentView)
67 | if (imageView is ImageView && type == AnimType.ENTER) {
68 | imageView.scaleType = ImageView.ScaleType.FIT_CENTER
69 | } else if (imageView is ImageView && thumbnailView is ImageView && (type == AnimType.EXIT || type == AnimType.DRAG_EXIT)) {
70 | imageView.scaleType = thumbnailView.scaleType
71 | }
72 | }
73 |
74 |
75 | override fun getFullViewId(): Int {
76 | return Larger.largerConfig?.fullViewId ?: Larger.largerConfig?.videoLoad?.getVideoViewId()
77 | ?: -1
78 | }
79 |
80 | override fun onDoBefore(
81 | data: LargerBean?,
82 | fullView: View?,
83 | thumbnailView: View?,
84 | position: Int,
85 | view: View
86 | ) {
87 | if (fullView != null) {
88 | this.videoView = fullView
89 | }
90 |
91 | val imageView = getPoster(view)
92 | if (imageView != null && data != null) {
93 | val thumbnailsUrl = data.thumbnailsUrl
94 | if (thumbnailsUrl.isNullOrEmpty()) {
95 | return
96 | }
97 | imageView.scaleType = ImageView.ScaleType.FIT_CENTER
98 | // Larger.largerConfig?.imageLoad?.load(thumbnailsUrl, false, imageView)
99 | }
100 | }
101 |
102 | private fun getPoster(view: View): ImageView? {
103 | return Larger.largerConfig?.videoLoad?.getPoster(view)
104 | }
105 |
106 | override fun onDoAfter(
107 | data: LargerBean?,
108 | fullView: View?,
109 | thumbnailView: View?,
110 | position: Int,
111 | view: View
112 | ) {
113 | LogUtils.i("video onDoAfter")
114 | if (data != null) {
115 | val poster = getPoster(view)
116 | if (poster != null) {
117 | poster.scaleType = ImageView.ScaleType.FIT_CENTER
118 | }
119 | if (isLoadVideo) {
120 | LogUtils.i("isLoadVideo ")
121 | return
122 | }
123 | isLoadVideo = true
124 | Larger.largerConfig?.videoLoad?.loadVideo(data, view, this)
125 | }
126 |
127 | }
128 |
129 |
130 | override fun onDrag(x: Float, y: Float) {
131 | if (isAnimIng()) return
132 | LogUtils.i("video drag------------------")
133 | startDrag(fragmentView, videoView, x = x, y = y)
134 | }
135 |
136 | override fun onDragEnd() {
137 | LargerStatus.status.value = (AnimStatus.DRAG_END)
138 | endDrag(videoView)
139 | }
140 |
141 | override fun onDragPrepare(dx: Float, dy: Float): Boolean {
142 | //动画过程中不能触发drag
143 | if (isAnimIng()) {
144 | return false
145 | }
146 |
147 | if (getOrientation() == ViewPager2.ORIENTATION_HORIZONTAL) {
148 | //一开始向上无效
149 | if (abs(dy) > abs(dx)) {
150 | //默认是可以不可以直接向上滑的
151 | val upCanMove = Larger.largerConfig?.upCanMove
152 | if (upCanMove == null || upCanMove == false) {
153 | if (dy < 0) {
154 | return false
155 | }
156 | }
157 | return true
158 | }
159 | } else {
160 | if (abs(dx) > abs(dy)) {
161 | return true
162 | }
163 | }
164 |
165 | return false
166 | }
167 |
168 | override fun onDragStart() {
169 | LargerStatus.status.value = (AnimStatus.DRAG_START)
170 | }
171 |
172 | override fun onAlreadyLoad(
173 | data: LargerBean?,
174 | fullView: View?,
175 | thumbnailView: View?,
176 | position: Int,
177 | view: View,
178 | success: (LargerBean) -> Unit
179 | ) {
180 | val imageView = getPoster(view)
181 | if (imageView != null && data != null) {
182 | val thumbnailsUrl = data.thumbnailsUrl
183 | if (thumbnailsUrl.isNullOrEmpty()) {
184 | return
185 | }
186 | Larger.largerConfig?.imageLoad?.load(
187 | thumbnailsUrl,
188 | position,
189 | imageView,
190 | object : OnImageLoadReadyListener {
191 | override fun onLoadFailed() {
192 |
193 | }
194 |
195 | override fun onReady() {
196 | LogUtils.i("onReady")
197 | success(data)
198 | }
199 | })
200 | }
201 | }
202 |
203 |
204 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnImageLoadListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import android.view.View
4 | import android.widget.ImageView
5 | import androidx.lifecycle.MutableLiveData
6 | import com.starot.larger.bean.LargerBean
7 | import com.starot.larger.enums.LoadImageStatus
8 |
9 | //加载图片接口
10 | interface OnImageLoadListener : OnLoadProgressPrepareListener, OnLifecycleListener {
11 |
12 |
13 | //加载图片
14 | fun load(url: String, position: Int, isLoadFull: Boolean, imageView: ImageView)
15 |
16 | fun load(url: String, position: Int, imageView: ImageView, listener: OnImageLoadReadyListener?)
17 |
18 | //判断是有有缓存
19 | fun checkCache(url: String, listener: OnImageCacheListener)
20 |
21 | //清理缓存
22 | fun clearCache()
23 | }
24 |
25 | //是否有缓存
26 | interface OnImageCacheListener {
27 | fun onCache(hasCache: Boolean)
28 | }
29 |
30 |
31 | interface OnImageLoadReadyListener {
32 | fun onLoadFailed();
33 | fun onReady()
34 | }
35 |
36 | //自行处理view
37 | interface OnCustomImageLoadListener : OnLoadProgressListener {
38 |
39 |
40 | //动画开始以前做啥事情
41 | fun onDoBefore(
42 | progressLoadChangeLiveData:MutableLiveData,
43 | imageLoader: OnImageLoadListener?,
44 | view: View,
45 | position: Int,
46 | data: LargerBean
47 | )
48 |
49 | //动画结束以后做啥事情
50 | fun onDoAfter(
51 | progressLoadChangeLiveData:MutableLiveData,
52 | imageLoader: OnImageLoadListener?,
53 | view: View,
54 | position: Int,
55 | data: LargerBean
56 | )
57 |
58 | }
59 |
60 |
61 | interface OnLoadProgressPrepareListener {
62 |
63 | // 将记录是否显示加载的进度框 的 liveData 传入
64 | fun onPrepareProgressView(status: MutableLiveData, position: Int) {}
65 |
66 | // 将记录变化的 liveData 传入
67 | fun onPrepareLoadProgress(progressLiveData: MutableLiveData, position: Int) {}
68 |
69 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnLargerConfigListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.GridLayoutManager
5 | import androidx.recyclerview.widget.LinearLayoutManager
6 | import androidx.recyclerview.widget.StaggeredGridLayoutManager
7 | import androidx.viewpager2.widget.ViewPager2
8 | import com.starot.larger.Larger
9 | import com.starot.larger.config.DefConfig
10 | import com.starot.larger.enums.LargerEnum
11 | import com.starot.larger.enums.Orientation
12 | import com.starot.larger.view.progress.ImageProgressLoader
13 |
14 | //处理返回一些 框架需要的数据
15 | interface OnLargerConfigListener {
16 |
17 |
18 | //动画时长
19 | fun getDuration(): Long {
20 | return Larger.largerConfig?.duration ?: DefConfig.def_duration
21 | }
22 |
23 | //背景颜色
24 | fun getBackGroundColor(): Int {
25 | return Larger.largerConfig?.backgroundColor ?: DefConfig.def_back_color
26 | }
27 |
28 | //加载方向
29 | fun getOrientation(): Int {
30 | return if (Larger.largerConfig?.orientation == null) {
31 | ViewPager2.ORIENTATION_HORIZONTAL
32 | } else {
33 | if (Larger.largerConfig?.orientation == Orientation.ORIENTATION_HORIZONTAL) {
34 | ViewPager2.ORIENTATION_HORIZONTAL
35 | } else {
36 | ViewPager2.ORIENTATION_VERTICAL
37 | }
38 | }
39 |
40 | }
41 |
42 |
43 | //是否自动加载下一页大图数据
44 | fun isAutoLoadNextFragment(): Boolean {
45 | return Larger.largerConfig?.loadNextFragment ?: DefConfig.def_loadNextFragment
46 | }
47 |
48 |
49 | //缩放最大
50 | fun getMaxScale(): Float {
51 | val maxScale = Larger.largerConfig?.maxScale ?: return DefConfig.def_max_scale
52 | if (maxScale < DefConfig.def_max_scale_last_size) {
53 | return DefConfig.def_max_scale_last_size
54 | }
55 | return maxScale
56 | }
57 |
58 | //双击 中间的大小
59 | fun getMediumScale(): Float {
60 | val mediumScale = Larger.largerConfig?.mediumScale ?: return DefConfig.def_medium_scale
61 | if (getMaxScale() < mediumScale) {
62 | throw Throwable("mediumScale must <= maxScale")
63 | }
64 | return mediumScale
65 | }
66 |
67 | //缩放最小
68 | fun getMinScale(): Float {
69 | val minScale = Larger.largerConfig?.minScale ?: return DefConfig.def_min_scale
70 | if (minScale > 0.7f) {
71 | return 0.7f
72 | }
73 | return minScale
74 | }
75 |
76 | //获取小图
77 | fun getThumbnailView(position: Int): View? {
78 | return when (Larger.largerConfig?.largerType) {
79 | LargerEnum.LISTS -> {
80 | getViewInRecycler(position)
81 | }
82 | LargerEnum.SINGLES -> {
83 | getViewInSingles(position)
84 | }
85 | else -> {
86 | null
87 | }
88 | }
89 | }
90 |
91 | //是否自动加载
92 | fun isAutomatic(): Boolean {
93 | return Larger.largerConfig?.automatic ?: DefConfig.def_automatic
94 | }
95 |
96 | //获取singles 小图
97 | private fun getViewInSingles(position: Int): View? {
98 | val images = Larger.largerConfig?.images
99 | return images?.get(position)
100 | }
101 |
102 | //图片加载框的样式
103 | fun getProgressLoaderType(): ImageProgressLoader.ProgressType {
104 | return Larger.largerConfig?.progressType ?: DefConfig.def_progress_type
105 | }
106 |
107 | private fun getViewInRecycler(position: Int): View? {
108 | val recyclerView = Larger.largerConfig?.recyclerView
109 | val layoutManager = recyclerView?.layoutManager
110 |
111 | var pos = position
112 | when (layoutManager) {
113 | is GridLayoutManager -> {
114 | pos = getRecyclerViewId(layoutManager, pos)
115 | }
116 | is LinearLayoutManager -> {
117 | pos = getRecyclerViewId(layoutManager, pos)
118 | }
119 | is StaggeredGridLayoutManager -> {
120 | }
121 | }
122 | return recyclerView?.getChildAt(pos) ?: return null
123 | }
124 |
125 |
126 | //获取recyclerView Id
127 | private fun getRecyclerViewId(
128 | layoutManager: LinearLayoutManager,
129 | pos: Int
130 | ): Int {
131 | var pos1 = pos
132 | pos1 -= layoutManager.findFirstVisibleItemPosition()
133 | return pos1
134 | }
135 |
136 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnLargerListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.GridLayoutManager
5 | import androidx.recyclerview.widget.LinearLayoutManager
6 | import androidx.recyclerview.widget.StaggeredGridLayoutManager
7 | import com.starot.larger.Larger
8 | import com.starot.larger.config.DefConfig
9 | import com.starot.larger.enums.LargerEnum
10 |
11 | //处理返回一些 框架需要的数据
12 | interface OnLargerListener : OnLargerConfigListener {
13 |
14 | //返回larger 界面的 需要加载的 大图 id
15 | fun getFullViewId(): Int
16 |
17 | //获取layout id
18 | fun getLayoutId(): Int
19 |
20 | //获取加载框的id
21 | fun getProgressId(): Int{
22 | return -1
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnLargerType.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import android.os.Parcelable
4 | import com.starot.larger.enums.LargerDataEnum
5 |
6 | /** 当前数据源的类型 **/
7 | interface OnLargerType : Parcelable {
8 |
9 | fun getType(): LargerDataEnum
10 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnLifecycleListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import androidx.lifecycle.Lifecycle
4 | import androidx.lifecycle.LifecycleObserver
5 | import androidx.lifecycle.OnLifecycleEvent
6 |
7 |
8 | interface OnLifecycleListener : LifecycleObserver {
9 |
10 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
11 | fun onCreate() {
12 | }
13 |
14 | @OnLifecycleEvent(Lifecycle.Event.ON_START)
15 | fun onStart() {
16 | }
17 |
18 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
19 | fun onResume() {
20 | }
21 |
22 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
23 | fun onPause() {
24 | }
25 |
26 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
27 | fun onStop() {
28 | }
29 |
30 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
31 | fun onDestroy() {
32 | }
33 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnLoadProgressListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import com.starot.larger.enums.LoadImageStatus
6 |
7 | interface OnLoadProgressListener : OnLifecycleListener {
8 |
9 | //进度条的变化
10 | fun onProgressChange(
11 | context: Context,
12 | view: View,
13 | progressId: Int,
14 | status: LoadImageStatus,
15 | position: Int
16 | )
17 |
18 | //图片加载进度
19 | fun onLoadProgress(view: View, progressId: Int, progress: Int, position: Int)
20 |
21 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/impl/OnVideoLoadListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.impl
2 |
3 | import android.view.View
4 | import android.widget.ImageView
5 | import com.starot.larger.bean.LargerBean
6 | import com.starot.larger.view.image.OnLargerDragListener
7 |
8 | //加载图片接口
9 | interface OnVideoLoadListener : OnLoadProgressPrepareListener,
10 | OnVideoViewIdListener, OnLifecycleListener {
11 |
12 | //返回预览图
13 | fun getPoster(view: View): ImageView
14 |
15 | //加载视屏
16 | fun loadVideo(data: LargerBean, view: View, listener: OnLargerDragListener)
17 |
18 |
19 | //清理资源
20 | fun onRelease()
21 |
22 | }
23 |
24 |
25 | interface OnVideoViewIdListener {
26 | //返回视屏的id
27 | fun getVideoViewId(): Int
28 |
29 | //返回布局id
30 | fun getVideoLayoutId(): Int
31 |
32 |
33 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/livedata/UnViscousLiveData.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.livedata
2 |
3 | import androidx.lifecycle.LifecycleOwner
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.Observer
7 | import java.lang.reflect.Field
8 | import java.lang.reflect.Method
9 |
10 |
11 | class UnViscousLiveData : MutableLiveData() {
12 | //目的:使得在observe被调用的时候,能够保证 if (observer.mLastVersion >= mVersion) (livedata源码里面的)成立
13 | override fun observe(owner: LifecycleOwner, observer: Observer) {
14 | super.observe(owner, observer)
15 | try {
16 | hook(observer)
17 | } catch (t: Throwable) {
18 |
19 | }
20 | }
21 |
22 | /**要修改observer.mLastVersion的值那么思考:(逆向思维)
23 | * mLastVersion-》observer-》iterator.next().getValue()-》mObservers
24 | * 反射使用的时候,正好相反
25 | *
26 | * mObservers-》函数(iterator.next().getValue())-》observer-》mLastVersion
27 | * 通过hook,将observer.mLastVersion = mVersion
28 | * @param observer
29 | * @throws Exception
30 | */
31 | @Throws(Exception::class)
32 | private fun hook(observer: Observer) {
33 | val liveDataClass = LiveData::class.java
34 | val fieldObservers: Field = liveDataClass.getDeclaredField("mObservers")
35 | fieldObservers.isAccessible = true
36 | val mObservers = fieldObservers.get(this)
37 | val mObserversClass: Class<*> = mObservers.javaClass
38 | val method: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
39 | method.isAccessible = true
40 | val entry = method.invoke(mObservers, observer)
41 | val observerWrapper = (entry as Map.Entry<*, *>).value!!
42 | val mObserver: Class<*> = observerWrapper.javaClass.superclass //observer
43 | val mLastVersion: Field = mObserver.getDeclaredField("mLastVersion")
44 | mLastVersion.isAccessible = true
45 | val mVersion: Field = liveDataClass.getDeclaredField("mVersion")
46 | mVersion.isAccessible = true
47 | val mVersionObject = mVersion.get(this)
48 | mLastVersion.set(observerWrapper, mVersionObject)
49 | }
50 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/status/LargerStatus.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.status
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import com.starot.larger.enums.AnimStatus
5 | import com.starot.larger.enums.BackEnum
6 | import com.starot.larger.impl.OnLifecycleListener
7 | import com.starot.larger.livedata.UnViscousLiveData
8 |
9 | object LargerStatus : OnLifecycleListener {
10 |
11 | var status = MutableLiveData().apply {
12 | value = (AnimStatus.NOME)
13 | }
14 |
15 | //是否已经加载过了
16 | var isLoad = MutableLiveData().apply {
17 | value = (false)
18 | }
19 |
20 | var pos = MutableLiveData()
21 |
22 | var back = MutableLiveData().apply {
23 | value = BackEnum.BACK_NOME
24 | }
25 |
26 | override fun onDestroy() {
27 | super.onDestroy()
28 | isLoad.value = (false)
29 | back.value = BackEnum.BACK_NOME
30 | status.value = (AnimStatus.NOME)
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/utils/ColorTool.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.utils
2 |
3 | object ColorTool {
4 |
5 | /**
6 | * 对rgb色彩加入透明度
7 | * @param alpha 透明度,取值范围 0.0f -- 1.0f.
8 | * @param baseColor
9 | * @return a color with alpha made from base color
10 | */
11 | fun getColorWithAlpha(baseColor: Int, alpha: Float): Int {
12 | val a = 255.coerceAtMost(0.coerceAtLeast((alpha * 255).toInt())) shl 24
13 | val rgb = 0x00ffffff and baseColor
14 | return a + rgb
15 | }
16 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/utils/LogUtils.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.utils
2 |
3 | import android.util.Log
4 | import com.starot.larger.Larger
5 |
6 | object LogUtils {
7 |
8 |
9 | private const val TAG = "allens_tag"
10 |
11 | @JvmStatic
12 | fun i(info: String) {
13 | if (Larger.largerConfig?.debug == true)
14 | Log.e(TAG, info)
15 | }
16 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/utils/PageChange.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.utils
2 |
3 | import androidx.viewpager2.widget.ViewPager2
4 |
5 | class PageChange {
6 |
7 |
8 | fun register(viewPager2: ViewPager2, listener: PageChangeListener) {
9 | viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
10 | override fun onPageSelected(position: Int) {
11 | super.onPageSelected(position)
12 | listener.onPageChange(position)
13 | }
14 | })
15 | }
16 |
17 | interface PageChangeListener {
18 | fun onPageChange(pos: Int)
19 | }
20 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/utils/StatusBarTools.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.utils
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.graphics.Color
6 | import android.os.Build
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.view.Window
10 | import android.view.WindowManager
11 | import android.widget.FrameLayout
12 | import androidx.core.view.ViewCompat
13 |
14 | //将电池兰取消 沉寂式 的布局
15 | object StatusBarTools {
16 |
17 |
18 | fun setStatusBar(activity: Activity) {
19 | translucentStatusBar(activity, true)
20 | changeToLightStatusBar(activity)
21 | }
22 |
23 | //SDK >= 21时, 取消状态栏的阴影
24 | private fun translucentStatusBar(
25 | activity: Activity,
26 | hideStatusBarBackground: Boolean
27 | ) {
28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
29 | translucentStatusBarLOLLIPOP(activity, hideStatusBarBackground)
30 | } else
31 | translucentStatusBar(activity)
32 | }
33 |
34 | //SDK> = 23,将状态栏改为浅色模式(状态栏图标和字体会变成深色)
35 | private fun changeToLightStatusBar(activity: Activity) {
36 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
37 | return
38 | }
39 | val window = activity.window ?: return
40 | val decorView = window.decorView
41 | decorView.systemUiVisibility =
42 | decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
43 | }
44 |
45 |
46 | private fun translucentStatusBarLOLLIPOP(
47 | activity: Activity,
48 | hideStatusBarBackground: Boolean
49 | ) {
50 | val window = activity.window
51 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
52 | if (hideStatusBarBackground) {
53 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
54 | window.statusBarColor = Color.TRANSPARENT
55 | window.decorView.systemUiVisibility =
56 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
57 | } else {
58 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
59 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
60 | }
61 | val mContentView =
62 | window.findViewById(Window.ID_ANDROID_CONTENT) as ViewGroup
63 | val mChildView = mContentView.getChildAt(0)
64 | if (mChildView != null) {
65 | ViewCompat.setFitsSystemWindows(mChildView, false)
66 | ViewCompat.requestApplyInsets(mChildView)
67 | }
68 | }
69 |
70 | private fun translucentStatusBar(activity: Activity) {
71 | val window = activity.window
72 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
73 | val mContentView =
74 | activity.findViewById(Window.ID_ANDROID_CONTENT) as ViewGroup
75 | val mContentChild = mContentView.getChildAt(0)
76 | removeFakeStatusBarViewIfExist(activity)
77 | removeMarginTopOfContentChild(
78 | mContentChild,
79 | getStatusBarHeight(activity)
80 | )
81 | if (mContentChild != null) {
82 | ViewCompat.setFitsSystemWindows(mContentChild, false)
83 | }
84 | }
85 |
86 | /**
87 | * return statusBar's Height in pixels
88 | */
89 | private fun getStatusBarHeight(context: Context): Int {
90 | var result = 0
91 | val resId =
92 | context.resources.getIdentifier("status_bar_height", "dimen", "android")
93 | if (resId > 0) {
94 | result = context.resources.getDimensionPixelOffset(resId)
95 | }
96 | return result
97 | }
98 |
99 |
100 | /**
101 | * remove marginTop to simulate set FitsSystemWindow false
102 | */
103 | private fun removeMarginTopOfContentChild(
104 | mContentChild: View?,
105 | statusBarHeight: Int
106 | ) {
107 | if (mContentChild == null) {
108 | return
109 | }
110 | if ("marginAdded" == mContentChild.tag) {
111 | val lp =
112 | mContentChild.layoutParams as FrameLayout.LayoutParams
113 | lp.topMargin -= statusBarHeight
114 | mContentChild.layoutParams = lp
115 | mContentChild.tag = null
116 | }
117 | }
118 |
119 |
120 | /**
121 | * use reserved order to remove is more quickly.
122 | */
123 | private fun removeFakeStatusBarViewIfExist(activity: Activity) {
124 | val window = activity.window
125 | val mDecorView = window.decorView as ViewGroup
126 | val fakeView =
127 | mDecorView.findViewWithTag("statusBarView")
128 | if (fakeView != null) {
129 | mDecorView.removeView(fakeView)
130 | }
131 | }
132 |
133 |
134 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/Compat.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2011, 2012 Chris Banes.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.starot.larger.view.image;
17 |
18 | import android.annotation.TargetApi;
19 | import android.os.Build.VERSION;
20 | import android.os.Build.VERSION_CODES;
21 | import android.view.View;
22 |
23 | class Compat {
24 |
25 | private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
26 |
27 | public static void postOnAnimation(View view, Runnable runnable) {
28 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
29 | postOnAnimationJellyBean(view, runnable);
30 | } else {
31 | view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
32 | }
33 | }
34 |
35 | @TargetApi(16)
36 | private static void postOnAnimationJellyBean(View view, Runnable runnable) {
37 | view.postOnAnimation(runnable);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnGestureListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2011, 2012 Chris Banes.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package com.starot.larger.view.image;
17 |
18 | interface OnGestureListener {
19 |
20 | void onDrag(float dx, float dy);
21 |
22 | void onFling(float startX, float startY, float velocityX,
23 | float velocityY);
24 |
25 | void onScale(float scaleFactor, float focusX, float focusY);
26 |
27 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnLargerDragListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image
2 |
3 | interface OnLargerDragListener {
4 |
5 |
6 | fun onDrag(x: Float, y: Float) {}
7 |
8 | fun onDragEnd() {}
9 |
10 | fun onDragStart() {}
11 |
12 | fun onDragPrepare(dx: Float, dy: Float): Boolean {
13 | return true
14 | }
15 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnLargerScaleListener.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image
2 |
3 | interface OnLargerScaleListener {
4 |
5 |
6 | fun onScaleEnd() {}
7 |
8 | fun onScaleStart() {}
9 |
10 | fun onScale(scaleFactor: Float, focusX: Float, focusY: Float) {}
11 |
12 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnMatrixChangedListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | import android.graphics.RectF;
4 |
5 | /**
6 | * Interface definition for a callback to be invoked when the internal Matrix has changed for
7 | * this View.
8 | */
9 | public interface OnMatrixChangedListener {
10 |
11 | /**
12 | * Callback for when the Matrix displaying the Drawable has changed. This could be because
13 | * the View's bounds have changed, or the user has zoomed.
14 | *
15 | * @param rect - Rectangle displaying the Drawable's new bounds.
16 | */
17 | void onMatrixChanged(RectF rect);
18 | }
19 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnOutsidePhotoTapListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | import android.widget.ImageView;
4 |
5 | /**
6 | * Callback when the user tapped outside of the photo
7 | */
8 | public interface OnOutsidePhotoTapListener {
9 |
10 | /**
11 | * The outside of the photo has been tapped
12 | */
13 | void onOutsidePhotoTap(ImageView imageView);
14 | }
15 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnPhotoTapListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | import android.widget.ImageView;
4 |
5 | /**
6 | * A callback to be invoked when the Photo is tapped with a single
7 | * tap.
8 | */
9 | public interface OnPhotoTapListener {
10 |
11 | /**
12 | * A callback to receive where the user taps on a photo. You will only receive a callback if
13 | * the user taps on the actual photo, tapping on 'whitespace' will be ignored.
14 | *
15 | * @param view ImageView the user tapped.
16 | * @param x where the user tapped from the of the Drawable, as percentage of the
17 | * Drawable width.
18 | * @param y where the user tapped from the top of the Drawable, as percentage of the
19 | * Drawable height.
20 | */
21 | void onPhotoTap(ImageView view, float x, float y);
22 | }
23 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnScaleChangedListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 |
4 | /**
5 | * Interface definition for callback to be invoked when attached ImageView scale changes
6 | */
7 | public interface OnScaleChangedListener {
8 |
9 | /**
10 | * Callback for when the scale changes
11 | *
12 | * @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
13 | * @param focusX focal point X position
14 | * @param focusY focal point Y position
15 | */
16 | void onScaleChange(float scaleFactor, float focusX, float focusY);
17 | }
18 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnSingleFlingListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | import android.view.MotionEvent;
4 |
5 | /**
6 | * A callback to be invoked when the ImageView is flung with a single
7 | * touch
8 | */
9 | public interface OnSingleFlingListener {
10 |
11 | /**
12 | * A callback to receive where the user flings on a ImageView. You will receive a callback if
13 | * the user flings anywhere on the view.
14 | *
15 | * @param e1 MotionEvent the user first touch.
16 | * @param e2 MotionEvent the user last touch.
17 | * @param velocityX distance of user's horizontal fling.
18 | * @param velocityY distance of user's vertical fling.
19 | */
20 | boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
21 | }
22 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnViewDragListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | /**
4 | * Interface definition for a callback to be invoked when the photo is experiencing a drag event
5 | */
6 | public interface OnViewDragListener {
7 |
8 | /**
9 | * Callback for when the photo is experiencing a drag event. This cannot be invoked when the
10 | * user is scaling.
11 | *
12 | * @param dx The change of the coordinates in the x-direction
13 | * @param dy The change of the coordinates in the y-direction
14 | */
15 | void onDrag(float dx, float dy);
16 | }
17 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/OnViewTapListener.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | import android.view.View;
4 |
5 | public interface OnViewTapListener {
6 |
7 | /**
8 | * A callback to receive where the user taps on a ImageView. You will receive a callback if
9 | * the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
10 | *
11 | * @param view - View the user tapped.
12 | * @param x - where the user tapped from the left of the View.
13 | * @param y - where the user tapped from the top of the View.
14 | */
15 | void onViewTap(View view, float x, float y);
16 | }
17 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/image/Util.java:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.image;
2 |
3 | import android.view.MotionEvent;
4 | import android.widget.ImageView;
5 |
6 | class Util {
7 |
8 | static void checkZoomLevels(float minZoom, float midZoom,
9 | float maxZoom) {
10 | if (minZoom >= midZoom) {
11 | throw new IllegalArgumentException(
12 | "Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value");
13 | } else if (midZoom > maxZoom) {
14 | throw new IllegalArgumentException(
15 | "Medium zoom has to be less than Maximum zoom. Call setMaximumZoom() with a more appropriate value");
16 | }
17 | }
18 |
19 | static boolean hasDrawable(ImageView imageView) {
20 | return imageView.getDrawable() != null;
21 | }
22 |
23 | static boolean isSupportedScaleType(final ImageView.ScaleType scaleType) {
24 | if (scaleType == null) {
25 | return false;
26 | }
27 | switch (scaleType) {
28 | case MATRIX:
29 | throw new IllegalStateException("Matrix scale type is not supported");
30 | }
31 | return true;
32 | }
33 |
34 | static int getPointerIndex(int action) {
35 | return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/progress/ImageProgressLoader.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.progress
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.view.View
6 | import com.starot.larger.enums.LoadImageStatus
7 | import com.starot.larger.utils.LogUtils
8 |
9 | class ImageProgressLoader(private val type: ProgressType) : ProgressLoader() {
10 |
11 |
12 | override fun onProgressChange(
13 | context: Context,
14 | view: View,
15 | progressId: Int,
16 | status: LoadImageStatus,
17 | position: Int
18 | ) {
19 | LogUtils.i("进度弹窗$position 是否不显示: $status")
20 | if (progressId == -1) {
21 | return
22 | }
23 | val progressView = view.findViewById(progressId) ?: return
24 | when (status) {
25 | LoadImageStatus.LOAD_SHOW -> {
26 | progressView.visibility = View.VISIBLE
27 | }
28 | LoadImageStatus.LOAD_FAILED -> {
29 | progressView.visibility = View.INVISIBLE
30 | }
31 | LoadImageStatus.LOAD_SUCCESS -> {
32 | progressView.visibility = View.INVISIBLE
33 | }
34 | else -> {
35 |
36 | }
37 | }
38 | if (progressView is CircleProgressView) {
39 | setStyle(
40 | progressView,
41 | if (type == ProgressType.FULL) {
42 | 1
43 | } else {
44 | 0
45 | }
46 | )
47 | }
48 |
49 | }
50 |
51 | override fun onLoadProgress(view: View, progressId: Int, progress: Int, position: Int) {
52 |
53 | LogUtils.i("进度弹窗$position progress:$progress")
54 | if (progressId == -1) {
55 | return
56 | }
57 | val progressView = view.findViewById(progressId)
58 | if (progressView is CircleProgressView) {
59 | progressView.progress = progress
60 | }
61 |
62 | }
63 |
64 |
65 | enum class ProgressType {
66 | NONE,
67 | FULL
68 | }
69 |
70 |
71 | private fun setStyle(progressView: CircleProgressView?, style: Int) {
72 | when (style) {
73 | 0 -> {
74 | progressView?.progressStyle = CircleProgressView.ProgressStyle.NORMAL
75 | progressView?.textColor = Color.parseColor("#ffffff")
76 | progressView?.normalBarColor = Color.parseColor("#00000000")
77 | progressView?.reachBarColor = Color.parseColor("#ffffff")
78 | progressView?.isTextVisible = true
79 | progressView?.textSuffix = "%"
80 | progressView?.reachBarSize = 3
81 | progressView?.textSize = 11
82 | }
83 | 1 -> {
84 | progressView?.progressStyle = CircleProgressView.ProgressStyle.FILL_IN_ARC
85 | progressView?.outerColor = Color.parseColor("#ffffff")
86 | progressView?.normalBarColor = Color.parseColor("#00000000")
87 | progressView?.reachBarColor = Color.parseColor("#ffffff")
88 | progressView?.outerSize = 2
89 | progressView?.innerPadding = 2
90 | }
91 | else -> {
92 | progressView?.progressStyle = CircleProgressView.ProgressStyle.FILL_IN_ARC
93 | progressView?.outerColor = Color.parseColor("#ffffff")
94 | progressView?.normalBarColor = Color.parseColor("#00000000")
95 | progressView?.reachBarColor = Color.parseColor("#ffffff")
96 | progressView?.outerSize = 2
97 | progressView?.innerPadding = 2
98 | }
99 | }
100 |
101 | }
102 | }
--------------------------------------------------------------------------------
/Larger/src/main/java/com/starot/larger/view/progress/ProgresssLoader.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger.view.progress
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import com.starot.larger.enums.LoadImageStatus
6 | import com.starot.larger.impl.OnLoadProgressListener
7 |
8 | open class ProgressLoader : OnLoadProgressListener {
9 | override fun onProgressChange(
10 | context: Context,
11 | view: View,
12 | progressId: Int,
13 | status: LoadImageStatus,
14 | position: Int
15 | ) {
16 |
17 | }
18 |
19 | override fun onLoadProgress(view: View, progressId: Int, progress: Int, position: Int) {
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Larger/src/main/res/layout/activity_larger_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/Larger/src/main/res/layout/fg_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
22 |
23 |
--------------------------------------------------------------------------------
/Larger/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Larger/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Larger/src/test/java/com/starot/larger/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.starot.larger
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/LargerGlide/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/LargerGlide/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.2"
9 |
10 | defaultConfig {
11 | minSdkVersion 19
12 | targetSdkVersion 30
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: "libs", include: ["*.jar"])
30 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
31 | implementation 'androidx.core:core-ktx:1.3.1'
32 | implementation 'androidx.appcompat:appcompat:1.2.0'
33 | testImplementation 'junit:junit:4.13'
34 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
35 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
36 |
37 |
38 |
39 | implementation project(":Larger")
40 |
41 | kapt 'com.github.bumptech.glide:glide:4.11.0'
42 | kapt 'com.github.bumptech.glide:compiler:4.11.0'
43 | implementation "com.github.bumptech.glide:okhttp3-integration:4.11.0"
44 |
45 | }
--------------------------------------------------------------------------------
/LargerGlide/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/LargerGlide/consumer-rules.pro
--------------------------------------------------------------------------------
/LargerGlide/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
--------------------------------------------------------------------------------
/LargerGlide/src/androidTest/java/com/allens/largerglide/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide
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.allens.largerglide.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/LargerGlide/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
--------------------------------------------------------------------------------
/LargerGlide/src/main/java/com/allens/largerglide/GlideImageLoader.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.graphics.drawable.Drawable
6 | import android.os.Handler
7 | import android.os.Looper
8 | import android.widget.ImageView
9 | import androidx.lifecycle.MutableLiveData
10 | import com.allens.largerglide.impl.CustomRequestListener
11 | import com.allens.largerglide.impl.ProgressListener
12 | import com.allens.largerglide.interceptor.ProgressInterceptor
13 | import com.bumptech.glide.Glide
14 | import com.bumptech.glide.load.DataSource
15 | import com.bumptech.glide.load.engine.GlideException
16 | import com.bumptech.glide.request.RequestListener
17 | import com.bumptech.glide.request.RequestOptions
18 | import com.bumptech.glide.request.target.Target
19 | import com.starot.larger.enums.LoadImageStatus
20 | import com.starot.larger.impl.OnImageCacheListener
21 | import com.starot.larger.impl.OnImageLoadListener
22 | import com.starot.larger.impl.OnImageLoadReadyListener
23 | import com.starot.larger.utils.LogUtils
24 | import java.io.File
25 |
26 | //Glide 加载图片 这里记录了 加载的进度 和 加载状态 后续考虑 移植到其他地方 以便于拓展
27 | class GlideImageLoader(private val context: Context) : OnImageLoadListener {
28 |
29 |
30 | private var handler: Handler = Handler(Looper.getMainLooper())
31 |
32 | private val statusMap = HashMap>()
33 | private val progressMap = HashMap>()
34 |
35 | private var thread: Thread? = null
36 |
37 | @SuppressLint("CheckResult")
38 | override fun load(url: String, position: Int, isLoadFull: Boolean, imageView: ImageView) {
39 |
40 | val progressViewLiveData = statusMap[position]
41 | val progressLiveData = progressMap[position]
42 | val options = RequestOptions()
43 | if (isLoadFull) {
44 | ProgressInterceptor.addListener(url, object : ProgressListener {
45 | override fun onProgress(progress: Int) {
46 |
47 | val value = progressViewLiveData?.value
48 | if (value == null || value == LoadImageStatus.LOAD_SHOW) {
49 | progressViewLiveData?.value = LoadImageStatus.LOAD_START
50 | }
51 |
52 | //进度
53 | progressLiveData?.value = (progress)
54 | }
55 | })
56 | options
57 | .placeholder(imageView.drawable)
58 | .override(imageView.width, imageView.height)
59 | }
60 | LogUtils.i("load image isLoadFull:$isLoadFull, url:$url")
61 | Glide.with(context)
62 | .load(url)
63 | .apply(options)
64 | .listener(CustomRequestListener(url, progressViewLiveData, isLoadFull))
65 | .into(imageView)
66 | }
67 |
68 | override fun load(
69 | url: String,
70 | position: Int,
71 | imageView: ImageView,
72 | listener: OnImageLoadReadyListener?
73 | ) {
74 | Glide.with(context)
75 | .load(url)
76 | .listener(object : RequestListener {
77 | override fun onLoadFailed(
78 | e: GlideException?,
79 | model: Any?,
80 | target: Target?,
81 | isFirstResource: Boolean
82 | ): Boolean {
83 | listener?.onLoadFailed()
84 | return false
85 | }
86 |
87 | override fun onResourceReady(
88 | resource: Drawable?,
89 | model: Any?,
90 | target: Target?,
91 | dataSource: DataSource?,
92 | isFirstResource: Boolean
93 | ): Boolean {
94 | listener?.onReady()
95 | return false
96 | }
97 | })
98 | .into(imageView)
99 |
100 | }
101 |
102 | override fun checkCache(url: String, listener: OnImageCacheListener) {
103 | thread = Thread {
104 | val file: File? = try {
105 | Glide.with(context).downloadOnly()
106 | .load(url)
107 | .apply(
108 | RequestOptions().onlyRetrieveFromCache(true)
109 | ).submit()
110 | .get()
111 | } catch (e: Exception) {
112 | null
113 | }
114 | if (file == null) {
115 | handler.post {
116 | listener.onCache(false)
117 | }
118 | } else {
119 | handler.post {
120 | listener.onCache(true)
121 | }
122 | }
123 | }
124 | thread?.start()
125 | }
126 |
127 |
128 | override fun clearCache() {
129 | Glide.get(context).clearMemory()
130 | Thread { Glide.get(context).clearDiskCache() }.start()
131 | }
132 |
133 | override fun onPrepareLoadProgress(progressLiveData: MutableLiveData, position: Int) {
134 | progressMap[position] = progressLiveData
135 | }
136 |
137 | override fun onPrepareProgressView(
138 | status: MutableLiveData,
139 | position: Int
140 | ) {
141 | statusMap[position] = status
142 | }
143 |
144 |
145 | override fun onDestroy() {
146 | super.onDestroy()
147 | statusMap.clear()
148 | progressMap.clear()
149 | handler.removeCallbacksAndMessages(null)
150 | thread?.interrupt()
151 | thread = null
152 | }
153 |
154 | }
--------------------------------------------------------------------------------
/LargerGlide/src/main/java/com/allens/largerglide/body/ProgressResponseBody.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide.body
2 |
3 |
4 | import android.os.Handler
5 | import android.util.Log
6 | import com.allens.largerglide.impl.ProgressListener
7 | import com.allens.largerglide.interceptor.ProgressInterceptor
8 | import okhttp3.MediaType
9 | import okhttp3.ResponseBody
10 | import okio.*
11 |
12 |
13 | class ProgressResponseBody(
14 | url: String,
15 | private val handler: Handler,
16 | private var responseBody: ResponseBody
17 | ) : ResponseBody() {
18 |
19 | private var listener: ProgressListener? = ProgressInterceptor.map[url]
20 |
21 | override fun contentLength(): Long {
22 | return responseBody.contentLength()
23 | }
24 |
25 | override fun contentType(): MediaType? {
26 | return responseBody.contentType()
27 | }
28 |
29 | override fun source(): BufferedSource {
30 | return Okio.buffer(ProgressSource(responseBody.source()))
31 | }
32 |
33 | inner class ProgressSource(source: Source) : ForwardingSource(source) {
34 |
35 | private var totalBytesRead: Long = 0
36 |
37 | private var currentProgress = 0
38 | override fun read(sink: Buffer, byteCount: Long): Long {
39 | val bytesRead = super.read(sink, byteCount)
40 | val fullLength = responseBody.contentLength()
41 | if (bytesRead == -1L) {
42 | totalBytesRead = fullLength;
43 | } else {
44 | totalBytesRead += bytesRead;
45 | }
46 | val progress = (100f * totalBytesRead / fullLength).toInt()
47 | if (progress != currentProgress) {
48 | handler.post {
49 | listener?.onProgress(progress)
50 | }
51 | }
52 | currentProgress = progress;
53 | return bytesRead
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/LargerGlide/src/main/java/com/allens/largerglide/impl/CustomRequestListener.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide.impl
2 |
3 | import android.graphics.drawable.Drawable
4 | import androidx.lifecycle.MutableLiveData
5 | import com.allens.largerglide.interceptor.ProgressInterceptor
6 | import com.bumptech.glide.load.DataSource
7 | import com.bumptech.glide.load.engine.GlideException
8 | import com.bumptech.glide.request.RequestListener
9 | import com.bumptech.glide.request.target.Target
10 | import com.starot.larger.enums.LoadImageStatus
11 |
12 | class CustomRequestListener(
13 | private val url: String,
14 | private val progressViewLiveData: MutableLiveData?,
15 | private val loadFull: Boolean
16 | ) :
17 | RequestListener {
18 | override fun onLoadFailed(
19 | e: GlideException?,
20 | model: Any?,
21 | target: Target?,
22 | isFirstResource: Boolean
23 | ): Boolean {
24 | ProgressInterceptor.removeListener(url = url)
25 |
26 | if (loadFull) {
27 | progressViewLiveData?.value = LoadImageStatus.LOAD_FAILED
28 | }
29 | return false
30 | }
31 |
32 | override fun onResourceReady(
33 | resource: Drawable?,
34 | model: Any?,
35 | target: Target?,
36 | dataSource: DataSource?,
37 | isFirstResource: Boolean
38 | ): Boolean {
39 | ProgressInterceptor.removeListener(url = url)
40 |
41 | if (loadFull) {
42 | progressViewLiveData?.value = LoadImageStatus.LOAD_SUCCESS
43 | }
44 | return false
45 | }
46 |
47 |
48 | }
--------------------------------------------------------------------------------
/LargerGlide/src/main/java/com/allens/largerglide/impl/ProgressListener.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide.impl
2 |
3 |
4 | interface ProgressListener {
5 | fun onProgress(progress: Int)
6 | }
7 |
--------------------------------------------------------------------------------
/LargerGlide/src/main/java/com/allens/largerglide/interceptor/ProgressInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide.interceptor
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import com.allens.largerglide.impl.ProgressListener
6 | import com.allens.largerglide.body.ProgressResponseBody
7 | import okhttp3.Interceptor
8 | import okhttp3.Request
9 | import okhttp3.Response
10 | import java.util.concurrent.ConcurrentHashMap
11 |
12 |
13 | object ProgressInterceptor : Interceptor {
14 | override fun intercept(chain: Interceptor.Chain): Response {
15 | val request: Request = chain.request()
16 | val response = chain.proceed(request)
17 | val url: String = request.url().toString()
18 | val body = response.body()
19 | val handler = Handler(Looper.getMainLooper())
20 | return response.newBuilder().body(body?.let {
21 | ProgressResponseBody(
22 | url,
23 | handler,
24 | it
25 | )
26 | }).build()
27 | }
28 |
29 | val map = ConcurrentHashMap()
30 |
31 | //入注册下载监听
32 | fun addListener(url: String, listener: ProgressListener) {
33 | map[url] = listener
34 | }
35 |
36 | //取消注册下载监听
37 | fun removeListener(url: String?) {
38 | map.remove(url)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LargerGlide/src/main/java/com/allens/largerglide/module/MyGlideModule.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide.module
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import com.bumptech.glide.Glide
6 | import com.bumptech.glide.Registry
7 | import com.bumptech.glide.annotation.GlideModule
8 | import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
9 | import com.bumptech.glide.load.model.GlideUrl
10 | import com.bumptech.glide.module.AppGlideModule
11 | import com.allens.largerglide.interceptor.ProgressInterceptor
12 | import okhttp3.OkHttpClient
13 | import java.io.InputStream
14 |
15 | @GlideModule
16 | class MyGlideModule : AppGlideModule() {
17 | override fun registerComponents(
18 | context: Context,
19 | glide: Glide,
20 | registry: Registry
21 | ) {
22 | //添加拦截器到Glide
23 | val builder = OkHttpClient.Builder()
24 | builder.addInterceptor(ProgressInterceptor)
25 | val okHttpClient = builder.build()
26 |
27 | registry.replace(
28 | GlideUrl::class.java,
29 | InputStream::class.java,
30 | OkHttpUrlLoader.Factory(okHttpClient)
31 | )
32 | }
33 |
34 |
35 | }
--------------------------------------------------------------------------------
/LargerGlide/src/test/java/com/allens/largerglide/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.allens.largerglide
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/LargerLoadVideo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/LargerLoadVideo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 | android {
6 | compileSdkVersion 30
7 | buildToolsVersion "30.0.2"
8 |
9 | defaultConfig {
10 | minSdkVersion 21
11 | targetSdkVersion 30
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | consumerProguardFiles "consumer-rules.pro"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility 1.8
27 | targetCompatibility 1.8
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation fileTree(dir: "libs", include: ["*.jar"])
33 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
34 | implementation 'androidx.core:core-ktx:1.3.1'
35 | implementation 'androidx.appcompat:appcompat:1.2.0'
36 | testImplementation 'junit:junit:4.13'
37 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
38 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
39 |
40 |
41 | implementation project(":Larger")
42 |
43 | implementation 'cn.jzvd:jiaozivideoplayer:7.4.2'
44 | }
--------------------------------------------------------------------------------
/LargerLoadVideo/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/LargerLoadVideo/consumer-rules.pro
--------------------------------------------------------------------------------
/LargerLoadVideo/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
--------------------------------------------------------------------------------
/LargerLoadVideo/src/androidTest/java/com/example/largerloadvideo/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.largerloadvideo
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.example.largerloadvideo.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/LargerLoadVideo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
--------------------------------------------------------------------------------
/LargerLoadVideo/src/main/java/com/example/largerloadvideo/LargerDrag.kt:
--------------------------------------------------------------------------------
1 | package com.example.largerloadvideo
2 |
3 | import android.content.Context
4 | import android.view.GestureDetector
5 | import android.view.MotionEvent
6 | import android.view.ViewConfiguration
7 | import com.starot.larger.view.image.OnLargerDragListener
8 | import java.util.concurrent.atomic.AtomicBoolean
9 | import kotlin.math.sqrt
10 |
11 |
12 | class LargerDrag(private val listener: OnLargerDragListener, context: Context) :
13 | GestureDetector.SimpleOnGestureListener() {
14 |
15 | val isDragging = AtomicBoolean(false)
16 |
17 | private val mTouchSlop = ViewConfiguration.get(context).scaledEdgeSlop
18 | override fun onScroll(
19 | e1: MotionEvent?,
20 | e2: MotionEvent?,
21 | distanceX: Float,
22 | distanceY: Float
23 | ): Boolean {
24 | if (e1 != null && e2 != null) {
25 |
26 | if (!isDragging.get()) {
27 | val dx = e2.rawX - e1.rawX
28 | val dy = e2.rawY - e1.rawY
29 | if (listener.onDragPrepare(dx, dy)) {
30 | isDragging.set(sqrt(dx * dx + (dy * dy).toDouble()) >= mTouchSlop)
31 | if (isDragging.get()) {
32 | listener.onDragStart()
33 | }
34 | }
35 | } else {
36 | listener.onDrag(
37 | e2.rawX - e1.rawX,
38 | e2.rawY - e1.rawY
39 | )
40 | }
41 | }
42 | return super.onScroll(e1, e2, distanceX, distanceY)
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/LargerLoadVideo/src/main/java/com/example/largerloadvideo/LargerVideoLoad.kt:
--------------------------------------------------------------------------------
1 | package com.example.largerloadvideo
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.widget.ImageView
6 | import androidx.lifecycle.MutableLiveData
7 | import cn.jzvd.JZUtils
8 | import cn.jzvd.Jzvd
9 | import cn.jzvd.JzvdStd
10 | import com.starot.larger.bean.LargerBean
11 | import com.starot.larger.view.image.OnLargerDragListener
12 | import com.starot.larger.impl.OnVideoLoadListener
13 | import com.starot.larger.utils.LogUtils
14 |
15 |
16 | //视屏加载器
17 | class LargerVideoLoad(private val context: Context) : OnVideoLoadListener {
18 |
19 |
20 | override fun getPoster(view: View): ImageView {
21 | val video = view.findViewById(getVideoViewId())
22 | return video.posterImageView
23 | }
24 |
25 |
26 | override fun loadVideo(data: LargerBean, view: View, listener: OnLargerDragListener) {
27 | LogUtils.i("loadVideo")
28 | val video = view.findViewById(getVideoViewId())?:return
29 | video.setDragListener(object : OnLargerDragListener {
30 | override fun onDrag(x: Float, y: Float) {
31 | listener.onDrag(x, y = y)
32 | }
33 |
34 | override fun onDragEnd() {
35 | listener.onDragEnd()
36 | Jzvd.goOnPlayOnResume()
37 | }
38 |
39 | override fun onDragPrepare(dx: Float, dy: Float): Boolean {
40 | return listener.onDragPrepare(dx, dy)
41 | }
42 |
43 | override fun onDragStart() {
44 | listener.onDragStart()
45 | Jzvd.goOnPlayOnPause()
46 | video.setButtonProgressStatus(false)
47 | }
48 | })
49 | video.setUp(data.fullUrl, "", Jzvd.SCREEN_NORMAL)
50 | video.startVideoAfterPreloading()
51 | }
52 |
53 |
54 | override fun onRelease() {
55 | LogUtils.i("onRelease")
56 | Jzvd.releaseAllVideos()
57 | }
58 |
59 | override fun onPause() {
60 | LogUtils.i("onPause")
61 | JZUtils.clearSavedProgress(context.applicationContext, null)
62 | Jzvd.goOnPlayOnPause()
63 | }
64 |
65 | override fun onResume() {
66 | LogUtils.i("onResume")
67 | Jzvd.goOnPlayOnResume()
68 | }
69 |
70 | override fun onDestroy() {
71 | super.onDestroy()
72 | Jzvd.releaseAllVideos()
73 | }
74 |
75 |
76 | override fun getVideoViewId(): Int {
77 | return R.id.audio_video
78 | }
79 |
80 |
81 | override fun getVideoLayoutId(): Int {
82 | return R.layout.item_larger_video
83 | }
84 |
85 | }
--------------------------------------------------------------------------------
/LargerLoadVideo/src/main/java/com/example/largerloadvideo/MyVideoView.java:
--------------------------------------------------------------------------------
1 | package com.example.largerloadvideo;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.GestureDetector;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 |
9 | import com.starot.larger.view.image.OnLargerDragListener;
10 |
11 | import cn.jzvd.JzvdStd;
12 |
13 | public class MyVideoView extends JzvdStd {
14 |
15 |
16 | private GestureDetector gestureDetector;
17 |
18 | private LargerDrag largerDrag;
19 |
20 | private OnLargerDragListener listener;
21 |
22 | public MyVideoView(Context context) {
23 | super(context);
24 | }
25 |
26 | public MyVideoView(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 | }
29 |
30 | @Override
31 | public void onCompletion() {
32 | super.onCompletion();
33 | posterImageView.setVisibility(View.GONE);
34 | }
35 |
36 | @Override
37 | public int getLayoutId() {
38 | return R.layout.layout_jzstd_notitle;
39 | }
40 |
41 | @Override
42 | public boolean dispatchTouchEvent(MotionEvent ev) {
43 | if (gestureDetector != null && largerDrag != null) {
44 | gestureDetector.onTouchEvent(ev);
45 | if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
46 | if (listener != null && largerDrag.isDragging().get()) {
47 | largerDrag.isDragging().set(false);
48 | listener.onDragEnd();
49 | }
50 | }
51 | }
52 |
53 | return super.dispatchTouchEvent(ev);
54 | }
55 |
56 |
57 | public void setDragListener(OnLargerDragListener listener) {
58 | this.listener = listener;
59 | largerDrag = new LargerDrag(listener, getContext());
60 | gestureDetector = new GestureDetector(getContext(), largerDrag);
61 | }
62 |
63 | public void setButtonProgressStatus(boolean isVisibility) {
64 | bottomProgressBar.setVisibility(isVisibility ? VISIBLE : GONE);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/LargerLoadVideo/src/main/res/layout/item_larger_video.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/LargerLoadVideo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LargerLoadVideo/src/test/java/com/example/largerloadvideo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.largerloadvideo
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 高仿微信朋友圈,点击查看大图,放大 缩小,可自定义
5 |
6 |
7 |
8 |
9 | # 前言
10 |
11 | 之前写过一个 [高仿微信查看大图 放大缩小](https://allens.icu/posts/30acc017/) ,开源以后,有小伙伴提出疑问,想要加入视屏的功能,反思了一下,自己当初写这个轮子时候,为什么没有考虑到这个问题,后来经过修改,吧兼容视频放入轮子中
12 |
13 | > 举一反三
14 |
15 | - 除了保留当初设计的图片功能,还需要保留拓展,给以后的其他功能加入
16 | - 能够兼容各种模式在一起
17 | - 开发者只需要图片功能,不需要视屏,那么就不需要视屏的轮子,
18 | - 可以自行拓展想要的布局,和可修改的拓展性
19 |
20 |
21 |
22 |
23 | # 下载
24 |
25 | 这里将每个部分模块化,可以单独依赖,减少体积
26 |
27 | ```java
28 | allprojects {
29 | repositories {
30 | ...
31 | maven { url 'https://www.jitpack.io' }
32 | }
33 | }
34 | ```
35 |
36 | 必须添加的模块,也是基础模块
37 |
38 | ```java
39 | dependencies {
40 | implementation 'com.github.JiangHaiYang01.WeChatPhoto:Larger:0.0.5'
41 | }
42 | ```
43 |
44 | 最新版本 [](https://www.jitpack.io/#JiangHaiYang01/WeChatPhoto)
45 |
46 |
47 | 提供默认的图片加载器
48 |
49 | ```java
50 | implementation 'com.github.JiangHaiYang01.WeChatPhoto:LargerGlide:0.0.5'
51 | ```
52 |
53 | 提供默认的视屏加载器
54 | ```java
55 | implementation 'com.github.JiangHaiYang01.WeChatPhoto:LargerLoadVideo:0.0.5'
56 | ```
57 |
58 |
59 |
60 |
61 | # 使用介绍
62 |
63 | ## 加载列表类型的图片
64 |
65 |
66 | 自定义数据类型,需要继承 ``LargerBean`` 并且设置这个类型的是想要改成哪种模式,当前支持的模式 图片 和 视屏模式
67 |
68 | ```java
69 | @Parcelize
70 | class ImageBean : LargerBean() {
71 | override fun getType(): LargerDataEnum {
72 | return LargerDataEnum.IMAGE
73 | }
74 |
75 | }
76 | ```
77 |
78 | > 需要导入 图片加载器
79 |
80 | 在需要的地方启动 下面是最基础的用法, 就能实现之前版本的需求
81 |
82 | ```java
83 | Larger.create()
84 | .withImageMulti()//这里展示的是列表类型的
85 | .setImageLoad(GlideImageLoader(context)) //图片加载器
86 | .setIndex(position)//下标
87 | .setDuration(3000)//动画持续时间
88 | .setRecyclerView(recyclerView)//recyclerview
89 | .setData(data) //添加默认的数据源
90 | .start(context)
91 | ```
92 |
93 |
94 |
95 |
96 | 
97 |
98 |
99 | ## 加载视屏
100 |
101 | 和图片一样需要自定义数据类型
102 |
103 | ```
104 | @Parcelize
105 | class VideoBean : LargerBean() {
106 | override fun getType(): LargerDataEnum {
107 | return LargerDataEnum.Video
108 | }
109 |
110 | }
111 | ```
112 |
113 | 导入图片加载器和视屏加载器
114 |
115 | ```java
116 | Larger.create()
117 | .withVideoMulti()//这里展示的是列表类型的
118 | .setImageLoad(GlideImageLoader(context)) //图片加载器
119 | .setVideoLoad(LargerVideoLoad(context))//视屏加载器
120 | .setIndex(position)//下标
121 | .setRecyclerView(recyclerView)//recyclerview
122 | .setData(data) //添加默认的数据源
123 | .start(context)//跳转
124 |
125 | ```
126 |
127 |
128 |
129 |
130 | 
131 |
132 |
133 | # 更多属性
134 |
135 | ```
136 |
137 | //是否直接向上就能够拖动,微信直接向上不可以拖动,这里默认false
138 | var upCanMove: Boolean = DefConfig.def_up_can_move,
139 |
140 | //是否自动加载下一页,默认不自动加载下一页
141 | var loadNextFragment :Boolean = DefConfig.def_loadNextFragment,
142 |
143 | //是否打印日志
144 | var debug: Boolean = DefConfig.def_debug,
145 |
146 | //单个或者多个图片
147 | var images: List? = null,
148 |
149 | //列表
150 | var recyclerView: RecyclerView? = null,
151 |
152 | //使用的类型
153 | var largerType: LargerEnum = LargerEnum.LISTS,
154 |
155 | //持续时间
156 | var duration: Long = DefConfig.def_duration,
157 |
158 | //是否自动加载大图
159 | var automatic: Boolean = DefConfig.def_automatic,
160 |
161 | //最大缩放比例 (2 - f)
162 | var maxScale: Float = DefConfig.def_max_scale,
163 |
164 | //双击中间的大小 需要小于等于 max
165 | var mediumScale: Float = DefConfig.def_medium_scale,
166 |
167 | //最小缩放比例 (0.1f-0.7f)
168 | var minScale: Float = DefConfig.def_min_scale,
169 |
170 | //数据集合
171 | var data: List? = null,
172 |
173 | //当前的下标
174 | var position: Int = 0,
175 |
176 | //列表的布局
177 | var layoutId: Int? = null,
178 |
179 | //大图的ImageViewID
180 | var fullViewId: Int? = null,
181 |
182 | //获取加载框的id
183 | var progressId: Int? = null,
184 |
185 | //默认的背景颜色
186 | var backgroundColor: Int = DefConfig.def_back_color,
187 |
188 | //自定义
189 | var customImageLoadListener: OnCustomImageLoadListener? = null,
190 |
191 | //图片加载器
192 | var imageLoad: OnImageLoadListener? = null,
193 |
194 | //加载y样式
195 | var progressType: ImageProgressLoader.ProgressType = DefConfig.def_progress_type,
196 |
197 | //是否使用加载框
198 | var progressLoaderUse: Boolean = DefConfig.def_progress_use,
199 |
200 | //设置滑动方向
201 | var orientation: Orientation = DefConfig.orientation,
202 |
203 | //视屏加载器
204 | var videoLoad: OnVideoLoadListener? = null
205 | ```
206 |
207 |
208 |
209 | # 最后
210 |
211 | 整个架构用fragment 的方式去处理,方便后续的拓展,视屏部分使用的是 [JiaoZiVideoPlayer](https://github.com/Jzvd/JiaoZiVideoPlayer) 作为播放器,eumm 可以替换自己喜欢的播放器去处理,
212 |
213 |
214 |
215 | # github
216 |
217 | [Github](https://github.com/JiangHaiYang01/WeChatPhoto)
218 | [博客说明](https://allens.icu/posts/4a05dc12/#more)
219 |
220 |
221 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.2"
9 |
10 | defaultConfig {
11 | applicationId "com.starot.wechat_debug"
12 | minSdkVersion 21
13 | targetSdkVersion 30
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility 1.8
28 | targetCompatibility 1.8
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(dir: "libs", include: ["*.jar"])
34 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
35 | implementation 'androidx.core:core-ktx:1.3.1'
36 | implementation 'androidx.appcompat:appcompat:1.2.0'
37 | implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
38 | testImplementation 'junit:junit:4.13'
39 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
41 |
42 | implementation project(":Larger")
43 | //加载器
44 | implementation project(":LargerGlide")
45 | //进度
46 | // implementation project(":LargerProgress")
47 | //加载视屏模式
48 | implementation project(":LargerLoadVideo")
49 |
50 | implementation 'androidx.recyclerview:recyclerview:1.1.0'
51 |
52 | implementation 'com.github.bumptech.glide:glide:4.11.0'
53 | annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
54 |
55 |
56 | // debugImplementation because LeakCanary should only run in debug builds.
57 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
58 |
59 | }
--------------------------------------------------------------------------------
/app/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
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/starot/wechat/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat
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.starot.wechat", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.widget.Button
6 | import androidx.appcompat.app.AppCompatActivity
7 | import com.bumptech.glide.Glide
8 | import com.starot.wechat.activity.*
9 | import kotlinx.android.synthetic.main.activity_main.*
10 |
11 | class MainActivity : BaseAct() {
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | setContentView(R.layout.activity_main)
15 |
16 | val arrayListOf = arrayListOf(
17 | "图片列表布局",
18 | "加载原图自定义处理",
19 | "加载框的样式1",
20 | "加载框的样式2",
21 | "竖着滑动",
22 | "设置缩放大小",
23 | "设置背景颜色",
24 | "加载列表视屏",
25 | "图片视屏混合",
26 | "单个图片",
27 | "单个视屏",
28 | "清理缓存"
29 | )
30 |
31 | for (index in arrayListOf.indices) {
32 | val button = Button(this)
33 | button.text = arrayListOf[index]
34 | main_ll.addView(button)
35 | button.setOnClickListener {
36 |
37 |
38 | when (index) {
39 | 0 -> {
40 | val intent = Intent(this, ImageListAct::class.java)
41 | intent.putExtra("name", arrayListOf[index])
42 | intent.putExtra("type", 0)
43 | startActivity(intent)
44 | }
45 | 1 -> {
46 | val intent = Intent(this, ImageListAct::class.java)
47 | intent.putExtra("name", arrayListOf[index])
48 | intent.putExtra("type", 1)
49 | startActivity(intent)
50 | }
51 |
52 | 2 -> {
53 |
54 | Glide.get(this).clearMemory()
55 | Thread(Runnable { Glide.get(this).clearDiskCache() }).start()
56 |
57 | val intent = Intent(this, ImageListAct::class.java)
58 | intent.putExtra("name", arrayListOf[index])
59 | intent.putExtra("type", 2)
60 | startActivity(intent)
61 | }
62 | 3 -> {
63 |
64 | Glide.get(this).clearMemory()
65 | Thread(Runnable { Glide.get(this).clearDiskCache() }).start()
66 |
67 | val intent = Intent(this, ImageListAct::class.java)
68 | intent.putExtra("name", arrayListOf[index])
69 | intent.putExtra("type", 3)
70 | startActivity(intent)
71 | }
72 | 4 -> {
73 | val intent = Intent(this, ImageListAct::class.java)
74 | intent.putExtra("name", arrayListOf[index])
75 | intent.putExtra("type", 4)
76 | startActivity(intent)
77 | }
78 | 5 -> {
79 | val intent = Intent(this, ImageListAct::class.java)
80 | intent.putExtra("name", arrayListOf[index])
81 | intent.putExtra("type", 5)
82 | startActivity(intent)
83 | }
84 | 6 -> {
85 | val intent = Intent(this, ImageListAct::class.java)
86 | intent.putExtra("name", arrayListOf[index])
87 | intent.putExtra("type", 6)
88 | startActivity(intent)
89 | }
90 | 7 -> {
91 | val intent = Intent(this, VideoListAct::class.java)
92 | intent.putExtra("name", arrayListOf[index])
93 | intent.putExtra("type", 0)
94 | startActivity(intent)
95 | }
96 |
97 | 8 -> {
98 | val intent = Intent(this, HybridListAct::class.java)
99 | intent.putExtra("name", arrayListOf[index])
100 | intent.putExtra("type", 0)
101 | startActivity(intent)
102 | }
103 |
104 | 9 -> {
105 | val intent = Intent(this, SingleImageAct::class.java)
106 | intent.putExtra("name", arrayListOf[index])
107 | intent.putExtra("type", 0)
108 | startActivity(intent)
109 | }
110 | 10 -> {
111 | val intent = Intent(this, SingleAudioAct::class.java)
112 | intent.putExtra("name", arrayListOf[index])
113 | intent.putExtra("type", 0)
114 | startActivity(intent)
115 | }
116 |
117 | arrayListOf.size - 1 -> {
118 | Glide.get(this).clearMemory()
119 | Thread(Runnable { Glide.get(this).clearDiskCache() }).start()
120 | return@setOnClickListener
121 | }
122 | }
123 |
124 |
125 | }
126 | }
127 |
128 | }
129 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/activity/BaseAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.starot.larger.utils.StatusBarTools
6 | import com.starot.wechat.R
7 |
8 | open class BaseAct :AppCompatActivity(){
9 |
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | StatusBarTools.setStatusBar(this)
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/activity/HybridListAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.recyclerview.widget.GridLayoutManager
6 | import com.starot.larger.bean.LargerBean
7 | import com.starot.wechat.R
8 | import com.starot.wechat.adapter.HybridListAdapter
9 | import com.starot.wechat.adapter.ImageListAdapter
10 | import com.starot.wechat.bean.ImageBean
11 | import com.starot.wechat.bean.VideoBean
12 | import com.starot.wechat.utils.Urls
13 | import kotlinx.android.synthetic.main.activity_image_list.*
14 |
15 |
16 | class HybridListAct : BaseAct() {
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | setContentView(R.layout.activity_image_list)
21 | title = intent.getStringExtra("name")
22 | val type = intent.getIntExtra("type", 0)
23 |
24 | val list = arrayListOf()
25 |
26 | val targetButtonSmall = Urls().getTargetButtonSmall()
27 | val targetButtonTarget = Urls().getTargetButtonTarget()
28 | for (index in targetButtonSmall.indices) {
29 | val element = ImageBean()
30 | element.fullUrl = targetButtonTarget[index]
31 | element.thumbnailsUrl = targetButtonSmall[index]
32 | list.add(element)
33 | }
34 |
35 |
36 | val audioImage = Urls().getAudioImage()
37 | val audio = Urls().getAudio()
38 | for (index in audioImage.indices) {
39 | val element = VideoBean()
40 | element.fullUrl = audio[index]
41 | element.thumbnailsUrl = audioImage[index]
42 | list.add(element)
43 | }
44 |
45 |
46 |
47 | act_list_ry.layoutManager = GridLayoutManager(this, 2)
48 | act_list_ry.adapter = HybridListAdapter(list, act_list_ry, type)
49 | }
50 |
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/activity/ImageListAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.recyclerview.widget.GridLayoutManager
6 | import com.starot.wechat.R
7 | import com.starot.wechat.adapter.ImageListAdapter
8 | import com.starot.wechat.bean.ImageBean
9 | import com.starot.wechat.utils.Urls
10 | import kotlinx.android.synthetic.main.activity_image_list.*
11 |
12 |
13 | class ImageListAct : BaseAct() {
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_image_list)
18 | title = intent.getStringExtra("name")
19 | val type = intent.getIntExtra("type", 0)
20 |
21 | val list = arrayListOf()
22 |
23 | val targetButtonSmall = Urls().getTargetButtonSmall()
24 | val targetButtonTarget = Urls().getTargetButtonTarget()
25 | for (index in targetButtonSmall.indices) {
26 | val element = ImageBean()
27 | element.fullUrl = targetButtonTarget[index]
28 | element.thumbnailsUrl = targetButtonSmall[index]
29 | list.add(element)
30 | }
31 | act_list_ry.layoutManager = GridLayoutManager(this, 2)
32 | act_list_ry.adapter = ImageListAdapter(list, act_list_ry, type)
33 | }
34 |
35 |
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/activity/SingleAudioAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.activity
2 |
3 | import android.os.Bundle
4 | import com.allens.largerglide.GlideImageLoader
5 | import com.bumptech.glide.Glide
6 | import com.example.largerloadvideo.LargerVideoLoad
7 | import com.starot.larger.Larger
8 | import com.starot.wechat.R
9 | import com.starot.wechat.bean.VideoBean
10 | import com.starot.wechat.utils.Urls
11 | import kotlinx.android.synthetic.main.activity_image_single.*
12 |
13 |
14 | class SingleAudioAct : BaseAct() {
15 |
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_image_single)
20 | title = intent.getStringExtra("name")
21 |
22 |
23 | val list = arrayListOf()
24 |
25 | val targetButtonSmall = Urls().getAudioImage()
26 | val targetButtonTarget = Urls().getAudio()
27 | for (index in targetButtonSmall.indices) {
28 | if (index == 2) {
29 | val element = VideoBean()
30 | element.fullUrl = targetButtonTarget[index]
31 | element.thumbnailsUrl = targetButtonSmall[index]
32 | list.add(element)
33 |
34 | }
35 | }
36 |
37 | Glide.with(this).load(list[0].thumbnailsUrl).into(src_image)
38 |
39 | src_image.setOnClickListener {
40 | Larger.create()
41 | .withVideoSingle()//这里展示的是列表类型的
42 | .setImageLoad(GlideImageLoader(this)) //图片加载器
43 | .setDuration(3000)//动画持续时间
44 | .setVideoLoad(LargerVideoLoad(this))
45 | .setImage(src_image)//设置imageView
46 | .setData(list[0]) //添加默认的数据源
47 | .start(this)
48 | }
49 | }
50 |
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/activity/SingleImageAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.activity
2 |
3 | import android.os.Bundle
4 | import com.allens.largerglide.GlideImageLoader
5 | import com.bumptech.glide.Glide
6 | import com.starot.larger.Larger
7 | import com.starot.wechat.R
8 | import com.starot.wechat.bean.ImageBean
9 | import com.starot.wechat.utils.Urls
10 | import kotlinx.android.synthetic.main.activity_image_single.*
11 |
12 |
13 | class SingleImageAct : BaseAct() {
14 |
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | setContentView(R.layout.activity_image_single)
19 | title = intent.getStringExtra("name")
20 |
21 |
22 | val list = arrayListOf()
23 |
24 | val targetButtonSmall = Urls().getTargetButtonSmall()
25 | val targetButtonTarget = Urls().getTargetButtonTarget()
26 | for (index in targetButtonSmall.indices) {
27 | if (index == 1) {
28 | break
29 | }
30 | val element = ImageBean()
31 | element.fullUrl = targetButtonTarget[index]
32 | element.thumbnailsUrl = targetButtonSmall[index]
33 | list.add(element)
34 |
35 | }
36 |
37 | Glide.with(this).load(list[0].thumbnailsUrl).into(src_image)
38 |
39 | src_image.setOnClickListener {
40 | Larger.create()
41 | .withImageSingle()//这里展示的是单个图片
42 | .setImageLoad(GlideImageLoader(this)) //图片加载器
43 | .setDuration(300)//动画持续时间
44 | .setImage(src_image)//设置imageView
45 | .setData(list[0]) //添加默认的数据源
46 | .start(this)
47 | }
48 | }
49 |
50 |
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/activity/VideoListAct.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.recyclerview.widget.GridLayoutManager
6 | import com.starot.wechat.R
7 | import com.starot.wechat.adapter.VideoListAdapter
8 | import com.starot.wechat.bean.VideoBean
9 | import com.starot.wechat.utils.Urls
10 | import kotlinx.android.synthetic.main.activity_image_list.*
11 |
12 |
13 | class VideoListAct : BaseAct() {
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_image_list)
18 | title = intent.getStringExtra("name")
19 | val type = intent.getIntExtra("type", 0)
20 | val list = arrayListOf()
21 |
22 | val targetButtonSmall = Urls().getAudioImage()
23 | val targetButtonTarget = Urls().getAudio()
24 | for (index in targetButtonSmall.indices) {
25 | val element = VideoBean()
26 | element.fullUrl = targetButtonTarget[index]
27 | element.thumbnailsUrl = targetButtonSmall[index]
28 | list.add(element)
29 | }
30 | act_list_ry.layoutManager = GridLayoutManager(this, 2)
31 | act_list_ry.adapter = VideoListAdapter(list, act_list_ry,type)
32 | }
33 |
34 |
35 |
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/adapter/HybridListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.adapter
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.ImageView
9 | import android.widget.TextView
10 | import androidx.recyclerview.widget.RecyclerView
11 | import com.allens.largerglide.GlideImageLoader
12 | import com.bumptech.glide.Glide
13 | import com.example.largerloadvideo.LargerVideoLoad
14 | import com.starot.larger.Larger
15 | import com.starot.larger.bean.LargerBean
16 | import com.starot.larger.enums.Orientation
17 | import com.starot.larger.impl.OnCustomImageLoadListener
18 | import com.starot.larger.impl.OnImageCacheListener
19 | import com.starot.larger.impl.OnImageLoadListener
20 | import com.starot.wechat.R
21 | import com.starot.wechat.bean.ImageBean
22 | import kotlin.collections.ArrayList
23 |
24 |
25 | class HybridListAdapter(
26 | private val data: ArrayList,
27 | private val recyclerView: RecyclerView,
28 | private val type: Int,
29 | ) :
30 | RecyclerView.Adapter() {
31 |
32 | private lateinit var context: Context
33 |
34 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
35 | var image: ImageView = itemView.findViewById(R.id.item_image)
36 | }
37 |
38 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
39 | val v: View =
40 | LayoutInflater.from(parent.context).inflate(R.layout.item_image, parent, false)
41 | context = parent.context
42 | return ViewHolder(v)
43 | }
44 |
45 | override fun getItemCount(): Int {
46 | return data.size
47 | }
48 |
49 |
50 |
51 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
52 | Glide.with(context)
53 | .load(data[position].thumbnailsUrl)
54 | .into(holder.image)
55 |
56 |
57 | holder.itemView.setOnClickListener {
58 | val withListType = Larger.create()
59 | .withListType()//这里展示的是列表类型的
60 | .setImageLoad(GlideImageLoader(context)) //图片加载器
61 | .setVideoLoad(LargerVideoLoad(context))
62 | .setIndex(position)//下标
63 | .setDuration(300)//动画持续时间
64 | // .setProgress(ProgressLoader(ProgressLoader.ProgressType.FULL)) //添加进度显示
65 | .setRecyclerView(recyclerView)//recyclerview
66 | .setData(data) //添加默认的数据源
67 | withListType.start(context)
68 | }
69 |
70 | }
71 |
72 |
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/adapter/VideoListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.adapter
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.ImageView
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.allens.largerglide.GlideImageLoader
10 | import com.bumptech.glide.Glide
11 | import com.example.largerloadvideo.LargerVideoLoad
12 | import com.starot.larger.Larger
13 | import com.starot.larger.enums.Orientation
14 | import com.starot.wechat.R
15 | import com.starot.wechat.bean.VideoBean
16 | import kotlin.collections.ArrayList
17 |
18 |
19 | class VideoListAdapter(
20 | private val data: ArrayList,
21 | private val recyclerView: RecyclerView,
22 | private val type: Int,
23 | ) :
24 | RecyclerView.Adapter() {
25 |
26 | private lateinit var context: Context
27 |
28 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
29 | var image: ImageView = itemView.findViewById(R.id.item_image)
30 | }
31 |
32 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
33 | val v: View =
34 | LayoutInflater.from(parent.context).inflate(R.layout.item_image, parent, false)
35 | context = parent.context
36 | return ViewHolder(v)
37 | }
38 |
39 | override fun getItemCount(): Int {
40 | return data.size
41 | }
42 |
43 |
44 |
45 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
46 | Glide.with(context)
47 | .load(data[position].thumbnailsUrl)
48 | .into(holder.image)
49 |
50 |
51 |
52 | holder.itemView.setOnClickListener {
53 | val withListType = Larger.create()
54 | .withVideoMulti()//这里展示的是列表类型的
55 | .setImageLoad(GlideImageLoader(context)) //图片加载器
56 | .setVideoLoad(LargerVideoLoad(context))//视屏加载器
57 | .setIndex(position)//下标
58 | .setDebug(true)
59 | .setUpCanMove(true)
60 | .setDuration(3000)//动画持续时间
61 | .setRecyclerView(recyclerView)//recyclerview
62 | .setData(data) //添加默认的数据源
63 | when (type) {
64 | 0 -> {
65 | }
66 | }
67 | withListType.start(context)
68 | }
69 |
70 | }
71 |
72 |
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/bean/ImageBean.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.bean
2 |
3 | import com.starot.larger.bean.LargerBean
4 | import com.starot.larger.enums.LargerDataEnum
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | class ImageBean : LargerBean() {
9 | override fun getType(): LargerDataEnum {
10 | return LargerDataEnum.IMAGE
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/bean/VideoBean.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.bean
2 |
3 | import com.starot.larger.bean.LargerBean
4 | import com.starot.larger.enums.LargerDataEnum
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | class VideoBean : LargerBean() {
9 | override fun getType(): LargerDataEnum {
10 | return LargerDataEnum.Video
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/starot/wechat/utils/Urls.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat.utils
2 |
3 | import java.util.ArrayList
4 |
5 | open class Urls {
6 | fun getTargetButtonTarget(): List {
7 | val list: MutableList =
8 | ArrayList()
9 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643441654-assets/web-upload/771e09b0-aaf9-4308-bae0-cd5b3cb98817.jpeg")
10 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643441557-assets/web-upload/94ed7774-2bed-4dbe-be54-080c2f8939a1.jpeg")
11 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643441632-assets/web-upload/84d01b3f-7f28-4125-b3c7-8e5b5b15c0cb.jpeg")
12 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4k2flh3j31c00u0gs8.jpg")
13 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4m99esij30u01hcn1x.jpg")
14 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4onuhofj30sg1ek43l.jpg")
15 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4pi32qcj30qe110gob.jpg")
16 |
17 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643441654-assets/web-upload/771e09b0-aaf9-4308-bae0-cd5b3cb98817.jpeg")
18 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643441557-assets/web-upload/94ed7774-2bed-4dbe-be54-080c2f8939a1.jpeg")
19 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643441632-assets/web-upload/84d01b3f-7f28-4125-b3c7-8e5b5b15c0cb.jpeg")
20 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4k2flh3j31c00u0gs8.jpg")
21 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4m99esij30u01hcn1x.jpg")
22 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4onuhofj30sg1ek43l.jpg")
23 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4pi32qcj30qe110gob.jpg")
24 | return list
25 | }
26 |
27 | fun getTargetButtonSmall(): List {
28 | val list: MutableList =
29 | ArrayList()
30 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643585276-assets/web-upload/6e2520de-544d-45b6-9892-ff228d14e175.jpeg")
31 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643585330-assets/web-upload/85629ce4-bacf-4ab4-af6f-5a0a67931b68.jpeg")
32 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643585344-assets/web-upload/3b178609-8aef-48f3-9ebc-41537149f13b.jpeg")
33 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4l9gekoj305c03c3yf.jpg")
34 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4mwvc60j303005c0sl.jpg")
35 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4onuhofj30sg1ek43l.jpg")
36 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4pxkzaxj302n03p743.jpg")
37 |
38 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643585276-assets/web-upload/6e2520de-544d-45b6-9892-ff228d14e175.jpeg")
39 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643585330-assets/web-upload/85629ce4-bacf-4ab4-af6f-5a0a67931b68.jpeg")
40 | list.add("https://cdn.nlark.com/yuque/0/2020/jpeg/252337/1592643585344-assets/web-upload/3b178609-8aef-48f3-9ebc-41537149f13b.jpeg")
41 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4l9gekoj305c03c3yf.jpg")
42 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4mwvc60j303005c0sl.jpg")
43 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4onuhofj30sg1ek43l.jpg")
44 | list.add("https://tva1.sinaimg.cn/large/007S8ZIlly1giy4pxkzaxj302n03p743.jpg")
45 | return list
46 | }
47 |
48 | fun getAudioImage(): List {
49 | val list: MutableList =
50 | ArrayList()
51 | list.add("https://gitee.com/_Allens/BlogImage/raw/master/image/20200901152310.png")
52 | list.add("https://gitee.com/_Allens/BlogImage/raw/master/image/20200901152900.png")
53 | list.add("https://gitee.com/_Allens/BlogImage/raw/master/image/20200901153024.png")
54 | list.add("http://jzvd-pic.nathen.cn/jzvd-pic/00b026e7-b830-4994-bc87-38f4033806a6.jpg")
55 | list.add("http://jzvd-pic.nathen.cn/jzvd-pic/1d935cc5-a1e7-4779-bdfa-20fd7a60724c.jpg")
56 | list.add("http://jzvd-pic.nathen.cn/jzvd-pic/a019ffc1-556c-4a85-b70c-b1b49811d577.jpg")
57 | list.add("http://jzvd-pic.nathen.cn/jzvd-pic/6fc2ae91-36e2-44c5-bb10-29ae5d5c678c.png")
58 | list.add("http://jzvd-pic.nathen.cn/jzvd-pic/f03cee95-9b78-4dd5-986f-d162c06c385c.png")
59 | list.add("http://jzvd-pic.nathen.cn/jzvd-pic/e7ea659f-c3d2-4979-9ea5-f993b05e5930.png")
60 |
61 | return list
62 | }
63 |
64 |
65 | fun getAudio(): List {
66 | val list: MutableList =
67 | ArrayList()
68 | list.add("https://mp4.vjshi.com/2018-12-22/f4de0fcda0cf34707cf89d8d38825692.mp4")
69 | list.add("https://mp4.vjshi.com/2020-08-28/f17ccf7a47b0d96d8a033397f6eac7f5.mp4")
70 | list.add("https://mp4.vjshi.com/2020-03-17/6cf7d4f0ad7a573bf6d684515c4ee4e7.mp4")
71 | list.add("http://jzvd.nathen.cn/c494b340ff704015bb6682ffde3cd302/64929c369124497593205a4190d7d128-5287d2089db37e62345123a1be272f8b.mp4")
72 | list.add("http://jzvd.nathen.cn/63f3f73712544394be981d9e4f56b612/69c5767bb9e54156b5b60a1b6edeb3b5-5287d2089db37e62345123a1be272f8b.mp4")
73 | list.add("http://jzvd.nathen.cn/b201be3093814908bf987320361c5a73/2f6d913ea25941ffa78cc53a59025383-5287d2089db37e62345123a1be272f8b.mp4")
74 | list.add("http://jzvd.nathen.cn/d2438fd1c37c4618a704513ad38d68c5/68626a9d53ca421c896ac8010f172b68-5287d2089db37e62345123a1be272f8b.mp4")
75 | list.add("http://jzvd.nathen.cn/25a8d119cfa94b49a7a4117257d8ebd7/f733e65a22394abeab963908f3c336db-5287d2089db37e62345123a1be272f8b.mp4")
76 | list.add("http://jzvd.nathen.cn/7512edd1ad834d40bb5b978402274b1a/9691c7f2d7b74b5e811965350a0e5772-5287d2089db37e62345123a1be272f8b.mp4")
77 | list.add("http://jzvd.nathen.cn/c6e3dc12a1154626b3476d9bf3bd7266/6b56c5f0dc31428083757a45764763b0-5287d2089db37e62345123a1be272f8b.mp4")
78 | return list
79 | }
80 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_image_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_image_single.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_single.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_custom_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WeChat
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/test/java/com/starot/wechat/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.starot.wechat
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = "1.4.0"
4 | repositories {
5 | // maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'}
6 | google()
7 | jcenter()
8 | mavenCentral()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:4.0.1'
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | jcenter()
22 | // maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'}
23 | maven { url 'https://www.jitpack.io' }
24 | google()
25 | mavenCentral()
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiangHaiYang01/WeChatPhoto/e1f5739ae1ba02d22344073e81ef1e5c51511c61/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jul 02 09:35:20 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':LargerGlide'
2 | include ':LargerLoadVideo'
3 | include ':Larger'
4 | include ':app'
5 | rootProject.name = "WeChat"
--------------------------------------------------------------------------------