├── .gitignore
├── README.md
├── Screenrecorder-2017-11-21-21-40-47-458_20171121214225.gif
├── Screenrecorder-2017-12-24-20-59-09-590_20171224205953.gif
├── Screenrecorder-2017-12-24-20-59-24-806_20171224205930.gif
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── kalu
│ │ └── image
│ │ ├── CustomDotIndexProvider.java
│ │ ├── CustomLoadingUIProvider.java
│ │ ├── Data.java
│ │ ├── IndicatorView.java
│ │ ├── MainActivity.java
│ │ ├── MainActivity2.java
│ │ ├── MainActivity3.java
│ │ ├── MainActivity4.java
│ │ ├── MainActivity5.java
│ │ ├── MessageAdapter.java
│ │ ├── MessagePicturesLayout.java
│ │ ├── MyGlideModule.java
│ │ ├── SimpleLoader.java
│ │ ├── SpaceItemDecoration.java
│ │ ├── SquareImageView.java
│ │ ├── TestActivity.java
│ │ └── Utils.java
│ └── res
│ ├── drawable
│ ├── b_gray_dcdcdc_oval.xml
│ ├── b_yellow_ffb100_oval.xml
│ ├── default_avatar.xml
│ ├── default_picture.xml
│ └── dice_action.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── activity_main2.xml
│ ├── activity_main3.xml
│ ├── activity_main4.xml
│ ├── activity_main5.xml
│ ├── activity_test.xml
│ ├── recycler_main_message.xml
│ └── recycler_message_picture.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
│ ├── dice_action_0.png
│ ├── dice_action_1.png
│ ├── dice_action_2.png
│ ├── dice_action_3.png
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── raw
│ └── image.jpg
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── lib_glide
├── .gitignore
├── build.gradle
├── lib_glide.iml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── lib
│ └── kalu
│ └── glide
│ ├── LibDataFetcher.java
│ ├── LibGlideUrl.java
│ ├── LibInterceptor.java
│ ├── LibModelLoader.java
│ ├── LibResponseBody.java
│ ├── ProgressListener.java
│ └── util
│ └── GlideUtil.java
├── lib_image
├── .gitignore
├── build.gradle
├── lib_image.iml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── lib
│ │ └── kalu
│ │ └── image
│ │ └── watch
│ │ ├── ImageWatcher.java
│ │ ├── ImageWatcherHelper.java
│ │ ├── ProgressView.java
│ │ └── ViewState.java
│ └── res
│ ├── mipmap-xxhdpi
│ └── error_picture.png
│ └── values
│ ├── ids.xml
│ ├── strings.xml
│ └── style.xml
├── local.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.iml
2 | /.idea
3 | /.gradle
4 | ### Android template
5 | # Built application files
6 | *.apk
7 | *.ap_
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Java class files
13 | *.class
14 |
15 | # Generated files
16 | bin/
17 | gen/
18 | out/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | .idea/caches
48 |
49 | # Keystore files
50 | # Uncomment the following line if you do not want to check your keystore files in.
51 | #*.jks
52 |
53 | # External native build folder generated in Android Studio 2.2 and later
54 | .externalNativeBuild
55 |
56 | # Google Services (e.g. APIs or Firebase)
57 | google-services.json
58 |
59 | # Freeline
60 | freeline.py
61 | freeline/
62 | freeline_project_description.json
63 |
64 | # fastlane
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 | fastlane/readme.md
70 |
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | 旧版本, tag 1.0
3 | 2019年2月18日: 重构中...
4 | ```
5 |
--------------------------------------------------------------------------------
/Screenrecorder-2017-11-21-21-40-47-458_20171121214225.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/Screenrecorder-2017-11-21-21-40-47-458_20171121214225.gif
--------------------------------------------------------------------------------
/Screenrecorder-2017-12-24-20-59-09-590_20171224205953.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/Screenrecorder-2017-12-24-20-59-09-590_20171224205953.gif
--------------------------------------------------------------------------------
/Screenrecorder-2017-12-24-20-59-24-806_20171224205930.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/Screenrecorder-2017-12-24-20-59-24-806_20171224205930.gif
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDevelopmentDebugSources
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 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | buildToolsVersion '28.0.3'
6 | defaultConfig {
7 | minSdkVersion 15
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | debug {
19 | signingConfig signingConfigs.debug
20 | ext.alwaysUpdateBuildId = false // 编译加速
21 | buildConfigField "long", "BUILD_TIMESTAMP", "000000000" // 编译加速
22 | }
23 | }
24 |
25 | if (project.hasProperty("devBuild")) { // 编译加速
26 | aaptOptions.cruncherEnabled = false // 编译加速
27 | }
28 |
29 | dexOptions { // 编译加速
30 | }
31 |
32 | flavorDimensions "default" // 编译加速
33 | productFlavors { // 编译加速
34 | development { // 编译加速
35 | minSdkVersion 21 // 编译加速
36 | dimension "default" // 编译加速
37 | resConfigs("en", "xxhdpi") // 编译加速
38 | }
39 | production { // 编译加速
40 | dimension "default" // 编译加速
41 | }
42 | }
43 | compileOptions {
44 | sourceCompatibility JavaVersion.VERSION_1_8
45 | targetCompatibility JavaVersion.VERSION_1_8
46 | }
47 | }
48 |
49 | dependencies {
50 | implementation 'com.android.support:appcompat-v7:28.+'
51 | implementation 'com.android.support:recyclerview-v7:28.+'
52 | implementation 'com.github.bumptech.glide:glide:4.9.0'
53 | implementation "com.github.bumptech.glide:okhttp3-integration:4.9.0"
54 | implementation 'com.android.support.constraint:constraint-layout:1.1.1'
55 | implementation project(path: ':lib_image')
56 | }
57 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/CustomDotIndexProvider.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.util.DisplayMetrics;
6 | import android.view.Gravity;
7 | import android.view.View;
8 | import android.view.WindowManager;
9 | import android.widget.FrameLayout;
10 |
11 | import lib.kalu.image.watch.ImageWatcher;
12 |
13 | import java.util.List;
14 |
15 | public class CustomDotIndexProvider implements ImageWatcher.IndexProvider {
16 | private boolean initLayout;
17 | private IndicatorView indicatorView;
18 |
19 | @Override
20 | public View initialView(Context context) {
21 | FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
22 | lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
23 | indicatorView = new IndicatorView(context);
24 | indicatorView.setLayoutParams(lp);
25 |
26 | DisplayMetrics d = new DisplayMetrics();
27 | ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
28 | .getDefaultDisplay().getMetrics(d);
29 | int size = (int) (20 * d.density + 0.5);
30 | lp.setMargins(0, 0, 0, size);
31 |
32 | initLayout = false;
33 | return indicatorView;
34 | }
35 |
36 | @Override
37 | public void onPageChanged(ImageWatcher imageWatcher, int position, List dataList) {
38 | if (!initLayout) {
39 | initLayout = true;
40 | indicatorView.reset(dataList.size(), position, R.drawable.b_gray_dcdcdc_oval, R.drawable.b_yellow_ffb100_oval);
41 | } else {
42 | indicatorView.select(position, R.drawable.b_gray_dcdcdc_oval, R.drawable.b_yellow_ffb100_oval);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/CustomLoadingUIProvider.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.graphics.drawable.AnimationDrawable;
4 | import android.view.Gravity;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.FrameLayout;
8 | import android.widget.ImageView;
9 |
10 | import lib.kalu.image.watch.ImageWatcher;
11 |
12 | public class CustomLoadingUIProvider implements ImageWatcher.LoadingUIProvider {
13 | private final FrameLayout.LayoutParams lpCenterInParent = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
14 |
15 | @Override
16 | public View initialView(ViewGroup parent) {
17 | ImageView load = new ImageView(parent.getContext());
18 | lpCenterInParent.gravity = Gravity.CENTER;
19 | load.setLayoutParams(lpCenterInParent);
20 | load.setImageResource(R.drawable.dice_action);
21 | return load;
22 | }
23 |
24 | @Override
25 | public void start(View loadView) {
26 | loadView.setVisibility(View.VISIBLE);
27 | ((AnimationDrawable) ((ImageView) loadView).getDrawable()).start();
28 | }
29 |
30 | @Override
31 | public void stop(View loadView) {
32 | ((AnimationDrawable) ((ImageView) loadView).getDrawable()).stop();
33 | loadView.setVisibility(View.GONE);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/Data.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.net.Uri;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | public class Data {
10 |
11 | private String avatar;
12 | private String nickname ;
13 | private String createTime;
14 | private String content;
15 | private List pictureList;
16 | private List pictureThumbList;
17 |
18 | public static List get() {
19 | List dataList = new ArrayList<>();
20 |
21 | Data data1 = new Data();
22 | data1.avatar = "http://b162.photo.store.qq.com/psb?/V14EhGon4cZvmh/z2WukT5EhNE76WtOcbqPIgwM2Wxz4Tb7Nub.rDpsDgo!/b/dOaanmAaKQAA";
23 | data1.nickname = "萌新-lpe";
24 | data1.createTime = "昨天 11:21";
25 | data1.content = "开司还是那么帅";
26 | data1.pictureList = Arrays.asList(
27 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664940_9893.jpg"),
28 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664940_3308.jpg"),
29 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664927_3920.png"),
30 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664926_8360.png"),
31 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664926_6184.png"),
32 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664925_8382.png"),
33 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664925_2087.jpg"),
34 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664777_5730.png"),
35 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664741_1378.jpg"),
36 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671689_9534.png"),
37 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671689_2126.png"),
38 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671703_7890.png"),
39 | Uri.parse("http://img.my.csdn.net/uploads/201707/27/1501118577_9169.jpg") // 超出屏幕宽度大尺寸图测试
40 | );
41 | data1.pictureThumbList = Arrays.asList(
42 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647899_2806.jpg"),
43 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647798_4500.jpg"),
44 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647897_1367.png"),
45 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484650736_2101.png"),
46 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647701_9893.png"),
47 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484650700_2514.png"),
48 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647930_5139.jpg"),
49 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647929_8108.png"),
50 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647897_1978.jpg"),
51 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647898_4474.png"),
52 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647930_7735.png"),
53 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647929_9591.png"),
54 | Uri.parse("http://img.my.csdn.net/uploads/201707/27/1501118720_9504.jpg") // 超出屏幕宽度大尺寸图测试
55 | );
56 |
57 |
58 | Data data2 = new Data();
59 | data2.avatar = "http://b167.photo.store.qq.com/psb?/V14EhGon2OmAUI/hQN450lNoDPF.dO82PVKEdFw0Qj5qyGeyN9fByKgWd0!/m/dJWKmWNZEwAAnull";
60 | data2.nickname = "苦涩";
61 | data2.createTime = "昨天 09:59";
62 | data2.content = "唐僧还是厉害啊。为什么?有宝马";
63 | data2.pictureList = Arrays.asList(
64 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483664741_7475.png")
65 | );
66 | data2.pictureThumbList = Arrays.asList(
67 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647799_1689.png")
68 | );
69 |
70 | Data data3 = new Data();
71 | data3.avatar = "http://b167.photo.store.qq.com/psb?/V14EhGon2OmAUI/hQN450lNoDPF.dO82PVKEdFw0Qj5qyGeyN9fByKgWd0!/m/dJWKmWNZEwAAnull";
72 | data3.nickname = "empty";
73 | data3.createTime = "昨天 08:12";
74 | data3.content = "各种眼神";
75 | data3.pictureList = Arrays.asList(
76 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671690_1970.png"),
77 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671690_6902.png"),
78 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671702_6499.png"),
79 | Uri.parse("http://img.my.csdn.net/uploads/201701/06/1483671702_2352.jpg")
80 | );
81 | data3.pictureThumbList = Arrays.asList(
82 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484650701_4150.png"),
83 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484650719_9275.png"),
84 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647702_8420.png"),
85 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647930_4474.jpg")
86 | );
87 |
88 | Data data4 = new Data();
89 | data4.avatar = "http://b167.photo.store.qq.com/psb?/V14EhGon2OmAUI/hQN450lNoDPF.dO82PVKEdFw0Qj5qyGeyN9fByKgWd0!/m/dJWKmWNZEwAAnull";
90 | data4.nickname = "empty";
91 | data4.createTime = "昨天 06:00";
92 | data4.content = "人与人间的信任,就像是纸片,一旦破损,就不会再回到原来的样子。";
93 | data4.pictureList = Arrays.asList(
94 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296303_7395.png"),
95 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296122_9613.jpg"),
96 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296303_6984.png")
97 | );
98 | data4.pictureThumbList = Arrays.asList(
99 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647817_3557.png"),
100 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647818_9583.jpg"),
101 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647817_7305.png")
102 | );
103 |
104 | Data data5 = new Data();
105 | data5.avatar = "http://qlogo3.store.qq.com/qzone/383559698/383559698/100?1416542262";
106 | data5.nickname = "越线龙马";
107 | data5.createTime = "前天 14:61";
108 | data5.content = "雪.触之即化..愿永久飘零";
109 | data5.pictureList = Arrays.asList(
110 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296288_3031.png"),
111 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296303_5044.jpg")
112 | );
113 | data5.pictureThumbList = Arrays.asList(
114 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647278_8869.png"),
115 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647702_1117.jpg")
116 | );
117 |
118 | Data data6 = new Data();
119 | data6.avatar = "http://b162.photo.store.qq.com/psb?/V14EhGon4cZvmh/z2WukT5EhNE76WtOcbqPIgwM2Wxz4Tb7Nub.rDpsDgo!/b/dOaanmAaKQAA";
120 | data6.nickname = "顺子要不起";
121 | data6.createTime = "圣诞节";
122 | data6.content = "颜宇扬的期末总结\n1、有本事冲我来,别再家长会上吓唬我爸\n2、期末考试成绩出来了,我觉得我妈生二胎是非常明智的选择\n3、这场考试对于我的意义就是知道了班上到底有多少人\n4、期末考试不给老师们露一手,他们还真以为自己教的好";
123 | data6.pictureList = Arrays.asList(
124 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296287_2190.png"),
125 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296286_7908.png"),
126 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296286_7013.png"),
127 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296286_6401.jpg"),
128 | Uri.parse("http://img.my.csdn.net/uploads/201701/13/1484296106_5671.png")
129 | );
130 | data6.pictureThumbList = Arrays.asList(
131 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647898_9300.png"),
132 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647278_2143.png"),
133 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647816_4929.png"),
134 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647817_5319.jpg"),
135 | Uri.parse("http://img.my.csdn.net/uploads/201701/17/1484647818_3369.png")
136 | );
137 |
138 |
139 | if (System.currentTimeMillis() % 3 == 0) {
140 | dataList.add(data1);
141 | dataList.add(data2);
142 | dataList.add(data3);
143 | dataList.add(data4);
144 | dataList.add(data6);
145 | } else if (System.currentTimeMillis() % 3 == 1) {
146 | dataList.add(data5);
147 | dataList.add(data6);
148 | dataList.add(data2);
149 | dataList.add(data4);
150 | dataList.add(data3);
151 | } else {
152 | dataList.add(data1);
153 | dataList.add(data3);
154 | dataList.add(data4);
155 | dataList.add(data5);
156 | dataList.add(data6);
157 | }
158 |
159 | return dataList;
160 | }
161 |
162 | public String getAvatar() {
163 | return avatar;
164 | }
165 |
166 | public void setAvatar(String avatar) {
167 | this.avatar = avatar;
168 | }
169 |
170 | public String getNickname() {
171 | return nickname;
172 | }
173 |
174 | public void setNickname(String nickname) {
175 | this.nickname = nickname;
176 | }
177 |
178 | public String getCreateTime() {
179 | return createTime;
180 | }
181 |
182 | public void setCreateTime(String createTime) {
183 | this.createTime = createTime;
184 | }
185 |
186 | public String getContent() {
187 | return content;
188 | }
189 |
190 | public void setContent(String content) {
191 | this.content = content;
192 | }
193 |
194 | public List getPictureList() {
195 | return pictureList;
196 | }
197 |
198 | public void setPictureList(List pictureList) {
199 | this.pictureList = pictureList;
200 | }
201 |
202 | public List getPictureThumbList() {
203 | return pictureThumbList;
204 | }
205 |
206 | public void setPictureThumbList(List pictureThumbList) {
207 | this.pictureThumbList = pictureThumbList;
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/IndicatorView.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.util.DisplayMetrics;
7 | import android.view.WindowManager;
8 | import android.widget.ImageView;
9 | import android.widget.LinearLayout;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | public class IndicatorView extends LinearLayout {
15 | private final List dotList = new ArrayList<>();
16 | private final int size ;
17 |
18 | public IndicatorView(Context context) {
19 | this(context, null);
20 | }
21 |
22 | public IndicatorView(Context context, @Nullable AttributeSet attrs) {
23 | super(context, attrs);
24 | DisplayMetrics d = new DisplayMetrics();
25 | ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE))
26 | .getDefaultDisplay().getMetrics(d);
27 | size = (int)(6 * d.density + 0.5);
28 | setPadding(size, 0, 0, 0);
29 | }
30 |
31 | public void reset(int count, int select, int normalRes, int selectRes) {
32 | if (count < 0) count = 0;
33 | if (select > count) select = count;
34 |
35 | dotList.clear();
36 | removeAllViewsInLayout();
37 |
38 | if (count > 1) {
39 | LayoutParams lpDot = new LayoutParams(size, size);
40 | lpDot.setMargins(0, 0, size, 0);
41 | for (int i = 0; i < count; i++) {
42 | ImageView vDot = new ImageView(getContext());
43 | vDot.setLayoutParams(lpDot);
44 |
45 | vDot.setImageResource(i == select ? selectRes : normalRes);
46 |
47 | dotList.add(vDot);
48 | addView(vDot);
49 | }
50 | }
51 | }
52 |
53 | public void select(int pos, int normalRes, int selectRes) {
54 | if (dotList.size() == 0) return;
55 |
56 | pos = pos % dotList.size();
57 |
58 | for (int i = 0; i < dotList.size(); i++) {
59 | final ImageView vDot = dotList.get(i);
60 | vDot.setImageResource(i == pos ? selectRes :
61 | normalRes);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.app.Activity;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.util.Log;
9 | import android.util.SparseArray;
10 | import android.view.View;
11 | import android.widget.ImageView;
12 | import android.widget.Toast;
13 |
14 | import lib.kalu.image.watch.ImageWatcher;
15 |
16 | import java.util.List;
17 |
18 |
19 | public class MainActivity extends Activity implements MessagePicturesLayout.Callback, ImageWatcher.OnPictureLongPressListener {
20 |
21 | private ImageWatcher vImageWatcher;
22 |
23 | private RecyclerView vRecycler;
24 | private MessageAdapter adapter;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | boolean isTranslucentStatus = false;
29 | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
30 | // Window window = getWindow();
31 | // window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
32 | // window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
33 | // window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
34 | // window.setStatusBarColor(Color.TRANSPARENT);
35 | // window.setNavigationBarColor(Color.TRANSPARENT);
36 | // isTranslucentStatus = true;
37 | // }
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_main);
40 |
41 | findViewById(R.id.vRefresh).setOnClickListener(new View.OnClickListener() {
42 | @Override
43 | public void onClick(View v) {
44 | Toast.makeText(v.getContext().getApplicationContext(), "刷新列表内容 adapter.reset()" , Toast.LENGTH_SHORT).show();
45 | adapter.set(Data.get());
46 | }
47 | });
48 |
49 | vRecycler = (RecyclerView) findViewById(R.id.v_recycler);
50 | vRecycler.setLayoutManager(new LinearLayoutManager(this));
51 | vRecycler.addItemDecoration(new SpaceItemDecoration(this).setSpace(14).setSpaceColor(0xFFECECEC));
52 | vRecycler.setAdapter(adapter = new MessageAdapter(this).setPictureClickCallback(this));
53 | adapter.set(Data.get());
54 |
55 | // ************** xml 方式加载 ******** 推荐使用后面demo的iwHelper
56 |
57 | // 一般来讲, ImageWatcher 需要占据全屏的位置
58 | vImageWatcher = (ImageWatcher) findViewById(R.id.v_image_watcher);
59 | // 如果不是透明状态栏,你需要给ImageWatcher标记 一个偏移值,以修正点击ImageView查看的启动动画的Y轴起点的不正确
60 | vImageWatcher.setTranslucentStatus(!isTranslucentStatus ? Utils.calcStatusBarHeight(this) : 0);
61 | // 配置error图标 如果不介意使用lib自带的图标,并不一定要调用这个API
62 | vImageWatcher.setErrorImageRes(R.mipmap.error_picture);
63 | // 长按图片的回调,你可以显示一个框继续提供一些复制,发送等功能
64 | vImageWatcher.setOnPictureLongPressListener(this);
65 | vImageWatcher.setLoader(new SimpleLoader());
66 | vImageWatcher.setOnStateChangedListener(new ImageWatcher.OnStateChangedListener() {
67 | @Override
68 | public void onStateChangeUpdate(ImageWatcher imageWatcher, ImageView clicked, int position, Uri uri, float animatedValue, int actionTag) {
69 | Log.e("IW", "onStateChangeUpdate [" + position + "][" + uri + "][" + animatedValue + "][" + actionTag + "]");
70 | }
71 |
72 | @Override
73 | public void onStateChanged(ImageWatcher imageWatcher, int position, Uri uri, int actionTag) {
74 | if (actionTag == ImageWatcher.STATE_ENTER_DISPLAYING) {
75 | Toast.makeText(getApplicationContext(), "点击了图片 [" + position + "]" + uri + "", Toast.LENGTH_SHORT).show();
76 | } else if (actionTag == ImageWatcher.STATE_EXIT_HIDING) {
77 | Toast.makeText(getApplicationContext(), "退出了查看大图", Toast.LENGTH_SHORT).show();
78 | }
79 | }
80 | });
81 | Utils.fitsSystemWindows(isTranslucentStatus, findViewById(R.id.v_fit));
82 | }
83 |
84 |
85 | @Override
86 | public void onThumbPictureClick(ImageView i, SparseArray imageGroupList, List urlList) {
87 | vImageWatcher.show(i, imageGroupList, urlList);
88 | }
89 |
90 | @Override
91 | public void onPictureLongPress(ImageView v, Uri uri, int pos) {
92 | Toast.makeText(v.getContext().getApplicationContext(), "长按了第" + (pos + 1) + "张图片", Toast.LENGTH_SHORT).show();
93 | }
94 |
95 | @Override
96 | public void onBackPressed() {
97 | if (!vImageWatcher.handleBackPressed()) {
98 | super.onBackPressed();
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MainActivity2.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.net.Uri;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.util.Log;
11 | import android.util.SparseArray;
12 | import android.view.View;
13 | import android.view.Window;
14 | import android.view.WindowManager;
15 | import android.widget.ImageView;
16 | import android.widget.Toast;
17 |
18 | import lib.kalu.image.watch.ImageWatcher;
19 | import lib.kalu.image.watch.ImageWatcherHelper;
20 |
21 | import java.util.List;
22 |
23 | public class MainActivity2 extends Activity implements MessagePicturesLayout.Callback {
24 |
25 | private ImageWatcherHelper iwHelper;
26 | private RecyclerView vRecycler;
27 | private MessageAdapter adapter;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | boolean isTranslucentStatus = false;
32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
33 | Window window = getWindow();
34 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
35 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
36 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
37 | window.setStatusBarColor(Color.TRANSPARENT);
38 | window.setNavigationBarColor(Color.TRANSPARENT);
39 | isTranslucentStatus = true;
40 | }
41 | super.onCreate(savedInstanceState);
42 | setContentView(R.layout.activity_main2);
43 |
44 | vRecycler = (RecyclerView) findViewById(R.id.v_recycler);
45 | vRecycler.setLayoutManager(new LinearLayoutManager(this));
46 | vRecycler.addItemDecoration(new SpaceItemDecoration(this).setSpace(14).setSpaceColor(0xFFECECEC));
47 | vRecycler.setAdapter(adapter = new MessageAdapter(this).setPictureClickCallback(this));
48 | adapter.set(Data.get());
49 |
50 | // ************** 动态 addView **************
51 |
52 | iwHelper = ImageWatcherHelper.with(this, new SimpleLoader()) // 一般来讲, ImageWatcher 需要占据全屏的位置
53 | .setTranslucentStatus(!isTranslucentStatus ? Utils.calcStatusBarHeight(this) : 0) // 如果不是透明状态栏,你需要给ImageWatcher标记 一个偏移值,以修正点击ImageView查看的启动动画的Y轴起点的不正确
54 | .setErrorImageRes(R.mipmap.error_picture) // 配置error图标 如果不介意使用lib自带的图标,并不一定要调用这个API
55 | .setOnPictureLongPressListener(new ImageWatcher.OnPictureLongPressListener() {
56 | @Override
57 | public void onPictureLongPress(ImageView v, Uri uri, int pos) {
58 | // 长按图片的回调,你可以显示一个框继续提供一些复制,发送等功能
59 | Toast.makeText(v.getContext().getApplicationContext(), "长按了第" + (pos + 1) + "张图片", Toast.LENGTH_SHORT).show();
60 | }
61 | })
62 | .setOnStateChangedListener(new ImageWatcher.OnStateChangedListener() {
63 | @Override
64 | public void onStateChangeUpdate(ImageWatcher imageWatcher, ImageView clicked, int position, Uri uri, float animatedValue, int actionTag) {
65 | Log.e("IW", "onStateChangeUpdate [" + position + "][" + uri + "][" + animatedValue + "][" + actionTag + "]");
66 | }
67 |
68 | @Override
69 | public void onStateChanged(ImageWatcher imageWatcher, int position, Uri uri, int actionTag) {
70 | if (actionTag == ImageWatcher.STATE_ENTER_DISPLAYING) {
71 | Toast.makeText(getApplicationContext(), "点击了图片 [" + position + "]" + uri + "", Toast.LENGTH_SHORT).show();
72 | } else if (actionTag == ImageWatcher.STATE_EXIT_HIDING) {
73 | Toast.makeText(getApplicationContext(), "退出了查看大图", Toast.LENGTH_SHORT).show();
74 | }
75 | }
76 | })
77 | .setLoadingUIProvider(new CustomLoadingUIProvider()); // 自定义LoadingUI
78 |
79 |
80 | Utils.fitsSystemWindows(isTranslucentStatus, findViewById(R.id.v_fit));
81 | }
82 |
83 | @Override
84 | public void onThumbPictureClick(ImageView i, SparseArray imageGroupList, List urlList) {
85 | iwHelper.show(i, imageGroupList, urlList);
86 | }
87 |
88 | @Override
89 | public void onBackPressed() {
90 | if (!iwHelper.handleBackPressed()) {
91 | super.onBackPressed();
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MainActivity3.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.net.Uri;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.util.SparseArray;
9 | import android.view.View;
10 | import android.view.Window;
11 | import android.view.WindowManager;
12 | import android.widget.ImageView;
13 |
14 | import com.bumptech.glide.Glide;
15 | import lib.kalu.image.watch.ImageWatcherHelper;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | public class MainActivity3 extends Activity {
21 |
22 | private ImageWatcherHelper iwHelper;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | boolean isTranslucentStatus = false;
27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
28 | Window window = getWindow();
29 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
30 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
31 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
32 | window.setStatusBarColor(Color.TRANSPARENT);
33 | window.setNavigationBarColor(Color.TRANSPARENT);
34 | isTranslucentStatus = true;
35 | }
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_main3);
38 |
39 | iwHelper = ImageWatcherHelper.with(this, new SimpleLoader()) // 一般来讲, ImageWatcher 需要占据全屏的位置
40 | .setTranslucentStatus(!isTranslucentStatus ? Utils.calcStatusBarHeight(this) : 0) // 如果不是透明状态栏,你需要给ImageWatcher标记 一个偏移值,以修正点击ImageView查看的启动动画的Y轴起点的不正确
41 | .setErrorImageRes(R.mipmap.error_picture); // 配置error图标 如果不介意使用lib自带的图标,并不一定要调用这个API
42 |
43 | Utils.fitsSystemWindows(isTranslucentStatus, findViewById(R.id.v_fit));
44 |
45 | ImageView iPicture = (ImageView) findViewById(R.id.i_picture);
46 |
47 | final String picThumbUrl = "http://img.my.csdn.net/uploads/201707/27/1501118720_9504.jpg";
48 | final String picUrl = "http://img.my.csdn.net/uploads/201707/27/1501118577_9169.jpg";
49 |
50 | Glide.with(iPicture.getContext()).asBitmap().load(picThumbUrl).into(iPicture);
51 | iPicture.setOnClickListener(new View.OnClickListener() {
52 | @Override
53 | public void onClick(View v) {
54 | final List longPictureList = new ArrayList<>();
55 | longPictureList.add(picUrl);
56 | final SparseArray mappingViews = new SparseArray<>();
57 | mappingViews.put(0, (ImageView) v);
58 | iwHelper.show((ImageView) v, mappingViews, convert(longPictureList));
59 | }
60 | });
61 |
62 |
63 | Glide.with(iPicture.getContext()).asBitmap().load("http://img.zcool.cn/community/01ee43596f0ce9a8012193a38dcb00.jpg")
64 | .into((ImageView) findViewById(R.id.vLongPicture));
65 | findViewById(R.id.vLongPicture).setOnClickListener(new View.OnClickListener() {
66 | @Override
67 | public void onClick(View v) {
68 | final List longPictureList = new ArrayList<>();
69 | longPictureList.add("http://img.zcool.cn/community/01ee43596f0ce9a8012193a38dcb00.jpg");
70 | longPictureList.add("https://img3.duitang.com/uploads/item/201608/03/20160803170546_BwshQ.thumb.224_0.jpeg");
71 | longPictureList.add("http://img4.duitang.com/uploads/item/201601/21/20160121150507_AkrQx.thumb.224_0.jpeg");
72 | longPictureList.add("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2211841400,3995215486&fm=27&gp=0.jpg");
73 | final SparseArray mappingViews = new SparseArray<>();
74 | mappingViews.put(0, (ImageView) v);
75 | iwHelper.show((ImageView) v, mappingViews, convert(longPictureList));
76 | }
77 | });
78 | }
79 |
80 | private List convert(List data) {
81 | List list = new ArrayList<>();
82 | for (String d : data) list.add(Uri.parse(d));
83 | return list;
84 | }
85 |
86 |
87 | @Override
88 | public void onBackPressed() {
89 | if (!iwHelper.handleBackPressed()) {
90 | super.onBackPressed();
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MainActivity4.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.net.Uri;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.util.SparseArray;
9 | import android.view.View;
10 | import android.view.Window;
11 | import android.view.WindowManager;
12 | import android.widget.ImageView;
13 |
14 | import com.bumptech.glide.Glide;
15 |
16 | import lib.kalu.image.watch.ImageWatcherHelper;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | public class MainActivity4 extends Activity {
22 | private List dataList = new ArrayList<>();
23 |
24 | private ImageWatcherHelper iwHelper;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | boolean isTranslucentStatus = false;
29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
30 | Window window = getWindow();
31 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
32 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
33 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
34 | window.setStatusBarColor(Color.TRANSPARENT);
35 | window.setNavigationBarColor(Color.TRANSPARENT);
36 | isTranslucentStatus = true;
37 | }
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_main4);
40 |
41 | String u1 = "http://img.hb.aicdn.com/adf79cb0385bfe98456fea7768b12a5ca4eca0b8c81b-Tp0ywW_fw658";
42 | String u2 = "http://img.hb.aicdn.com/df75487fbc3ad89bb0c42eee053c3fd2fdc6b18a12b99-qYfZrA_fw658";
43 | String u3 = "http://img.hb.aicdn.com/f2fb872825d780bbe7eb1ca6696454719720f8f0a61a-1VaMd9_fw658";
44 | String u4 = "http://img.hb.aicdn.com/2982f37c8c149a1a9b9e236e45b7e1eabd4b168710c0c-cyspHw_fw658";
45 | String u5 = "http://img.hb.aicdn.com/e2c234cf4b8dc718459403b8f2cc8b5bb637bc213f74c-YYwZ0R_fw658";
46 | String u6 = "http://img.hb.aicdn.com/e1c5522de00aae08819d127b44b5dd943f6359fa121f7-EtF0yY_fw658";
47 | String u7 = "http://img.hb.aicdn.com/13bbb585cd889fe41d39e8da1eac185143a6a3123ae2-91zlEN_fw658";
48 | String u8 = "http://img.hb.aicdn.com/c2ea3454413ce9353e002749e5425fcf550f2bf7bb0c-yLD00Z_fw658";
49 | dataList.add(Uri.parse(u1));
50 | dataList.add(Uri.parse(u2));
51 | dataList.add(Uri.parse(u3));
52 | dataList.add(Uri.parse(u4));
53 | dataList.add(Uri.parse(u5));
54 | dataList.add(Uri.parse(u6));
55 | dataList.add(Uri.parse(u7));
56 | dataList.add(Uri.parse(u8));
57 |
58 | Glide.with(this).load(u1).into(((ImageView) findViewById(R.id.v1)));
59 | Glide.with(this).load(u2).into(((ImageView) findViewById(R.id.v2)));
60 | Glide.with(this).load(u3).into(((ImageView) findViewById(R.id.v3)));
61 | Glide.with(this).load(u4).into(((ImageView) findViewById(R.id.v4)));
62 | Glide.with(this).load(u5).into(((ImageView) findViewById(R.id.v5)));
63 | Glide.with(this).load(u6).into(((ImageView) findViewById(R.id.v6)));
64 | Glide.with(this).load(u7).into(((ImageView) findViewById(R.id.v7)));
65 | Glide.with(this).load(u8).into(((ImageView) findViewById(R.id.v8)));
66 |
67 | View.OnClickListener showListener = new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | show((ImageView) v);
71 | }
72 | };
73 | findViewById(R.id.v1).setOnClickListener(showListener);
74 | findViewById(R.id.v2).setOnClickListener(showListener);
75 | findViewById(R.id.v3).setOnClickListener(showListener);
76 | findViewById(R.id.v4).setOnClickListener(showListener);
77 | findViewById(R.id.v5).setOnClickListener(showListener);
78 | findViewById(R.id.v6).setOnClickListener(showListener);
79 | findViewById(R.id.v7).setOnClickListener(showListener);
80 | findViewById(R.id.v8).setOnClickListener(showListener);
81 |
82 |
83 | iwHelper = ImageWatcherHelper.with(this ,new SimpleLoader()) // 一般来讲, ImageWatcher 需要占据全屏的位置
84 | .setIndexProvider(new CustomDotIndexProvider()); // 自定义index
85 | }
86 |
87 | private void show(ImageView clickedImage) {
88 | SparseArray mapping = new SparseArray<>();
89 | mapping.put(0, (ImageView) findViewById(R.id.v1));
90 | mapping.put(1, (ImageView) findViewById(R.id.v2));
91 | mapping.put(2, (ImageView) findViewById(R.id.v3));
92 | mapping.put(3, (ImageView) findViewById(R.id.v4));
93 | mapping.put(4, (ImageView) findViewById(R.id.v5));
94 | mapping.put(5, (ImageView) findViewById(R.id.v6));
95 | mapping.put(6, (ImageView) findViewById(R.id.v7));
96 | mapping.put(7, (ImageView) findViewById(R.id.v8));
97 |
98 | // initPosition = -1;
99 | // for (int x = 0; x < imageGroupList.size(); x++) {
100 | // if (imageGroupList.get(imageGroupList.keyAt(x)) == i) {
101 | // initPosition = imageGroupList.keyAt(x);
102 | // break;
103 | // }
104 | // }
105 | // if (initPosition < 0) {
106 | // throw new IllegalArgumentException("param ImageView i must be a member of the List imageGroupList!");
107 | // }
108 |
109 | // 以上是show源码。 所以就是说, clickedImage 是 mapping 中的任意一个。 如果不是就崩了。
110 | // 注意,下标当然是从0开始的
111 | iwHelper.show(clickedImage, mapping, dataList);
112 | }
113 |
114 | @Override
115 | public void onBackPressed() {
116 | if (!iwHelper.handleBackPressed()) {
117 | super.onBackPressed();
118 | }
119 | }
120 | }
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MainActivity5.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.app.Activity;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.util.SparseArray;
7 | import android.view.View;
8 | import android.widget.ImageView;
9 |
10 | import com.bumptech.glide.Glide;
11 | import lib.kalu.image.watch.ImageWatcherHelper;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | public class MainActivity5 extends Activity {
17 | private ImageWatcherHelper iwHelper;
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main5);
23 |
24 | iwHelper = ImageWatcherHelper.with(this, new SimpleLoader());
25 |
26 | View vGifPicture = findViewById(R.id.vGifPicture);
27 | Glide.with(vGifPicture.getContext()).asBitmap().load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534324920537&di=278f9d990f277cca368a118afaac196b&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201409%2F22%2F20140922013938_NZfBs.thumb.700_0.gif")
28 | .into((ImageView) vGifPicture); // asBitmap 必须加
29 | vGifPicture.setOnClickListener(new View.OnClickListener() {
30 | @Override
31 | public void onClick(View v) {
32 | final List longPictureList = new ArrayList<>();
33 | longPictureList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534326475217&di=f9b996c80a034ae12126bed1e0156445&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201411%2F25%2F20141125204219_QzmMA.thumb.700_0.gif");
34 | longPictureList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534324920537&di=278f9d990f277cca368a118afaac196b&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201409%2F22%2F20140922013938_NZfBs.thumb.700_0.gif");
35 | longPictureList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534326475217&di=d828d5dd375440a6344d75ecde93dcb6&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201411%2F29%2F20141129014255_4hnZt.thumb.700_0.gif");
36 | longPictureList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534326475216&di=09e333916e78b88ad80ad80b26b65bf5&imgtype=0&src=http%3A%2F%2Fattach.cgjoy.com%2Fattachment%2Fforum%2F201505%2F06%2F102801e87qjqt1n3hmt0n1.gif");
37 | final SparseArray mappingViews = new SparseArray<>();
38 | mappingViews.put(1, (ImageView) v);
39 | iwHelper.show((ImageView) v, mappingViews, convert(longPictureList));
40 | }
41 | });
42 | }
43 |
44 | private List convert(List data) {
45 | List list = new ArrayList<>();
46 | for (String d : data) list.add(Uri.parse(d));
47 | return list;
48 | }
49 |
50 | @Override
51 | public void onBackPressed() {
52 | if (!iwHelper.handleBackPressed()) {
53 | super.onBackPressed();
54 | }
55 | }
56 | }
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MessageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
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 |
11 | import com.bumptech.glide.Glide;
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class MessageAdapter extends RecyclerView.Adapter {
16 | private final List mDataList = new ArrayList<>();
17 | private MessagePicturesLayout.Callback mCallback;
18 |
19 | MessageAdapter(Context context) {
20 | }
21 |
22 | public MessageAdapter setPictureClickCallback(MessagePicturesLayout.Callback callback) {
23 | mCallback = callback;
24 | return this;
25 | }
26 |
27 | public void set(List dataList) {
28 | mDataList.clear();
29 | if (dataList != null) {
30 | mDataList.addAll(dataList);
31 | }
32 | notifyDataSetChanged();
33 | }
34 |
35 |
36 | class ViewHolder extends RecyclerView.ViewHolder {
37 | ImageView iAvatar;
38 | TextView tNickname, tTime, tContent;
39 | MessagePicturesLayout lPictures;
40 |
41 | Data mData;
42 |
43 | ViewHolder(View itemView) {
44 | super(itemView);
45 | iAvatar = (ImageView) itemView.findViewById(R.id.i_avatar);
46 | tNickname = (TextView) itemView.findViewById(R.id.t_nickname);
47 | tTime = (TextView) itemView.findViewById(R.id.t_time);
48 | tContent = (TextView) itemView.findViewById(R.id.t_content);
49 | lPictures = (MessagePicturesLayout) itemView.findViewById(R.id.l_pictures);
50 | lPictures.setCallback(mCallback);
51 | }
52 |
53 | void refresh(int pos) {
54 | mData = mDataList.get(pos);
55 | Glide.with(itemView.getContext()).load(mData.getAvatar()).into(iAvatar);
56 | tNickname.setText(mData.getNickname());
57 | tTime.setText(mData.getCreateTime());
58 | tContent.setText(mData.getContent());
59 | lPictures.set(mData.getPictureThumbList(), mData.getPictureList());
60 | }
61 | }
62 |
63 | @Override
64 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
65 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_main_message, parent, false));
66 | }
67 |
68 | @Override
69 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
70 | ((ViewHolder) holder).refresh(position % mDataList.size());
71 | }
72 |
73 | @Override
74 | public int getItemCount() {
75 | return 99999;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MessagePicturesLayout.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.support.annotation.Nullable;
6 | import android.util.AttributeSet;
7 | import android.util.DisplayMetrics;
8 | import android.util.SparseArray;
9 | import android.util.TypedValue;
10 | import android.view.Gravity;
11 | import android.view.View;
12 | import android.widget.FrameLayout;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 |
16 | import com.bumptech.glide.Glide;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | /**
21 | * QQ 517309507
22 | * 至尊流畅;daLao专用;/斜眼笑
23 | */
24 | public class MessagePicturesLayout extends FrameLayout implements View.OnClickListener {
25 |
26 | public static final int MAX_DISPLAY_COUNT = 9;
27 | private final FrameLayout.LayoutParams lpChildImage = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
28 | private final int mSingleMaxSize;
29 | private final int mSpace;
30 | private final List iPictureList = new ArrayList<>();
31 | private final SparseArray mVisiblePictureList = new SparseArray<>();
32 | private final TextView tOverflowCount;
33 |
34 | private Callback mCallback;
35 | private boolean isInit;
36 | private List mDataList;
37 | private List mThumbDataList;
38 |
39 | public MessagePicturesLayout(Context context, @Nullable AttributeSet attrs) {
40 | super(context, attrs);
41 |
42 | DisplayMetrics mDisplayMetrics = context.getResources().getDisplayMetrics();
43 | mSingleMaxSize = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 216, mDisplayMetrics) + 0.5f);
44 | mSpace = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, mDisplayMetrics) + 0.5f);
45 |
46 | for (int i = 0; i < MAX_DISPLAY_COUNT; i++) {
47 | ImageView squareImageView = new SquareImageView(context);
48 | squareImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
49 | squareImageView.setVisibility(View.GONE);
50 | squareImageView.setOnClickListener(this);
51 | addView(squareImageView);
52 | iPictureList.add(squareImageView);
53 | }
54 |
55 | tOverflowCount = new TextView(context);
56 | tOverflowCount.setTextColor(0xFFFFFFFF);
57 | tOverflowCount.setTextSize(24);
58 | tOverflowCount.setGravity(Gravity.CENTER);
59 | tOverflowCount.setBackgroundColor(0x66000000);
60 | tOverflowCount.setVisibility(View.GONE);
61 | addView(tOverflowCount);
62 | }
63 |
64 | public void set(List urlThumbList, List urlList) {
65 | mThumbDataList = urlThumbList;
66 | mDataList = urlList;
67 | if (isInit) {
68 | notifyDataChanged();
69 | }
70 | }
71 |
72 | private void notifyDataChanged() {
73 | final List thumbList = mThumbDataList;
74 | final int urlListSize = thumbList != null ? mThumbDataList.size() : 0;
75 |
76 | if (thumbList == null || thumbList.size() < 1) {
77 | setVisibility(View.GONE);
78 | return;
79 | } else {
80 | setVisibility(View.VISIBLE);
81 | }
82 |
83 | if (thumbList.size() > mDataList.size()) {
84 | throw new IllegalArgumentException("dataList.size(" + mDataList.size() + ") > thumbDataList.size(" + thumbList.size() + ")");
85 | }
86 |
87 | int column = 3;
88 | if (urlListSize == 1) {
89 | column = 1;
90 | } else if (urlListSize == 4) {
91 | column = 2;
92 | }
93 | int row = 0;
94 | if (urlListSize > 6) {
95 | row = 3;
96 | } else if (urlListSize > 3) {
97 | row = 2;
98 | } else if (urlListSize > 0) {
99 | row = 1;
100 | }
101 |
102 | final int imageSize = urlListSize == 1 ? mSingleMaxSize :
103 | (int) ((getWidth() * 1f - mSpace * (column - 1)) / column);
104 |
105 | lpChildImage.width = imageSize;
106 | lpChildImage.height = lpChildImage.width;
107 |
108 | tOverflowCount.setVisibility(urlListSize > MAX_DISPLAY_COUNT ? View.VISIBLE : View.GONE);
109 | tOverflowCount.setText("+ " + (urlListSize - MAX_DISPLAY_COUNT));
110 | tOverflowCount.setLayoutParams(lpChildImage);
111 |
112 | mVisiblePictureList.clear();
113 | for (int i = 0; i < iPictureList.size(); i++) {
114 | final ImageView iPicture = iPictureList.get(i);
115 | if (i < urlListSize) {
116 | iPicture.setVisibility(View.VISIBLE);
117 | mVisiblePictureList.put(i, iPicture);
118 | iPicture.setLayoutParams(lpChildImage);
119 | iPicture.setBackgroundResource(R.drawable.default_picture);
120 | Glide.with(getContext()).load(thumbList.get(i)).into(iPicture);
121 | iPicture.setTranslationX((i % column) * (imageSize + mSpace));
122 | iPicture.setTranslationY((i / column) * (imageSize + mSpace));
123 | } else {
124 | iPicture.setVisibility(View.GONE);
125 | }
126 |
127 | if (i == MAX_DISPLAY_COUNT - 1) {
128 | tOverflowCount.setTranslationX((i % column) * (imageSize + mSpace));
129 | tOverflowCount.setTranslationY((i / column) * (imageSize + mSpace));
130 | }
131 | }
132 | getLayoutParams().height = imageSize * row + mSpace * (row - 1);
133 | }
134 |
135 | @Override
136 | public void onClick(View v) {
137 | if (mCallback != null) {
138 | mCallback.onThumbPictureClick((ImageView) v, mVisiblePictureList, mDataList);
139 | }
140 | }
141 |
142 | public interface Callback {
143 | void onThumbPictureClick(ImageView i, SparseArray imageGroupList, List urlList);
144 | }
145 |
146 | public void setCallback(Callback callback) {
147 | mCallback = callback;
148 | }
149 |
150 | @Override
151 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
152 | super.onSizeChanged(w, h, oldw, oldh);
153 | isInit = true;
154 | notifyDataChanged();
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/MyGlideModule.java:
--------------------------------------------------------------------------------
1 | //package com.demo.photo;
2 | //
3 | //import android.content.Context;
4 | //import android.support.annotation.NonNull;
5 | //
6 | //import com.bumptech.glide.Glide;
7 | //import com.bumptech.glide.GlideBuilder;
8 | //import com.bumptech.glide.Registry;
9 | //import com.bumptech.glide.annotation.GlideModule;
10 | //import com.bumptech.glide.load.model.GlideUrl;
11 | //import com.bumptech.glide.module.AppGlideModule;
12 | //import com.demo.photo.util.LogUtil;
13 | //
14 | //import java.io.InputStream;
15 | //
16 | //import lib.kalu.glide.LibInterceptor;
17 | //import lib.kalu.glide.LibModelLoader;
18 | //import okhttp3.OkHttpClient;
19 | //
20 | //@GlideModule
21 | //public class MyGlideModule extends AppGlideModule {
22 | //
23 | // @Override
24 | // public void applyOptions(Context context, GlideBuilder builder) {
25 | // LogUtil.e("kalu", "applyOptions");
26 | //
27 | // }
28 | //
29 | // @Override
30 | // public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
31 | // LogUtil.e("kalu", "registerComponents");
32 | //
33 | // // step1
34 | // final OkHttpClient.Builder builder = new OkHttpClient.Builder();
35 | // builder.addInterceptor(new LibInterceptor());
36 | // // step2
37 | // final OkHttpClient okHttpClient = builder.build();
38 | // // step3
39 | // registry.replace(GlideUrl.class, InputStream.class, new LibModelLoader.Factory(okHttpClient));
40 | // }
41 | //
42 | // @Override
43 | // public boolean isManifestParsingEnabled() {
44 | // LogUtil.e("kalu", "isManifestParsingEnabled");
45 | // return false;
46 | // }
47 | //}
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/SimpleLoader.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.net.Uri;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 |
9 | import com.bumptech.glide.Glide;
10 | import com.bumptech.glide.request.target.SimpleTarget;
11 | import com.bumptech.glide.request.transition.Transition;
12 | import lib.kalu.image.watch.ImageWatcher;
13 |
14 | class SimpleLoader implements ImageWatcher.Loader {
15 | @Override
16 | public void load(Context context, Uri uri, final ImageWatcher.LoadCallback lc) {
17 | Glide.with(context).load(uri)
18 | .into(new SimpleTarget() {
19 | @Override
20 | public void onResourceReady(@NonNull Drawable resource, @Nullable Transition super Drawable> transition) {
21 | lc.onResourceReady(resource);
22 | }
23 |
24 | @Override
25 | public void onLoadFailed(@Nullable Drawable errorDrawable) {
26 | lc.onLoadFailed(errorDrawable);
27 | }
28 |
29 | @Override
30 | public void onLoadStarted(@Nullable Drawable placeholder) {
31 | lc.onLoadStarted(placeholder);
32 | }
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/SpaceItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Rect;
7 | import android.support.v4.view.ViewCompat;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.util.DisplayMetrics;
12 | import android.util.TypedValue;
13 | import android.view.View;
14 |
15 | /**
16 | * QQ 517309507
17 | * 参考 http://www.jianshu.com/p/e742df6f59e2
18 | */
19 | public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
20 | private Paint mDividerPaint = new Paint();
21 | private DisplayMetrics mDisplayMetrics;
22 | private int mSpace;
23 | private int mEdgeSpace;
24 |
25 | public SpaceItemDecoration(Context context) {
26 | mDisplayMetrics = context.getResources().getDisplayMetrics();
27 | }
28 |
29 | public SpaceItemDecoration setSpace(int space) {
30 | mSpace = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, space, mDisplayMetrics) + 0.5f);
31 | return this;
32 | }
33 |
34 | public SpaceItemDecoration setEdgeSpace(int edgeSpace) {
35 | mEdgeSpace = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, edgeSpace, mDisplayMetrics) + 0.5f);
36 | return this;
37 | }
38 |
39 | public SpaceItemDecoration setSpaceColor(int spaceColor) {
40 | mDividerPaint.setColor(spaceColor);
41 | return this;
42 | }
43 |
44 |
45 | @Override
46 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
47 | final RecyclerView.LayoutManager manager = parent.getLayoutManager();
48 | final int childPosition = parent.getChildAdapterPosition(view);
49 | final int itemCount = parent.getAdapter().getItemCount();
50 | if (manager != null) {
51 | if (manager instanceof GridLayoutManager) {
52 | setGrid(((GridLayoutManager) manager).getOrientation(), ((GridLayoutManager) manager).getSpanCount(), outRect, childPosition, itemCount);
53 | } else if (manager instanceof LinearLayoutManager) {
54 | setLinear(((LinearLayoutManager) manager).getOrientation(), outRect, childPosition, itemCount);
55 | }
56 | }
57 | }
58 |
59 | @Override
60 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
61 | final RecyclerView.LayoutManager manager = parent.getLayoutManager();
62 | if (manager != null) {
63 | if (manager instanceof GridLayoutManager) {
64 |
65 | } else if (manager instanceof LinearLayoutManager) {
66 | drawLinear(((LinearLayoutManager) manager).getOrientation(), c, parent);
67 | }
68 | }
69 | }
70 |
71 | private void setLinear(int orientation, Rect outRect, int childPosition, int itemCount) {
72 | if (orientation == LinearLayoutManager.VERTICAL) {
73 | if (childPosition == 0) {
74 | outRect.set(0, mEdgeSpace, 0, mSpace);
75 | } else if (childPosition == itemCount - 1) {
76 | outRect.set(0, 0, 0, mEdgeSpace);
77 | } else {
78 | outRect.set(0, 0, 0, mSpace);
79 | }
80 | } else if (orientation == LinearLayoutManager.HORIZONTAL) {
81 | if (childPosition == 0) {
82 | outRect.set(mEdgeSpace, 0, mSpace, 0);
83 | } else if (childPosition == itemCount - 1) {
84 | outRect.set(0, 0, mEdgeSpace, 0);
85 | } else {
86 | outRect.set(0, 0, mSpace, 0);
87 | }
88 | }
89 | }
90 |
91 | private void setGrid(int orientation, int spanCount, Rect outRect, int childPosition, int itemCount) {
92 | float totalSpace = mSpace * (spanCount - 1) + mEdgeSpace * 2;
93 | float eachSpace = totalSpace / spanCount;
94 | int column = childPosition % spanCount;
95 | int row = childPosition / spanCount;
96 |
97 | float left;
98 | float right;
99 | float top;
100 | float bottom;
101 | if (orientation == GridLayoutManager.VERTICAL) {
102 | top = 0;
103 | bottom = mSpace;
104 |
105 | if (childPosition < spanCount) {
106 | top = mEdgeSpace;
107 | }
108 | if (itemCount % spanCount != 0 && itemCount / spanCount == row ||
109 | itemCount % spanCount == 0 && itemCount / spanCount == row + 1) {
110 | bottom = mEdgeSpace;
111 | }
112 |
113 | if (spanCount == 1) {
114 | left = mEdgeSpace;
115 | right = left;
116 | } else {
117 | left = column * (eachSpace - mEdgeSpace - mEdgeSpace) / (spanCount - 1) + mEdgeSpace;
118 | right = eachSpace - left;
119 | }
120 | } else {
121 | left = 0;
122 | right = mSpace;
123 |
124 | if (childPosition < spanCount) {
125 | left = mEdgeSpace;
126 | }
127 | if (itemCount % spanCount != 0 && itemCount / spanCount == row ||
128 | itemCount % spanCount == 0 && itemCount / spanCount == row + 1) {
129 | right = mEdgeSpace;
130 | }
131 |
132 | if (spanCount == 1) {
133 | top = mEdgeSpace;
134 | bottom = top;
135 | } else {
136 | top = column * (eachSpace - mEdgeSpace - mEdgeSpace) / (spanCount - 1) + mEdgeSpace;
137 | bottom = eachSpace - top;
138 | }
139 | }
140 | outRect.set((int) left, (int) top, (int) right, (int) bottom);
141 | }
142 |
143 |
144 | private void drawLinear(int orientation, Canvas c, RecyclerView parent) {
145 | if (orientation == LinearLayoutManager.VERTICAL) {
146 | final int left = parent.getPaddingLeft();
147 | final int right = parent.getWidth() - parent.getPaddingRight();
148 |
149 | final int childCount = parent.getChildCount();
150 | for (int i = 0; i < childCount; i++) {
151 | final View child = parent.getChildAt(i);
152 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
153 | .getLayoutParams();
154 | final int top = child.getBottom() + params.bottomMargin +
155 | Math.round(ViewCompat.getTranslationY(child));
156 | final int bottom = top + mSpace;
157 | c.drawRect(left, top, right, bottom, mDividerPaint);
158 | }
159 |
160 | } else if (orientation == LinearLayoutManager.HORIZONTAL) {
161 | final int top = parent.getPaddingTop();
162 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
163 | final int childCount = parent.getChildCount();
164 | for (int i = 0; i < childCount; i++) {
165 | final View child = parent.getChildAt(i);
166 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
167 | .getLayoutParams();
168 | final int left = child.getRight() + params.rightMargin +
169 | Math.round(ViewCompat.getTranslationX(child));
170 | final int right = left + mSpace;
171 | c.drawRect(left, top, right, bottom, mDividerPaint);
172 | }
173 | }
174 | }
175 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/SquareImageView.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.ImageView;
6 |
7 | public class SquareImageView extends ImageView {
8 |
9 | public SquareImageView(Context context) {
10 | this(context, null);
11 | }
12 |
13 | public SquareImageView(Context context, AttributeSet attrs) {
14 | super(context, attrs);
15 | }
16 |
17 | @Override
18 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
19 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
20 | setMeasuredDimension(widthSize, widthSize);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/TestActivity.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.view.View;
8 |
9 | public class TestActivity extends Activity {
10 |
11 | @Override
12 | protected void onCreate(@Nullable Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_test);
15 |
16 | findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
17 | @Override
18 | public void onClick(View v) {
19 | Intent intent = new Intent(TestActivity.this, MainActivity2.class);
20 | startActivity(intent);
21 | }
22 | });
23 |
24 |
25 | findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View v) {
28 | Intent intent = new Intent(TestActivity.this, MainActivity.class);
29 | startActivity(intent);
30 | }
31 | });
32 |
33 | findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
34 | @Override
35 | public void onClick(View v) {
36 | Intent intent = new Intent(TestActivity.this, MainActivity3.class);
37 | startActivity(intent);
38 | }
39 | });
40 |
41 | findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {
42 | @Override
43 | public void onClick(View v) {
44 | Intent intent = new Intent(TestActivity.this, MainActivity4.class);
45 | startActivity(intent);
46 | }
47 | });
48 |
49 | findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | Intent intent = new Intent(TestActivity.this, MainActivity5.class);
53 | startActivity(intent);
54 | }
55 | });
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kalu/image/Utils.java:
--------------------------------------------------------------------------------
1 | package com.kalu.image;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 |
7 | public class Utils {
8 | public static void fitsSystemWindows(boolean isTranslucentStatus, View view) {
9 | if (isTranslucentStatus) {
10 | view.getLayoutParams().height = calcStatusBarHeight(view.getContext());
11 | }
12 | }
13 |
14 | public static int calcStatusBarHeight(Context context) {
15 | int statusHeight = -1;
16 | try {
17 | Class> clazz = Class.forName("com.android.internal.R$dimen");
18 | Object object = clazz.newInstance();
19 | int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
20 | statusHeight = context.getResources().getDimensionPixelSize(height);
21 | } catch (Exception e) {
22 | e.printStackTrace();
23 | }
24 | return statusHeight;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/b_gray_dcdcdc_oval.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/b_yellow_ffb100_oval.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/default_avatar.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/default_picture.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dice_action.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
10 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
16 |
17 |
24 |
25 |
31 |
32 |
33 |
37 |
38 |
39 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
24 |
25 |
31 |
32 |
33 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main3.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
20 |
26 |
27 |
28 |
33 |
34 |
43 |
44 |
49 |
50 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main4.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
18 |
19 |
23 |
24 |
34 |
35 |
36 |
46 |
47 |
57 |
58 |
68 |
69 |
79 |
80 |
90 |
91 |
101 |
102 |
112 |
113 |
114 |
121 |
122 |
129 |
130 |
137 |
138 |
145 |
146 |
153 |
154 |
161 |
162 |
169 |
170 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main5.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
24 |
25 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
26 |
27 |
33 |
34 |
40 |
41 |
47 |
48 |
53 |
54 |
60 |
61 |
67 |
68 |
75 |
76 |
83 |
84 |
91 |
92 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_main_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
16 |
23 |
24 |
33 |
34 |
42 |
43 |
49 |
50 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_message_picture.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/dice_action_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxhdpi/dice_action_0.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/dice_action_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxhdpi/dice_action_1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/dice_action_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxhdpi/dice_action_2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/dice_action_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxhdpi/dice_action_3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/app/src/main/res/raw/image.jpg
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #11B7F6
4 | #11B7F6
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 10dip
3 | 3dip
4 | 48dip
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 图片预览
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
6 | maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
7 | jcenter()
8 | google()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.2.1'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
18 | maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
19 | jcenter()
20 | google()
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/gradle.properties
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 26 17:11:54 CST 2018
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-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/lib_glide/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib_glide/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 | buildToolsVersion '28.0.3'
6 | defaultConfig {
7 | minSdkVersion 15
8 | targetSdkVersion 28
9 | }
10 |
11 | buildTypes {
12 | release {
13 | minifyEnabled false
14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
15 | }
16 | }
17 |
18 | compileOptions {
19 | sourceCompatibility JavaVersion.VERSION_1_8
20 | targetCompatibility JavaVersion.VERSION_1_8
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation 'com.github.bumptech.glide:glide:4.8.0'
26 | implementation "com.github.bumptech.glide:okhttp3-integration:4.8.0"
27 | implementation project(path: ':lib_bitmap')
28 | }
29 |
--------------------------------------------------------------------------------
/lib_glide/lib_glide.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
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 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/lib_glide/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
22 |
--------------------------------------------------------------------------------
/lib_glide/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/LibDataFetcher.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.util.Log;
5 |
6 | import com.bumptech.glide.Priority;
7 | import com.bumptech.glide.load.DataSource;
8 | import com.bumptech.glide.load.data.DataFetcher;
9 | import com.bumptech.glide.load.model.GlideUrl;
10 | import com.bumptech.glide.util.ContentLengthInputStream;
11 |
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.util.Map;
15 |
16 | import okhttp3.OkHttpClient;
17 | import okhttp3.Request;
18 | import okhttp3.Response;
19 | import okhttp3.ResponseBody;
20 |
21 | final class LibDataFetcher implements DataFetcher {
22 |
23 | private final OkHttpClient client;
24 | private final GlideUrl url;
25 | private InputStream obtain;
26 | private ResponseBody responseBody;
27 | private volatile boolean isCancelled;
28 |
29 | public LibDataFetcher(OkHttpClient client, GlideUrl url) {
30 | this.client = client;
31 | this.url = url;
32 | }
33 |
34 | @Override
35 | public void loadData(@NonNull Priority priority, @NonNull DataCallback super InputStream> callback) {
36 |
37 | // step1
38 | final Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
39 | // step2
40 | for (Map.Entry headerEntry : url.getHeaders().entrySet()) {
41 | String key = headerEntry.getKey();
42 | requestBuilder.addHeader(key, headerEntry.getValue());
43 | }
44 | // step3
45 | final Request request = requestBuilder.build();
46 | if (isCancelled) {
47 | callback.onLoadFailed(new IOException("已取消"));
48 | }
49 |
50 | try {
51 |
52 | final Response response = client.newCall(request).execute();
53 | responseBody = response.body();
54 |
55 | if (!response.isSuccessful() || responseBody == null) {
56 | throw new IOException("Request failed with code: " + response.code());
57 | }
58 |
59 | obtain = ContentLengthInputStream.obtain(responseBody.byteStream(), responseBody.contentLength());
60 | callback.onDataReady(obtain);
61 |
62 | } catch (Exception e) {
63 | Log.e("kalu", e.getMessage(), e);
64 | callback.onLoadFailed(e);
65 | }
66 | }
67 |
68 | @Override
69 | public void cleanup() {
70 | try {
71 | if (obtain != null) {
72 | obtain.close();
73 | }
74 | if (responseBody != null) {
75 | responseBody.close();
76 | }
77 | } catch (IOException e) {
78 | Log.e("kalu", e.getMessage(), e);
79 | e.printStackTrace();
80 | }
81 | }
82 |
83 | @Override
84 | public void cancel() {
85 | isCancelled = true;
86 | }
87 |
88 | @NonNull
89 | @Override
90 | public Class getDataClass() {
91 | return InputStream.class;
92 | }
93 |
94 | @NonNull
95 | @Override
96 | public DataSource getDataSource() {
97 | return DataSource.REMOTE;
98 | }
99 | }
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/LibGlideUrl.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide;
2 |
3 | import com.bumptech.glide.load.model.GlideUrl;
4 | import com.bumptech.glide.load.model.Headers;
5 |
6 | import java.net.URL;
7 |
8 | public final class LibGlideUrl extends GlideUrl {
9 |
10 | public LibGlideUrl(URL url) {
11 | super(url);
12 | }
13 |
14 | public LibGlideUrl(String url) {
15 | super(url);
16 | }
17 |
18 | public LibGlideUrl(URL url, Headers headers) {
19 | super(url, headers);
20 | }
21 |
22 | public LibGlideUrl(String url, Headers headers) {
23 | super(url, headers);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/LibInterceptor.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide;
2 |
3 | import java.io.IOException;
4 | import java.util.Collections;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | import okhttp3.Interceptor;
9 | import okhttp3.Request;
10 | import okhttp3.Response;
11 | import okhttp3.ResponseBody;
12 |
13 | public final class LibInterceptor implements Interceptor {
14 |
15 | static final Map LISTENER_MAP = Collections.synchronizedMap(new HashMap());
16 |
17 | public static void addListener(String url, ProgressListener listener) {
18 | LISTENER_MAP.put(url, listener);
19 | }
20 |
21 | public static void removeListener(String url) {
22 | LISTENER_MAP.remove(url);
23 | }
24 |
25 | @Override
26 | public Response intercept(Chain chain) throws IOException {
27 | Request request = chain.request();
28 | Response response = chain.proceed(request);
29 | String url = request.url().toString();
30 | ResponseBody body = response.body();
31 | Response newResponse = response.newBuilder().body(new LibResponseBody(url, body)).build();
32 | return newResponse;
33 | }
34 | }
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/LibModelLoader.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.annotation.Nullable;
5 | import android.util.Log;
6 |
7 | import com.bumptech.glide.load.Key;
8 | import com.bumptech.glide.load.Options;
9 | import com.bumptech.glide.load.data.DataFetcher;
10 | import com.bumptech.glide.load.model.GlideUrl;
11 | import com.bumptech.glide.load.model.ModelLoader;
12 | import com.bumptech.glide.load.model.ModelLoaderFactory;
13 | import com.bumptech.glide.load.model.MultiModelLoaderFactory;
14 | import com.bumptech.glide.signature.ObjectKey;
15 |
16 | import java.io.InputStream;
17 |
18 | import okhttp3.OkHttpClient;
19 |
20 | public final class LibModelLoader implements ModelLoader {
21 |
22 | private OkHttpClient okHttpClient;
23 |
24 | public LibModelLoader(OkHttpClient client) {
25 | this.okHttpClient = client;
26 | }
27 |
28 | @Override
29 | public boolean handles(@NonNull GlideUrl glideUrl) {
30 | return false;
31 | }
32 |
33 | @Nullable
34 | @Override
35 | public LoadData buildLoadData(@NonNull GlideUrl glideUrl, int width, int height, @NonNull Options options) {
36 | Log.e("kalu", "buildLoadData");
37 |
38 | final DataFetcher fetcher = new LibDataFetcher(okHttpClient, glideUrl);
39 | final Key sourceKey = new ObjectKey(glideUrl.toString());
40 | return new LoadData<>(sourceKey, fetcher);
41 | }
42 |
43 | public static class Factory implements ModelLoaderFactory {
44 |
45 | private OkHttpClient client;
46 |
47 | public Factory(OkHttpClient client) {
48 | this.client = client;
49 | }
50 |
51 | private synchronized OkHttpClient getOkHttpClient() {
52 | if (client == null) {
53 | client = new OkHttpClient();
54 | }
55 | return client;
56 | }
57 |
58 | @NonNull
59 | @Override
60 | public ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) {
61 | return new LibModelLoader(getOkHttpClient());
62 | }
63 |
64 | @Override
65 | public void teardown() {
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/LibResponseBody.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.IOException;
6 |
7 | import okhttp3.MediaType;
8 | import okhttp3.ResponseBody;
9 | import okio.Buffer;
10 | import okio.BufferedSource;
11 | import okio.ForwardingSource;
12 | import okio.Okio;
13 | import okio.Source;
14 |
15 | final class LibResponseBody extends ResponseBody {
16 |
17 | private BufferedSource bufferedSource;
18 |
19 | private ResponseBody responseBody;
20 |
21 | private ProgressListener listener;
22 |
23 | public LibResponseBody(String url, ResponseBody responseBody) {
24 | this.responseBody = responseBody;
25 | listener = LibInterceptor.LISTENER_MAP.get(url);
26 | }
27 |
28 | @Override
29 | public MediaType contentType() {
30 | return responseBody.contentType();
31 | }
32 |
33 | @Override
34 | public long contentLength() {
35 | return responseBody.contentLength();
36 | }
37 |
38 | @Override
39 | public BufferedSource source() {
40 | if (bufferedSource == null) {
41 | bufferedSource = Okio.buffer(new ProgressSource(responseBody.source()));
42 | }
43 | return bufferedSource;
44 | }
45 |
46 | private class ProgressSource extends ForwardingSource {
47 |
48 | long totalBytesRead = 0;
49 |
50 | int currentProgress;
51 |
52 | ProgressSource(Source source) {
53 | super(source);
54 | }
55 |
56 | @Override
57 | public long read(Buffer sink, long byteCount) throws IOException {
58 | long bytesRead = super.read(sink, byteCount);
59 | long fullLength = responseBody.contentLength();
60 | if (bytesRead == -1) {
61 | totalBytesRead = fullLength;
62 | } else {
63 | totalBytesRead += bytesRead;
64 | }
65 | int progress = (int) (100f * totalBytesRead / fullLength);
66 | Log.e("kalu", "read ==> progress = " + progress);
67 | if (listener != null && progress != currentProgress) {
68 | listener.onProgress(progress);
69 | }
70 | if (listener != null && totalBytesRead == fullLength) {
71 | listener = null;
72 | }
73 | currentProgress = progress;
74 | return bytesRead;
75 | }
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/ProgressListener.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide;
2 |
3 | public interface ProgressListener {
4 |
5 | void onProgress(int progress);
6 | }
7 |
--------------------------------------------------------------------------------
/lib_glide/src/main/java/lib/kalu/glide/util/GlideUtil.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.glide.util;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.PixelFormat;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.net.Uri;
8 | import android.support.annotation.NonNull;
9 | import android.support.annotation.Nullable;
10 | import android.util.Log;
11 | import android.widget.ImageView;
12 |
13 | import com.bumptech.glide.Glide;
14 | import com.bumptech.glide.Priority;
15 | import com.bumptech.glide.RequestBuilder;
16 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
17 | import com.bumptech.glide.request.FutureTarget;
18 | import com.bumptech.glide.request.RequestOptions;
19 | import com.bumptech.glide.request.target.SimpleTarget;
20 | import com.bumptech.glide.request.target.Target;
21 | import com.bumptech.glide.request.transition.Transition;
22 |
23 | import java.io.ByteArrayInputStream;
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.File;
26 | import java.io.InputStream;
27 |
28 | import lib.kalu.bitmap.IntensifyImageView;
29 |
30 | /**
31 | * description: 图片加载工具类
32 | * created by kalu on 2016/11/19 11:58
33 | */
34 | public class GlideUtil {
35 |
36 | private static final String TAG = GlideUtil.class.getSimpleName();
37 |
38 | private static final int defaultImage = -1;
39 |
40 | // 条件设置
41 | // DiskCacheStrategy.NONE 不缓存文件
42 | // DiskCacheStrategy.RESOURCE 只缓存原图
43 | // DiskCacheStrategy.RESULT 只缓存最终加载的图(默认的缓存策略)
44 | // DiskCacheStrategy.ALL 同时缓存原图和结果图
45 | private static final RequestOptions options = new RequestOptions()
46 | .priority(Priority.HIGH)
47 | .diskCacheStrategy(DiskCacheStrategy.ALL);
48 |
49 | public static void loadImage(Context context, ImageView image, String url) {
50 | loadImage(context, image, url, -1, -1, false, false);
51 | }
52 |
53 | // public static void loadLarge(Context context, IntensifyImageView image, String url) {
54 | // loadLarge(context, image, url, -1);
55 | // }
56 |
57 | private static void loadImage(Context context, ImageView image, String url, int placeholder, int scaletype, boolean isCircle, boolean isZip) {
58 |
59 | if (null == context || null == image)
60 | return;
61 |
62 | if (null == url || url.length() == 0)
63 | return;
64 |
65 | if (!url.startsWith("http")) {
66 | image.setImageURI(Uri.fromFile(new File(url)));
67 | return;
68 | }
69 |
70 | final RequestBuilder builder = Glide
71 | .with(context)
72 | .load(url);
73 | if (placeholder != -1) {
74 | options.placeholder(placeholder)
75 | .error(placeholder)
76 | .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
77 | } else if (defaultImage != -1) {
78 | options.placeholder(defaultImage)
79 | .error(defaultImage)
80 | .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
81 | }
82 |
83 | if (isCircle) {
84 | options.circleCrop();
85 | } else if (isZip) {
86 | options.centerInside();
87 | } else {
88 | options.centerInside();
89 | }
90 |
91 | builder.apply(options).into(image);
92 | // builder.apply(options).into(image);
93 | //// builder.apply(options).into(new SimpleTarget() {
94 | //// @Override
95 | //// public void onResourceReady(@NonNull BitmapDrawable resource, @Nullable Transition super Bitmap> transition) {
96 | //// image.setImageBitmap(resource);
97 | //// }
98 | //// });
99 | }
100 |
101 | // private static void loadLarge(Context context, IntensifyImageView image, String url, int placeholder) {
102 | //
103 | // if (null == context || null == image)
104 | // return;
105 | //
106 | // if (null == url || url.length() == 0)
107 | // return;
108 | //
109 | // if (!url.startsWith("http")) {
110 | // try {
111 | // File file = new File(url);
112 | // image.setImage(file);
113 | // } catch (Exception e) {
114 | // Log.e("kalu", e.getMessage(), e);
115 | // }
116 | // return;
117 | // }
118 | //
119 | // final RequestBuilder builder = Glide
120 | // .with(context)
121 | // .load(url);
122 | // if (placeholder != -1) {
123 | // options.placeholder(placeholder)
124 | // .error(placeholder)
125 | // .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
126 | // } else if (defaultImage != -1) {
127 | // options.placeholder(defaultImage)
128 | // .error(defaultImage)
129 | // .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
130 | // }
131 | //
132 | // options.dontAnimate();
133 | // options.dontTransform();
134 | //
135 | // builder.apply(options).into(new SimpleTarget() {
136 | // @Override
137 | // public void onResourceReady(@NonNull BitmapDrawable resource, @Nullable Transition super BitmapDrawable> transition) {
138 | //
139 | // int width = resource.getIntrinsicWidth();
140 | // int height = resource.getIntrinsicHeight();
141 | // int opacity = resource.getOpacity();
142 | // Bitmap bitmap = Bitmap.createBitmap(width, height, opacity != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
143 | //
144 | // ByteArrayOutputStream baos = new ByteArrayOutputStream();
145 | // bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
146 | // InputStream is = new ByteArrayInputStream(baos.toByteArray());
147 | //
148 | // image.setImage(is);
149 | // }
150 | // });
151 | // }
152 |
153 | public static void clear(Context context) {
154 |
155 | new Thread(() -> {
156 | Glide.get(context).clearMemory();
157 | Glide.get(context).clearDiskCache();
158 | }).start();
159 | }
160 |
161 | public static String getPath(Context context, String url) {
162 |
163 | try {
164 |
165 | final FutureTarget future = Glide.with(context)
166 | .load(url)
167 | .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); // 不压缩图片
168 | final File cacheFile = future.get();
169 | return cacheFile.getAbsolutePath();
170 | } catch (Exception e) {
171 | return "";
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/lib_image/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib_image/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 | buildToolsVersion '28.0.3'
6 | defaultConfig {
7 | minSdkVersion 15
8 | targetSdkVersion 27
9 | }
10 |
11 | buildTypes {
12 | release {
13 | minifyEnabled false
14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
15 | }
16 | }
17 |
18 | compileOptions {
19 | sourceCompatibility JavaVersion.VERSION_1_8
20 | targetCompatibility JavaVersion.VERSION_1_8
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation fileTree(include: ['*.jar'], dir: 'libs')
26 | implementation 'com.android.support:appcompat-v7:28.+'
27 | }
28 |
--------------------------------------------------------------------------------
/lib_image/lib_image.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
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 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/lib_image/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
22 |
--------------------------------------------------------------------------------
/lib_image/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib_image/src/main/java/lib/kalu/image/watch/ImageWatcherHelper.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.image.watch;
2 |
3 | import android.app.Activity;
4 | import android.net.Uri;
5 | import android.util.SparseArray;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 |
10 | import java.util.List;
11 |
12 | import lib.kalu.image.R;
13 |
14 |
15 | public class ImageWatcherHelper {
16 | private static final int VIEW_IMAGE_WATCHER_ID = R.id.view_image_watcher;
17 | private final Activity holder;
18 | private final ViewGroup activityDecorView;
19 | private ImageWatcher mImageWatcher;
20 | private ImageWatcher.Loader loader;
21 | private Integer statusBarHeight;
22 | private Integer resErrorImage;
23 | private ImageWatcher.OnPictureLongPressListener listener;
24 | private ImageWatcher.IndexProvider indexProvider;
25 | private ImageWatcher.LoadingUIProvider loadingUIProvider;
26 | private ImageWatcher.OnStateChangedListener onStateChangedListener;
27 |
28 | private ImageWatcherHelper(Activity activity) {
29 | holder = activity;
30 | activityDecorView = (ViewGroup) activity.getWindow().getDecorView();
31 | }
32 |
33 | public static ImageWatcherHelper with(Activity activity, ImageWatcher.Loader l) { // attach
34 | if (activity == null) throw new NullPointerException("activity is null");
35 | if (l == null) throw new NullPointerException("loader is null");
36 | ImageWatcherHelper iwh = new ImageWatcherHelper(activity);
37 | iwh.loader = l;
38 | return iwh;
39 | }
40 |
41 | public ImageWatcherHelper setTranslucentStatus(int statusBarHeight) {
42 | this.statusBarHeight = statusBarHeight;
43 | return this;
44 | }
45 |
46 | public ImageWatcherHelper setErrorImageRes(int resErrorImage) {
47 | this.resErrorImage = resErrorImage;
48 | return this;
49 | }
50 |
51 | public ImageWatcherHelper setOnPictureLongPressListener(ImageWatcher.OnPictureLongPressListener listener) {
52 | this.listener = listener;
53 | return this;
54 | }
55 |
56 | public ImageWatcherHelper setIndexProvider(ImageWatcher.IndexProvider ip) {
57 | indexProvider = ip;
58 | return this;
59 | }
60 |
61 | public ImageWatcherHelper setLoadingUIProvider(ImageWatcher.LoadingUIProvider lp) {
62 | loadingUIProvider = lp;
63 | return this;
64 | }
65 |
66 | public ImageWatcherHelper setOnStateChangedListener(ImageWatcher.OnStateChangedListener listener) {
67 | onStateChangedListener = listener;
68 | return this;
69 | }
70 |
71 | public void show(ImageView i, SparseArray imageGroupList, final List urlList) {
72 | init();
73 | mImageWatcher.show(i, imageGroupList, urlList);
74 | }
75 |
76 | private void init() {
77 | mImageWatcher = new ImageWatcher(holder);
78 | mImageWatcher.setId(VIEW_IMAGE_WATCHER_ID);
79 | mImageWatcher.setLoader(loader);
80 | mImageWatcher.setDetachAffirmative(true); // helper
81 | if (statusBarHeight != null) mImageWatcher.setTranslucentStatus(statusBarHeight);
82 | if (resErrorImage != null) mImageWatcher.setErrorImageRes(resErrorImage);
83 | if (listener != null) mImageWatcher.setOnPictureLongPressListener(listener);
84 | if (indexProvider != null) mImageWatcher.setIndexProvider(indexProvider);
85 | if (loadingUIProvider != null) mImageWatcher.setLoadingUIProvider(loadingUIProvider);
86 | if (onStateChangedListener != null)
87 | mImageWatcher.setOnStateChangedListener(onStateChangedListener);
88 |
89 | removeExistingOverlayInView(activityDecorView); // 理论上是无意义的操作。在ImageWatcher 'dismiss' 时会移除自身。但检查一下不错
90 | activityDecorView.addView(mImageWatcher);
91 | }
92 |
93 | public boolean handleBackPressed() {
94 | return mImageWatcher != null && mImageWatcher.handleBackPressed();
95 | }
96 |
97 | private void removeExistingOverlayInView(ViewGroup parent) {
98 | for (int i = 0; i < parent.getChildCount(); i++) {
99 | View child = parent.getChildAt(i);
100 | if (child.getId() == VIEW_IMAGE_WATCHER_ID) {
101 | parent.removeView(child);
102 | }
103 | if (child instanceof ViewGroup) {
104 | removeExistingOverlayInView((ViewGroup) child);
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/lib_image/src/main/java/lib/kalu/image/watch/ProgressView.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.image.watch;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.graphics.Canvas;
6 | import android.graphics.ColorFilter;
7 | import android.graphics.Paint;
8 | import android.graphics.PixelFormat;
9 | import android.graphics.Rect;
10 | import android.graphics.RectF;
11 | import android.graphics.drawable.AnimationDrawable;
12 | import android.graphics.drawable.Drawable;
13 | import android.support.annotation.NonNull;
14 | import android.util.AttributeSet;
15 | import android.util.DisplayMetrics;
16 | import android.view.View;
17 | import android.view.animation.AccelerateDecelerateInterpolator;
18 | import android.view.animation.Animation;
19 | import android.view.animation.Interpolator;
20 | import android.view.animation.LinearInterpolator;
21 | import android.view.animation.Transformation;
22 |
23 | import java.util.ArrayList;
24 |
25 | /**
26 | * PtrFrameLayout 源码微调
27 | */
28 | public class ProgressView extends View {
29 |
30 | private AnimationDrawable mDrawable;
31 | private float mScale = 1f;
32 |
33 | public ProgressView(Context context) {
34 | this(context, null);
35 | }
36 |
37 | public ProgressView(Context context, AttributeSet attrs) {
38 | super(context, attrs);
39 | initView(new MaterialProgressDrawable(getContext(), this));
40 | }
41 |
42 | private void initView(AnimationDrawable d) {
43 | mDrawable = d;
44 | mDrawable.setAlpha(255);
45 | mDrawable.setCallback(this);
46 | }
47 |
48 | @Override
49 | public void invalidateDrawable(Drawable dr) {
50 | if (dr == mDrawable) {
51 | invalidate();
52 | } else {
53 | super.invalidateDrawable(dr);
54 | }
55 | }
56 |
57 | @Override
58 | public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
59 | super.scheduleDrawable(who, what, when);
60 | }
61 |
62 | public void start() {
63 | mDrawable.start();
64 | }
65 |
66 | public void stop() {
67 | mDrawable.stop();
68 | }
69 |
70 | @Override
71 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
72 | int height = mDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom();
73 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
74 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
75 | }
76 |
77 | @Override
78 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
79 | final int size = mDrawable.getIntrinsicHeight();
80 | mDrawable.setBounds(0, 0, size, size);
81 | }
82 |
83 | @Override
84 | protected void onDraw(Canvas canvas) {
85 | final int saveCount = canvas.save();
86 | Rect rect = mDrawable.getBounds();
87 | int l = getPaddingLeft() + (getMeasuredWidth() - mDrawable.getIntrinsicWidth()) / 2;
88 | canvas.translate(l, getPaddingTop());
89 | canvas.scale(mScale, mScale, rect.exactCenterX(), rect.exactCenterY());
90 | mDrawable.draw(canvas);
91 | canvas.restoreToCount(saveCount);
92 | }
93 |
94 | static class MaterialProgressDrawable extends AnimationDrawable {
95 | private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
96 | private static final Interpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator();
97 | private static final Interpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator();
98 | private static final Interpolator EASE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
99 | // Maps to ProgressBar default style
100 | private static final int CIRCLE_DIAMETER = 30;
101 | private static final float CENTER_RADIUS = 8f; //should add up to 10 when + stroke_width
102 | private static final float STROKE_WIDTH = 2f;
103 | /**
104 | * The duration of a single progress spin in milliseconds.
105 | */
106 | private static final int ANIMATION_DURATION = 1000 * 80 / 60;
107 | /**
108 | * The number of points in the progress "star".
109 | */
110 | private static final float NUM_POINTS = 5f;
111 | private static final float MAX_PROGRESS_ARC = .8f;
112 | private final int[] COLORS = new int[]{
113 | 0xFFFFFFFF,
114 | 0xFFFFFFFF,
115 | 0xFFFFFFFF,
116 | 0xFFFFFFFF
117 | };
118 | /**
119 | * The list of animators operating on this drawable.
120 | */
121 | private final ArrayList mAnimators = new ArrayList();
122 | /**
123 | * The indicator ring, used to manage animation state.
124 | */
125 | private final Ring mRing;
126 | private final Callback mCallback = new Callback() {
127 | @Override
128 | public void invalidateDrawable(Drawable d) {
129 | invalidateSelf();
130 | }
131 |
132 | @Override
133 | public void scheduleDrawable(Drawable d, Runnable what, long when) {
134 | scheduleSelf(what, when);
135 | }
136 |
137 | @Override
138 | public void unscheduleDrawable(Drawable d, Runnable what) {
139 | unscheduleSelf(what);
140 | }
141 | };
142 | /**
143 | * Canvas rotation in degrees.
144 | */
145 | private float mRotation;
146 | private Resources mResources;
147 | private View mParent;
148 | private Animation mAnimation;
149 | private float mRotationCount;
150 | private double mWidth;
151 | private double mHeight;
152 | private Animation mFinishAnimation;
153 |
154 | public MaterialProgressDrawable(Context context, View parent) {
155 | mParent = parent;
156 | mResources = context.getResources();
157 | mRing = new Ring(mCallback);
158 | mRing.setColors(COLORS);
159 | setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH);
160 | setupAnimators();
161 | }
162 |
163 | private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
164 | double centerRadius, double strokeWidth) {
165 | final Ring ring = mRing;
166 | final DisplayMetrics metrics = mResources.getDisplayMetrics();
167 | final float screenDensity = metrics.density;
168 | mWidth = progressCircleWidth * screenDensity;
169 | mHeight = progressCircleHeight * screenDensity;
170 | ring.setStrokeWidth((float) strokeWidth * screenDensity);
171 | ring.setCenterRadius(centerRadius * screenDensity);
172 | ring.setColorIndex(0);
173 | ring.setInsets((int) mWidth, (int) mHeight);
174 | }
175 |
176 | @Override
177 | public int getIntrinsicHeight() {
178 | return (int) mHeight;
179 | }
180 |
181 | @Override
182 | public int getIntrinsicWidth() {
183 | return (int) mWidth;
184 | }
185 |
186 | @Override
187 | public void draw(Canvas c) {
188 |
189 | final Rect bounds = getBounds();
190 | final int saveCount = c.save();
191 | c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
192 | mRing.draw(c, bounds);
193 | c.restoreToCount(saveCount);
194 | }
195 |
196 | public int getAlpha() {
197 | return mRing.getAlpha();
198 | }
199 |
200 | @Override
201 | public void setAlpha(int alpha) {
202 | mRing.setAlpha(alpha);
203 | }
204 |
205 | @Override
206 | public void setColorFilter(ColorFilter colorFilter) {
207 | mRing.setColorFilter(colorFilter);
208 | }
209 |
210 |
211 | void setRotation(float rotation) {
212 | mRotation = rotation;
213 | invalidateSelf();
214 | }
215 |
216 | @Override
217 | public int getOpacity() {
218 | return PixelFormat.TRANSLUCENT;
219 | }
220 |
221 | @Override
222 | public boolean isRunning() {
223 | final ArrayList animators = mAnimators;
224 | final int N = animators.size();
225 | for (int i = 0; i < N; i++) {
226 | final Animation animator = animators.get(i);
227 | if (animator.hasStarted() && !animator.hasEnded()) {
228 | return true;
229 | }
230 | }
231 | return false;
232 | }
233 |
234 | @Override
235 | public void start() {
236 | mAnimation.reset();
237 | mRing.storeOriginals();
238 | // Already showing some part of the ring
239 | if (mRing.getEndTrim() != mRing.getStartTrim()) {
240 | mParent.startAnimation(mFinishAnimation);
241 | } else {
242 | mRing.setColorIndex(0);
243 | mRing.resetOriginals();
244 | mParent.startAnimation(mAnimation);
245 | }
246 | }
247 |
248 | @Override
249 | public void stop() {
250 | mParent.clearAnimation();
251 | setRotation(0);
252 | mRing.setShowArrow(false);
253 | mRing.setColorIndex(0);
254 | mRing.resetOriginals();
255 | }
256 |
257 | private void setupAnimators() {
258 | final Ring ring = mRing;
259 | final Animation finishRingAnimation = new Animation() {
260 | public void applyTransformation(float interpolatedTime, Transformation t) {
261 | // shrink back down and complete a full rotation before starting other circles
262 | // Rotation goes between [0..1].
263 | float targetRotation = (float) (Math.floor(ring.getStartingRotation()
264 | / MAX_PROGRESS_ARC) + 1f);
265 | final float startTrim = ring.getStartingStartTrim()
266 | + (ring.getStartingEndTrim() - ring.getStartingStartTrim())
267 | * interpolatedTime;
268 | ring.setStartTrim(startTrim);
269 | final float rotation = ring.getStartingRotation()
270 | + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
271 | ring.setRotation(rotation);
272 | ring.setArrowScale(1 - interpolatedTime);
273 | }
274 | };
275 | finishRingAnimation.setInterpolator(EASE_INTERPOLATOR);
276 | finishRingAnimation.setDuration(ANIMATION_DURATION / 2);
277 | finishRingAnimation.setAnimationListener(new Animation.AnimationListener() {
278 | @Override
279 | public void onAnimationStart(Animation animation) {
280 | }
281 |
282 | @Override
283 | public void onAnimationEnd(Animation animation) {
284 | ring.goToNextColor();
285 | ring.storeOriginals();
286 | ring.setShowArrow(false);
287 | mParent.startAnimation(mAnimation);
288 | }
289 |
290 | @Override
291 | public void onAnimationRepeat(Animation animation) {
292 | }
293 | });
294 | final Animation animation = new Animation() {
295 | @Override
296 | public void applyTransformation(float interpolatedTime, Transformation t) {
297 | // The minProgressArc is calculated from 0 to create an angle that
298 | // matches the stroke width.
299 | final float minProgressArc = (float) Math.toRadians(ring.getStrokeWidth()
300 | / (2 * Math.PI * ring.getCenterRadius()));
301 | final float startingEndTrim = ring.getStartingEndTrim();
302 | final float startingTrim = ring.getStartingStartTrim();
303 | final float startingRotation = ring.getStartingRotation();
304 | // Offset the minProgressArc to where the endTrim is located.
305 | final float minArc = MAX_PROGRESS_ARC - minProgressArc;
306 | final float endTrim = startingEndTrim
307 | + (minArc * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime));
308 | ring.setEndTrim(endTrim);
309 | final float startTrim = startingTrim
310 | + (MAX_PROGRESS_ARC * END_CURVE_INTERPOLATOR
311 | .getInterpolation(interpolatedTime));
312 | ring.setStartTrim(startTrim);
313 | final float rotation = startingRotation + (0.25f * interpolatedTime);
314 | ring.setRotation(rotation);
315 | float groupRotation = ((720.0f / NUM_POINTS) * interpolatedTime)
316 | + (720.0f * (mRotationCount / NUM_POINTS));
317 | setRotation(groupRotation);
318 | }
319 | };
320 | animation.setRepeatCount(Animation.INFINITE);
321 | animation.setRepeatMode(Animation.RESTART);
322 | animation.setInterpolator(LINEAR_INTERPOLATOR);
323 | animation.setDuration(ANIMATION_DURATION);
324 | animation.setAnimationListener(new Animation.AnimationListener() {
325 | @Override
326 | public void onAnimationStart(Animation animation) {
327 | mRotationCount = 0;
328 | }
329 |
330 | @Override
331 | public void onAnimationEnd(Animation animation) {
332 | // do nothing
333 | }
334 |
335 | @Override
336 | public void onAnimationRepeat(Animation animation) {
337 | ring.storeOriginals();
338 | ring.goToNextColor();
339 | ring.setStartTrim(ring.getEndTrim());
340 | mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
341 | }
342 | });
343 | mFinishAnimation = finishRingAnimation;
344 | mAnimation = animation;
345 | }
346 |
347 | private static class Ring {
348 | private final RectF mTempBounds = new RectF();
349 | private final Paint mArcPaint = new Paint();
350 | private final Paint mArrowPaint = new Paint();
351 | private final Callback mRingCallback;
352 | private final Paint mCirclePaint = new Paint();
353 | private float mStartTrim = 0.0f;
354 | private float mEndTrim = 0.0f;
355 | private float mRotation = 0.0f;
356 | private float mStrokeWidth = 5.0f;
357 | private float mStrokeInset = 2.5f;
358 | private int[] mColors;
359 | // mColorIndex represents the offset into the available mColors that the
360 | // progress circle should currently display. As the progress circle is
361 | // animating, the mColorIndex moves by one to the next available color.
362 | private int mColorIndex;
363 | private float mStartingStartTrim;
364 | private float mStartingEndTrim;
365 | private float mStartingRotation;
366 | private boolean mShowArrow;
367 | private float mArrowScale;
368 | private double mRingCenterRadius;
369 | private int mAlpha;
370 |
371 | public Ring(Callback callback) {
372 | mRingCallback = callback;
373 | mArcPaint.setStrokeCap(Paint.Cap.SQUARE);
374 | mArcPaint.setAntiAlias(true);
375 | mArcPaint.setStyle(Paint.Style.STROKE);
376 | mArrowPaint.setStyle(Paint.Style.FILL);
377 | mArrowPaint.setAntiAlias(true);
378 | mCirclePaint.setAntiAlias(true);
379 | }
380 |
381 |
382 | /**
383 | * Draw the progress spinner
384 | */
385 | public void draw(Canvas c, Rect bounds) {
386 |
387 | final RectF arcBounds = mTempBounds;
388 | arcBounds.set(bounds);
389 | arcBounds.inset(mStrokeInset, mStrokeInset);
390 | final float startAngle = (mStartTrim + mRotation) * 360;
391 | final float endAngle = (mEndTrim + mRotation) * 360;
392 | float sweepAngle = endAngle - startAngle;
393 | mArcPaint.setColor(mColors[mColorIndex]);
394 | mArcPaint.setAlpha(mAlpha);
395 | c.drawArc(arcBounds, startAngle, sweepAngle, false, mArcPaint);
396 | }
397 |
398 |
399 | /**
400 | * Set the colors the progress spinner alternates between.
401 | *
402 | * @param colors Array of integers describing the colors. Must be non-null
.
403 | */
404 | public void setColors(int[] colors) {
405 | mColors = colors;
406 | // if colors are reset, make sure to reset the color index as well
407 | setColorIndex(0);
408 | }
409 |
410 | /**
411 | * @param index Index into the color array of the color to display in
412 | * the progress spinner.
413 | */
414 | public void setColorIndex(int index) {
415 | mColorIndex = index;
416 | }
417 |
418 | /**
419 | * Proceed to the next available ring color. This will automatically
420 | * wrap back to the beginning of colors.
421 | */
422 | public void goToNextColor() {
423 | mColorIndex = (mColorIndex + 1) % (mColors.length);
424 | }
425 |
426 | public void setColorFilter(ColorFilter filter) {
427 | mArcPaint.setColorFilter(filter);
428 | invalidateSelf();
429 | }
430 |
431 | /**
432 | * @return Current alpha of the progress spinner and arrowhead.
433 | */
434 | public int getAlpha() {
435 | return mAlpha;
436 | }
437 |
438 | /**
439 | * @param alpha Set the alpha of the progress spinner and associated arrowhead.
440 | */
441 | public void setAlpha(int alpha) {
442 | mAlpha = alpha;
443 | }
444 |
445 |
446 | public float getStrokeWidth() {
447 | return mStrokeWidth;
448 | }
449 |
450 | /**
451 | * @param strokeWidth Set the stroke width of the progress spinner in pixels.
452 | */
453 | public void setStrokeWidth(float strokeWidth) {
454 | mStrokeWidth = strokeWidth;
455 | mArcPaint.setStrokeWidth(strokeWidth);
456 | invalidateSelf();
457 | }
458 |
459 |
460 | public float getStartTrim() {
461 | return mStartTrim;
462 | }
463 |
464 |
465 | public void setStartTrim(float startTrim) {
466 | mStartTrim = startTrim;
467 | invalidateSelf();
468 | }
469 |
470 | public float getStartingStartTrim() {
471 | return mStartingStartTrim;
472 | }
473 |
474 | public float getStartingEndTrim() {
475 | return mStartingEndTrim;
476 | }
477 |
478 |
479 | public float getEndTrim() {
480 | return mEndTrim;
481 | }
482 |
483 |
484 | public void setEndTrim(float endTrim) {
485 | mEndTrim = endTrim;
486 | invalidateSelf();
487 | }
488 |
489 | public void setRotation(float rotation) {
490 | mRotation = rotation;
491 | invalidateSelf();
492 | }
493 |
494 | public void setInsets(int width, int height) {
495 | final float minEdge = (float) Math.min(width, height);
496 | float insets;
497 | if (mRingCenterRadius <= 0 || minEdge < 0) {
498 | insets = (float) Math.ceil(mStrokeWidth / 2.0f);
499 | } else {
500 | insets = (float) (minEdge / 2.0f - mRingCenterRadius);
501 | }
502 | mStrokeInset = insets;
503 | }
504 |
505 |
506 | public float getInsets() {
507 | return mStrokeInset;
508 | }
509 |
510 | public double getCenterRadius() {
511 | return mRingCenterRadius;
512 | }
513 |
514 | /**
515 | * @param centerRadius Inner radius in px of the circle the progress
516 | * spinner arc traces.
517 | */
518 | public void setCenterRadius(double centerRadius) {
519 | mRingCenterRadius = centerRadius;
520 | }
521 |
522 | /**
523 | * @param show Set to true to show the arrow head on the progress spinner.
524 | */
525 | public void setShowArrow(boolean show) {
526 | if (mShowArrow != show) {
527 | mShowArrow = show;
528 | invalidateSelf();
529 | }
530 | }
531 |
532 | /**
533 | * @param scale Set the scale of the arrowhead for the spinner.
534 | */
535 | public void setArrowScale(float scale) {
536 | if (scale != mArrowScale) {
537 | mArrowScale = scale;
538 | invalidateSelf();
539 | }
540 | }
541 |
542 | /**
543 | * @return The amount the progress spinner is currently rotated, between [0..1].
544 | */
545 | public float getStartingRotation() {
546 | return mStartingRotation;
547 | }
548 |
549 | /**
550 | * If the start / end trim are offset to begin with, store them so that
551 | * animation starts from that offset.
552 | */
553 | public void storeOriginals() {
554 | mStartingStartTrim = mStartTrim;
555 | mStartingEndTrim = mEndTrim;
556 | mStartingRotation = mRotation;
557 | }
558 |
559 | /**
560 | * Reset the progress spinner to default rotation, start and end angles.
561 | */
562 | public void resetOriginals() {
563 | mStartingStartTrim = 0;
564 | mStartingEndTrim = 0;
565 | mStartingRotation = 0;
566 | setStartTrim(0);
567 | setEndTrim(0);
568 | setRotation(0);
569 | }
570 |
571 | private void invalidateSelf() {
572 | mRingCallback.invalidateDrawable(null);
573 | }
574 | }
575 |
576 | /**
577 | * Squishes the interpolation curve into the second half of the animation.
578 | */
579 | private static class EndCurveInterpolator extends AccelerateDecelerateInterpolator {
580 | @Override
581 | public float getInterpolation(float input) {
582 | return super.getInterpolation(Math.max(0, (input - 0.5f) * 2.0f));
583 | }
584 | }
585 |
586 | /**
587 | * Squishes the interpolation curve into the first half of the animation.
588 | */
589 | private static class StartCurveInterpolator extends AccelerateDecelerateInterpolator {
590 | @Override
591 | public float getInterpolation(float input) {
592 | return super.getInterpolation(Math.min(1, input * 2.0f));
593 | }
594 | }
595 | }
596 | }
597 |
--------------------------------------------------------------------------------
/lib_image/src/main/java/lib/kalu/image/watch/ViewState.java:
--------------------------------------------------------------------------------
1 | package lib.kalu.image.watch;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ValueAnimator;
5 | import android.view.View;
6 |
7 | import lib.kalu.image.R;
8 |
9 | /**
10 | * ViewState包含记录了一个View的瞬时UI状态
11 | * 并且提供了给View新增状态,抓取View的当前状态,复制View的状态,将View还原至该状态等便捷方法
12 | */
13 | class ViewState {
14 | static final int STATE_ORIGIN = R.id.state_origin; // 缩略图初始
15 | static final int STATE_THUMB = R.id.state_thumb; // 缩略图居中
16 | static final int STATE_DEFAULT = R.id.state_default; // 高清图初始
17 | static final int STATE_CURRENT = R.id.state_current; // 当前状态
18 | static final int STATE_TEMP = R.id.state_temp; // 临时目标
19 | static final int STATE_DRAG = R.id.state_touch_drag; // 高清图拖拽起点
20 | static final int STATE_EXIT = R.id.state_exit; // 高清图退出起点
21 | static final int STATE_TOUCH_SCALE = R.id.state_touch_scale; // 高清图缩放起点
22 |
23 | int mTag;
24 | int width;
25 | int height;
26 | float translationX;
27 | float translationY;
28 | float scaleX;
29 | float scaleY;
30 | float alpha;
31 |
32 | private ViewState(int tag) {
33 | mTag = tag;
34 | }
35 |
36 | static ViewState write(View view, int tag) {
37 | if (view == null) return null;
38 |
39 | ViewState vs = read(view, tag);
40 | if (vs == null) view.setTag(tag, vs = new ViewState(tag));
41 |
42 | vs.width = view.getWidth();
43 | vs.height = view.getHeight();
44 | vs.translationX = view.getTranslationX();
45 | vs.translationY = view.getTranslationY();
46 | vs.scaleX = view.getScaleX();
47 | vs.scaleY = view.getScaleY();
48 | vs.alpha = view.getAlpha();
49 | return vs;
50 | }
51 |
52 | static ViewState read(View view, int tag) {
53 | if (view == null) return null;
54 | return view.getTag(tag) != null ? (ViewState) view.getTag(tag) : null;
55 | }
56 |
57 | static void clear(View view, int tag) {
58 | if (view == null) return;
59 | view.setTag(tag, null);
60 | }
61 |
62 | static ViewState copy(ViewState mir, int tag) {
63 | ViewState vs = new ViewState(tag);
64 | vs.width = mir.width;
65 | vs.height = mir.height;
66 | vs.translationX = mir.translationX;
67 | vs.translationY = mir.translationY;
68 | vs.scaleX = mir.scaleX;
69 | vs.scaleY = mir.scaleY;
70 | vs.alpha = mir.alpha;
71 | return vs;
72 | }
73 |
74 | static void restore(View view, int tag) {
75 | ViewState viewState = read(view, tag);
76 | if (viewState != null) {
77 | view.setTranslationX(viewState.translationX);
78 | view.setTranslationY(viewState.translationY);
79 | view.setScaleX(viewState.scaleX);
80 | view.setScaleY(viewState.scaleY);
81 | view.setAlpha(viewState.alpha);
82 | if (view.getLayoutParams().width != viewState.width || view.getLayoutParams().height != viewState.height) {
83 | view.getLayoutParams().width = viewState.width;
84 | view.getLayoutParams().height = viewState.height;
85 | view.requestLayout();
86 | }
87 | }
88 | }
89 |
90 | static ValueAnimatorBuilder restoreByAnim(final View view, int tag) {
91 | ValueAnimator animator = null;
92 | if (view != null) {
93 | final ViewState vsCurrent = ViewState.write(view, ViewState.STATE_CURRENT);
94 | if (vsCurrent.width == 0 && vsCurrent.height == 0) {
95 | ViewState vsOrigin = ViewState.read(view, ViewState.STATE_ORIGIN);
96 | if (vsOrigin != null) vsCurrent.width(vsOrigin.width).height(vsOrigin.height);
97 | }
98 | final ViewState vsResult = read(view, tag);
99 | if (vsResult != null) {
100 | animator = ValueAnimator.ofFloat(0, 1).setDuration(200);
101 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
102 | @Override
103 | public void onAnimationUpdate(ValueAnimator animation) {
104 | float p = (float) animation.getAnimatedValue();
105 | view.setTranslationX(vsCurrent.translationX + (vsResult.translationX - vsCurrent.translationX) * p);
106 | view.setTranslationY(vsCurrent.translationY + (vsResult.translationY - vsCurrent.translationY) * p);
107 | view.setScaleX(vsCurrent.scaleX + (vsResult.scaleX - vsCurrent.scaleX) * p);
108 | view.setScaleY(vsCurrent.scaleY + (vsResult.scaleY - vsCurrent.scaleY) * p);
109 | view.setAlpha((vsCurrent.alpha + (vsResult.alpha - vsCurrent.alpha) * p));
110 | if (vsCurrent.width != vsResult.width && vsCurrent.height != vsResult.height
111 | && vsResult.width != 0 && vsResult.height != 0) {
112 | view.getLayoutParams().width = (int) (vsCurrent.width + (vsResult.width - vsCurrent.width) * p);
113 | view.getLayoutParams().height = (int) (vsCurrent.height + (vsResult.height - vsCurrent.height) * p);
114 | view.requestLayout();
115 | }
116 | }
117 | });
118 | }
119 | }
120 | return new ValueAnimatorBuilder(animator);
121 | }
122 |
123 | static class ValueAnimatorBuilder {
124 | ValueAnimator mAnimator;
125 |
126 | ValueAnimatorBuilder(ValueAnimator animator) {
127 | mAnimator = animator;
128 | }
129 |
130 | ValueAnimatorBuilder addListener(Animator.AnimatorListener listener) {
131 | if (mAnimator != null) mAnimator.addListener(listener);
132 | return this;
133 | }
134 |
135 | ValueAnimator create() {
136 | return mAnimator;
137 | }
138 | }
139 |
140 | ViewState scaleX(float scaleX) {
141 | this.scaleX = scaleX;
142 | return this;
143 | }
144 |
145 | ViewState scaleXBy(float value) {
146 | this.scaleX *= value;
147 | return this;
148 | }
149 |
150 | ViewState scaleY(float scaleY) {
151 | this.scaleY = scaleY;
152 | return this;
153 | }
154 |
155 | ViewState scaleYBy(float value) {
156 | this.scaleY *= value;
157 | return this;
158 | }
159 |
160 |
161 | ViewState width(int width) {
162 | this.width = width;
163 | return this;
164 | }
165 |
166 | ViewState height(int height) {
167 | this.height = height;
168 | return this;
169 | }
170 |
171 | ViewState translationX(float translationX) {
172 | this.translationX = translationX;
173 | return this;
174 | }
175 |
176 | ViewState translationY(float translationY) {
177 | this.translationY = translationY;
178 | return this;
179 | }
180 |
181 | ViewState alpha(float alpha) {
182 | this.alpha = alpha;
183 | return this;
184 | }
185 | }
--------------------------------------------------------------------------------
/lib_image/src/main/res/mipmap-xxhdpi/error_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalu-github/module_image_watch/8dbaebbb1eb0ebbefb8242e153a1fcebcda22770/lib_image/src/main/res/mipmap-xxhdpi/error_picture.png
--------------------------------------------------------------------------------
/lib_image/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib_image/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | lib_photo
3 |
4 |
--------------------------------------------------------------------------------
/lib_image/src/main/res/values/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Tue Feb 19 17:16:16 CST 2019
8 | ndk.dir=D\:\\android\\sdkw\\ndk-bundle
9 | sdk.dir=D\:\\android\\sdkw
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':lib_image'
3 |
--------------------------------------------------------------------------------