├── .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 | 8 | 9 | 10 | 11 | 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 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 |