├── .gitignore ├── .idea ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── .travis.yml ├── README.md ├── Sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── about.html │ └── about.md │ ├── java │ └── com │ │ └── sunfusheng │ │ └── glideimageview │ │ └── sample │ │ ├── BaseActivity.java │ │ ├── MainActivity.java │ │ ├── NineImageViewActivity.java │ │ ├── RecyclerViewActivity.java │ │ ├── about │ │ ├── AboutActivity.java │ │ └── WebViewWrapper.java │ │ ├── image │ │ ├── FixedViewPager.java │ │ ├── ImagesActivity.java │ │ ├── ImagesAdapter.java │ │ ├── NineImageViewEventAdapter.java │ │ └── SingleImageActivity.java │ │ ├── model │ │ ├── ImageModel.java │ │ ├── ModelUtil.java │ │ └── NewsModel.java │ │ ├── util │ │ ├── AppUtil.java │ │ ├── ColorUtil.java │ │ └── StatusBarUtil.java │ │ └── widget │ │ ├── DraggableFrameLayout.java │ │ └── SlideVerticallyLayout.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── drawable_corner_icon_bg.xml │ ├── gif_robot_walk.gif │ ├── ic_launcher_background.xml │ └── progressbar_orange_selector.xml │ ├── layout │ ├── activity_about.xml │ ├── activity_image.xml │ ├── activity_main.xml │ ├── activity_preview.xml │ ├── item_nine_images.xml │ ├── item_photoview.xml │ ├── item_right_image.xml │ ├── item_three_images.xml │ ├── item_top_image.xml │ ├── layout_image_cell.xml │ ├── layout_recyclerview.xml │ ├── layout_roundimageview.xml │ └── layout_webview.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-anydpi-v26 │ └── ic_launcher.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_multi_imageview.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_multi_imageview.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── she.png │ ├── values-v21 │ └── styles.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── colors_material.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── glideimageview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── sunfusheng │ │ ├── GlideImageLoader.java │ │ ├── GlideImageView.java │ │ ├── progress │ │ ├── CircleProgressView.java │ │ ├── OnProgressListener.java │ │ ├── ProgressAppGlideModule.java │ │ ├── ProgressManager.java │ │ └── ProgressResponseBody.java │ │ ├── transformation │ │ ├── BlurTransformation.java │ │ ├── CircleTransformation.java │ │ └── RadiusTransformation.java │ │ ├── util │ │ ├── BlurUtils.java │ │ └── Utils.java │ │ └── widget │ │ ├── GridLayoutHelper.java │ │ ├── ImageCell.java │ │ ├── ImageData.java │ │ ├── LayoutHelper.java │ │ └── NineImageView.java │ └── res │ ├── drawable │ ├── drawable_image_bg_0dp.xml │ └── drawable_image_bg_5dp.xml │ ├── mipmap-hdpi │ ├── image_load_err.png │ └── image_loading.png │ ├── mipmap-xhdpi │ ├── image_load_err.png │ └── image_loading.png │ ├── mipmap-xxhdpi │ ├── image_load_err.png │ └── image_loading.png │ └── values │ ├── colors.xml │ └── style.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── resources ├── cat.jpg ├── cat_thumbnail.jpg ├── gif1.gif ├── gif2.gif ├── gif3.gif ├── gif4.gif ├── gif5.gif ├── gif6.gif ├── girl.jpg ├── girl_thumbnail.jpg ├── image1.png ├── image2.png ├── image3.png ├── image4.png └── image5.png ├── settings.gradle └── signings ├── keystore.jks ├── keystore.jks.enc └── signing.properties /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | sudo: true 4 | 5 | android: 6 | components: 7 | - tools 8 | - platform-tools 9 | - tools 10 | - build-tools-28.0.3 11 | - android-28 12 | - sys-img-armeabi-v7a-android-28 13 | - extra-android-support 14 | - extra-android-m2repository 15 | - extra-google-m2repository 16 | - add-on 17 | - extra 18 | licenses: 19 | - android-sdk-preview-license-52d11cd2 20 | - android-sdk-license-.+ 21 | - google-gdk-license-.+ 22 | 23 | before_cache: 24 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 25 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 26 | 27 | cache: 28 | directories: 29 | - "$HOME/.gradle/caches/" 30 | - "$HOME/.gradle/wrapper/" 31 | - "$HOME/.android/build-cache" 32 | 33 | before_install: 34 | - mkdir "$ANDROID_HOME/licenses" || true 35 | - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" 36 | - openssl aes-256-cbc -K $encrypted_0f82fc3ea788_key -iv $encrypted_0f82fc3ea788_iv 37 | -in signings/keystore.jks.enc -out signings/keystore.jks -d 38 | - gem install fir-cli 39 | 40 | before_script: 41 | - chmod +x gradlew 42 | 43 | script: 44 | - "./gradlew assembleRelease" 45 | 46 | deploy: 47 | provider: releases 48 | api_key: 49 | secure: BwzVE9rrCLQ1CKalfO66vdBVrpajt1AZVzG8n2qwRSRQxIKabnQht2NCEVWA9jBCGan6ahKG3ZV4Ky5Xeue49FZHb69zuvi7pdhL2AVGDv/T48TXks39FviJD40gSvtOC9H8ju5LokRBoTs74bdhg/weu0fbwjarioS+gsx/AdLYoji5xpe+FaCuwZEKRQ2Cer000XSntmm4d91oW1gJ9DiBLEyb0eEA4t0Trd+zCvC38pv5+sEEag1FIOnOnwc5dixozL0FSSSSPC3mDMxLJL0cgrDmSHzhRL6/DOb/taRGpAyyhOlrIn1H6fPcot8oQFPMv9LUzltYrdYjaKEgg5fGP/+4GVA50UqmQ7UEdtN6i1+UqfnRtkAugJRozy6M0+c8fgg9l5eZfH0jXCpNL8wYsTC0nmDnsG5kLayIM23nQRQOeYEoIiPZxnwvwCwyVZ0GbTEQIql/GHHBpcW9fjBDASsnK3CGtVVf/EHzU/5f0Y71GSPJ5DUHl79ZBNmw+fYkjuoAIt27vP+sf3WPAkGOUGT7PvwpAEe16Xh8cYr37R/Ryuw57Rk3vN/Js0pCqlDymIjMeOIeU57RK8KXKsqrYQtleC8Erjx89eeq1oqq/zZ2g3gFl31c9ajiCjjSpkMR+df518tqgfa40/SfqHX+oz6ihAsCs2PGwqPG8ig= 50 | file: sample/release/GlideImageView.apk 51 | skip_cleanup: true 52 | on: 53 | repo: sunfusheng/GlideImageView 54 | tags: true 55 | all_branches: true 56 | 57 | after_deploy: 58 | - "./gradlew clean build bintrayUpload -PbintrayUser=sunfusheng -PbintrayKey=$BINTRAY_TOKEN -PdryRun=false" 59 | - fir p sample/release/GlideImageView.apk -T $FIR_TOKEN -c "基于Glide V4.9.0封装的图片加载库,可以监听加载图片时的进度" 60 | 61 | notifications: 62 | email: 63 | - sfsheng0322@126.com -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GlideImageView [ ![Download](https://api.bintray.com/packages/sfsheng0322/maven/GlideImageView/images/download.svg) ](https://bintray.com/sfsheng0322/maven/GlideImageView/_latestVersion) 2 | 3 | ### 该库是基于[Glide](https://github.com/bumptech/glide) V4.9.0设计的,实现如下特性:
4 | 1、监听加载网络图片的进度
5 | 2、动态加载成有弧度的图片、圆形图片、高斯模糊图片更方便
6 | 3、链式设置触摸图片的透明度和非使能的透明度
7 | 4、增加九宫格控件,具体使用参考[NineImageViewActivity](https://github.com/sunfusheng/GlideImageView/blob/master/Sample/src/main/java/com/sunfusheng/glideimageview/sample/NineImageViewActivity.java)
8 | 9 |
10 | 11 | ### 监听加载高清图片进度的效果图 12 | 13 | 14 | 15 |
16 | 17 | ### [APK下载地址](https://fir.im/GlideImageView),去手机上体验吧 (◐‿◑) 18 | 19 |
20 | 21 | ### 具体使用说明如下 22 | 23 | #### Gradle: 24 | 25 | compile 'com.sunfusheng:GlideImageView:' 26 | 27 |
28 | 29 | #### GlideImageView 主要方法 30 | 31 | load(String url, @DrawableRes int placeholder, int radius, OnProgressListener onProgressListener) 32 | 33 | load(Object obj, @DrawableRes int placeholder, Transformation transformation, OnProgressListener onProgressListener) 34 | 35 | loadCircle(String url, @DrawableRes int placeholder, OnProgressListener onProgressListener) 36 | 37 | loadDrawable(@DrawableRes int resId, @DrawableRes int placeholder) 38 | 39 |
40 | 41 | ### 个人微信公众号 42 | 43 | 44 | 45 |
46 | 47 | ### 关于我 48 | 49 | [GitHub: sunfusheng](https://github.com/sunfusheng) 50 | 51 | [个人邮箱: sfsheng0322@126.com](https://mail.126.com/) 52 | 53 | [个人博客: sunfusheng.com](http://sunfusheng.com/) 54 | 55 | [简书主页](http://www.jianshu.com/users/88509e7e2ed1/latest_articles) 56 | 57 | [新浪微博](http://weibo.com/u/3852192525) -------------------------------------------------------------------------------- /Sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /Sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | Properties signingProperties = new Properties() 4 | signingProperties.load(new FileInputStream(file("../signings/signing.properties"))) 5 | 6 | android { 7 | compileSdkVersion COMPILE_SDK_VERSION 8 | defaultConfig { 9 | applicationId "com.sunfusheng.glideimageview.sample" 10 | minSdkVersion MIN_SDK_VERSION 11 | targetSdkVersion TARGET_SDK_VERSION 12 | versionCode VERSION_CODE 13 | versionName VERSION_NAME 14 | } 15 | 16 | compileOptions { 17 | sourceCompatibility JavaVersion.VERSION_1_8 18 | targetCompatibility JavaVersion.VERSION_1_8 19 | } 20 | 21 | lintOptions { 22 | abortOnError false 23 | } 24 | 25 | signingConfigs { 26 | release { 27 | storeFile file(signingProperties['KEYSTORE_FILEPATH']) 28 | storePassword signingProperties['STORE_PASSWORD'] 29 | keyAlias signingProperties['KEY_ALIAS'] 30 | keyPassword signingProperties['KEY_PASSWORD'] 31 | } 32 | } 33 | 34 | buildTypes { 35 | debug { 36 | signingConfig signingConfigs.release 37 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 38 | } 39 | release { 40 | signingConfig signingConfigs.release 41 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 42 | applicationVariants.all { variant -> 43 | variant.outputs.all { 44 | outputFileName = "GlideImageView.apk" 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | dependencies { 52 | api 'com.android.support:appcompat-v7:' + SUPPORT_LIBRARY_VERSION 53 | api 'com.android.support:percent:' + SUPPORT_LIBRARY_VERSION 54 | api 'com.android.support:design:' + SUPPORT_LIBRARY_VERSION 55 | api 'com.android.support.constraint:constraint-layout:1.1.3' 56 | api 'com.github.chrisbanes:PhotoView:2.1.3' 57 | 58 | // api 'com.sunfusheng:FirUpdater:1.1.1' 59 | api project(':glideimageview') 60 | } 61 | -------------------------------------------------------------------------------- /Sample/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 /Users/sunfusheng/Android/Studio/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 | -------------------------------------------------------------------------------- /Sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Sample/src/main/assets/about.md: -------------------------------------------------------------------------------- 1 | #### GlideImageView 2 | 3 | #### 该库是基于[Glide](https://github.com/bumptech/glide) V4.9.0设计的,实现如下特性:
4 | 1、监听加载网络图片的进度
5 | 2、动态加载成有弧度的图片、圆形图片、高斯模糊图片更方便
6 | 3、链式设置触摸图片的透明度和非使能的透明度
7 | 4、增加九宫格控件,具体使用参考
8 | 9 | #### GitHub地址 10 | 11 | [https://github.com/sunfusheng/GlideImageView](https://github.com/sunfusheng/GlideImageView) 12 | 13 | #### 关于我 14 | 15 | 个人邮箱:sfsheng0322@126.com 16 | [GitHub主页](https://github.com/sunfusheng) 17 | [简书主页](http://www.jianshu.com/users/88509e7e2ed1/latest_articles) 18 | [个人博客](http://sunfusheng.com/) 19 | [新浪微博](http://weibo.com/u/3852192525) 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | 10 | import com.sunfusheng.glideimageview.sample.util.StatusBarUtil; 11 | 12 | /** 13 | * Created by sunfusheng on 2016/12/24. 14 | */ 15 | public abstract class BaseActivity extends AppCompatActivity { 16 | 17 | protected Activity mActivity; 18 | protected Context mContext; 19 | 20 | @Override 21 | protected void onCreate(@Nullable Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | mActivity = this; 24 | mContext = this; 25 | } 26 | 27 | protected void setStatusBarTranslucent(boolean isLightStatusBar) { 28 | StatusBarUtil.setStatusBarTranslucent(this, isLightStatusBar); 29 | } 30 | 31 | @Override 32 | public void startActivity(Intent intent) { 33 | super.startActivity(intent); 34 | if (intent == null) return; 35 | if (intent.getComponent() == null) return; 36 | String className = intent.getComponent().getClassName(); 37 | if (!className.equals(MainActivity.class.getName())) { 38 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); 39 | } 40 | } 41 | 42 | @Override 43 | public void startActivityForResult(Intent intent, int requestCode) { 44 | super.startActivityForResult(intent, requestCode); 45 | if (intent == null) return; 46 | if (intent.getComponent() == null) return; 47 | String className = intent.getComponent().getClassName(); 48 | if (!className.equals(MainActivity.class.getName())) { 49 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); 50 | } 51 | } 52 | 53 | @Override 54 | public void finish() { 55 | super.finish(); 56 | if (!((Object) this).getClass().equals(MainActivity.class)) { 57 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); 58 | } 59 | } 60 | 61 | @Override 62 | protected void onDestroy() { 63 | super.onDestroy(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v4.app.ActivityCompat; 6 | import android.support.v4.app.ActivityOptionsCompat; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | 11 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 12 | import com.sunfusheng.GlideImageView; 13 | import com.sunfusheng.glideimageview.sample.about.AboutActivity; 14 | import com.sunfusheng.glideimageview.sample.image.SingleImageActivity; 15 | import com.sunfusheng.progress.CircleProgressView; 16 | import com.sunfusheng.transformation.BlurTransformation; 17 | 18 | /** 19 | * @author by sunfusheng on 2017/6/3. 20 | */ 21 | public class MainActivity extends BaseActivity { 22 | 23 | GlideImageView image11; 24 | GlideImageView image12; 25 | GlideImageView image13; 26 | GlideImageView image14; 27 | 28 | GlideImageView image21; 29 | GlideImageView image22; 30 | GlideImageView image23; 31 | GlideImageView image24; 32 | 33 | GlideImageView image31; 34 | CircleProgressView progressView1; 35 | GlideImageView image32; 36 | CircleProgressView progressView2; 37 | 38 | GlideImageView image41; 39 | 40 | View draggableView; 41 | 42 | String url1 = 43 | "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1497688355699&di=ea69a930b82ce88561c635089995e124&imgtype=0&src=http%3A%2F%2Fcms-bucket.nosdn.127.net%2Ff84e566bcf654b3698363409fbd676ef20161119091503.jpg"; 44 | String url2 = "http://img1.imgtn.bdimg.com/it/u=4027212837,1228313366&fm=23&gp=0.jpg"; 45 | String url3 = 46 | "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1529402445474&di=b5da3b2f6a466e618e1e32d4dd2bda4d&imgtype=0&src=http%3A%2F%2F2b.zol-img.com.cn%2Fproduct%2F133_500x2000%2F801%2Fce21ke76FRh4A.jpg"; 47 | 48 | String gif1 = "http://img.zcool.cn/community/01e97857c929630000012e7e3c2acf.gif"; 49 | String gif2 = 50 | "http://5b0988e595225.cdn.sohucs.com/images/20171202/a1cc52d5522f48a8a2d6e7426b13f82b.gif"; 51 | String gif3 = "http://img.zcool.cn/community/01d6dd554b93f0000001bf72b4f6ec.jpg"; 52 | 53 | public static final String cat = 54 | "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/resources/cat.jpg"; 55 | public static final String cat_thumbnail = 56 | "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/resources/cat_thumbnail.jpg"; 57 | 58 | public static final String girl = 59 | "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/resources/girl.jpg"; 60 | public static final String girl_thumbnail = 61 | "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/resources/girl_thumbnail.jpg"; 62 | 63 | @Override 64 | protected void onCreate(Bundle savedInstanceState) { 65 | super.onCreate(savedInstanceState); 66 | setContentView(R.layout.activity_main); 67 | 68 | //new FirUpdater(this, "3c57fb226edf7facf821501e4eba08d2", "59461f4c548b7a45cb000050").checkVersion(); 69 | 70 | image11 = findViewById(R.id.image11); 71 | image12 = findViewById(R.id.image12); 72 | image13 = findViewById(R.id.image13); 73 | image14 = findViewById(R.id.image14); 74 | 75 | image21 = findViewById(R.id.image21); 76 | image22 = findViewById(R.id.image22); 77 | image23 = findViewById(R.id.image23); 78 | image24 = findViewById(R.id.image24); 79 | 80 | image31 = findViewById(R.id.image31); 81 | progressView1 = findViewById(R.id.progressView1); 82 | image32 = findViewById(R.id.image32); 83 | progressView2 = findViewById(R.id.progressView2); 84 | 85 | image41 = findViewById(R.id.image41); 86 | 87 | draggableView = findViewById(R.id.draggableView); 88 | image11.setOnClickListener( 89 | v -> startActivity(new Intent(mContext, RecyclerViewActivity.class))); 90 | draggableView.setOnClickListener( 91 | v -> startActivity(new Intent(mContext, NineImageViewActivity.class))); 92 | 93 | image31.setOnClickListener(v -> { 94 | Intent intent = new Intent(MainActivity.this, SingleImageActivity.class); 95 | intent.putExtra(SingleImageActivity.KEY_IMAGE_URL, girl); 96 | intent.putExtra(SingleImageActivity.KEY_IMAGE_URL_THUMBNAIL, girl_thumbnail); 97 | ActivityOptionsCompat compat = 98 | ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, image31, 99 | getString(R.string.transitional_image)); 100 | ActivityCompat.startActivity(MainActivity.this, intent, compat.toBundle()); 101 | }); 102 | 103 | image32.setOnClickListener(v -> { 104 | Intent intent = new Intent(MainActivity.this, SingleImageActivity.class); 105 | intent.putExtra(SingleImageActivity.KEY_IMAGE_URL, cat); 106 | intent.putExtra(SingleImageActivity.KEY_IMAGE_URL_THUMBNAIL, cat_thumbnail); 107 | ActivityOptionsCompat compat = 108 | ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, image32, 109 | getString(R.string.transitional_image)); 110 | ActivityCompat.startActivity(MainActivity.this, intent, compat.toBundle()); 111 | }); 112 | 113 | line1(); 114 | line2(); 115 | line3(); 116 | line4(); 117 | } 118 | 119 | private void line1() { 120 | image11.enableState(true).load(url1); 121 | image12.loadCircle(url1); 122 | image13.load(url2, R.mipmap.image_loading); 123 | image14.load(url2, R.mipmap.image_loading, 10); 124 | } 125 | 126 | private void line2() { 127 | image21.fitCenter().load(gif2, R.mipmap.image_loading, 10); 128 | image22.fitCenter().load(gif1); 129 | image23.fitCenter().loadCircle(gif3); 130 | image24.fitCenter().loadDrawable(R.drawable.gif_robot_walk); 131 | } 132 | 133 | private void line3() { 134 | image31.centerCrop() 135 | .error(R.mipmap.image_load_err) 136 | .diskCacheStrategy(DiskCacheStrategy.NONE) 137 | .load(girl, R.color.placeholder, (isComplete, percentage, bytesRead, totalBytes) -> { 138 | // Log.d("--->", "load percentage: " + percentage + " totalBytes: " + totalBytes + " bytesRead: " + bytesRead); 139 | if (isComplete) { 140 | progressView1.setVisibility(View.GONE); 141 | } else { 142 | progressView1.setVisibility(View.VISIBLE); 143 | progressView1.setProgress(percentage); 144 | } 145 | }); 146 | 147 | image32.centerCrop() 148 | .error(R.mipmap.image_load_err) 149 | .load(cat, R.color.placeholder, (isComplete, percentage, bytesRead, totalBytes) -> { 150 | if (isComplete) { 151 | progressView2.setVisibility(View.GONE); 152 | } else { 153 | progressView2.setVisibility(View.VISIBLE); 154 | progressView2.setProgress(percentage); 155 | } 156 | }); 157 | } 158 | 159 | private void line4() { 160 | image41.fitCenter().load(url3, R.mipmap.image_loading, new BlurTransformation(this, 25, 1)); 161 | 162 | image41.setOnClickListener(v -> { 163 | Intent intent = new Intent(MainActivity.this, SingleImageActivity.class); 164 | intent.putExtra(SingleImageActivity.KEY_IMAGE_URL, url3); 165 | ActivityOptionsCompat compat = 166 | ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, image41, 167 | getString(R.string.transitional_image)); 168 | ActivityCompat.startActivity(MainActivity.this, intent, compat.toBundle()); 169 | }); 170 | } 171 | 172 | @Override 173 | public boolean onCreateOptionsMenu(Menu menu) { 174 | getMenuInflater().inflate(R.menu.menu_main, menu); 175 | return true; 176 | } 177 | 178 | @Override 179 | public boolean onOptionsItemSelected(MenuItem item) { 180 | switch (item.getItemId()) { 181 | case R.id.item_menu_app: 182 | startActivity(new Intent(this, AboutActivity.class)); 183 | return true; 184 | default: 185 | return super.onOptionsItemSelected(item); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/NineImageViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | import android.widget.Toast; 13 | 14 | import com.sunfusheng.glideimageview.sample.model.ImageModel; 15 | import com.sunfusheng.glideimageview.sample.model.ModelUtil; 16 | import com.sunfusheng.widget.GridLayoutHelper; 17 | import com.sunfusheng.widget.ImageData; 18 | import com.sunfusheng.widget.NineImageView; 19 | import com.sunfusheng.util.Utils; 20 | 21 | import java.util.List; 22 | 23 | public class NineImageViewActivity extends BaseActivity { 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.layout_recyclerview); 29 | 30 | setTitle("NineImageView"); 31 | 32 | RecyclerView recyclerView = findViewById(R.id.recycleView); 33 | LinearLayoutManager layoutManager = new LinearLayoutManager(this); 34 | recyclerView.setLayoutManager(layoutManager); 35 | RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, ModelUtil.getImages()); 36 | recyclerView.setAdapter(adapter); 37 | } 38 | 39 | private class RecyclerViewAdapter extends RecyclerView.Adapter { 40 | private List list; 41 | private int margin; 42 | private int maxImgWidth; 43 | private int maxImgHeight; 44 | private int cellWidth; 45 | private int cellHeight; 46 | private int minImgWidth; 47 | private int minImgHeight; 48 | 49 | RecyclerViewAdapter(Context context, List list) { 50 | this.list = list; 51 | margin = Utils.dp2px(context, 3); 52 | maxImgHeight = maxImgWidth = (Utils.getWindowWidth(context) - Utils.dp2px(context, 16) * 2) * 3 / 4; 53 | cellHeight = cellWidth = (maxImgWidth - margin * 3) / 3; 54 | minImgHeight = minImgWidth = cellWidth; 55 | } 56 | 57 | @NonNull 58 | @Override 59 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { 60 | View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_nine_images, viewGroup, false); 61 | return new ViewHolder(view); 62 | } 63 | 64 | @Override 65 | public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { 66 | ImageModel model = list.get(position); 67 | 68 | viewHolder.vDesc.setText(model.desc); 69 | viewHolder.multiImageView.loadGif(false) 70 | .enableRoundCorner(true) 71 | .setRoundCornerRadius(5) 72 | .setData(model.images, getLayoutHelper(model.images)); 73 | 74 | viewHolder.multiImageView.setOnLongClickListener(v -> { 75 | Toast.makeText(getApplicationContext(), "长按:" + model.desc, Toast.LENGTH_SHORT).show(); 76 | return false; 77 | }); 78 | 79 | viewHolder.multiImageView.setOnItemClickListener(index -> { 80 | Toast.makeText(getApplicationContext(), "点击:position = " + index, Toast.LENGTH_SHORT).show(); 81 | }); 82 | } 83 | 84 | private GridLayoutHelper getLayoutHelper(List list) { 85 | int spanCount = Utils.getSize(list); 86 | if (spanCount == 1) { 87 | int width = list.get(0).realWidth; 88 | int height = list.get(0).realHeight; 89 | if (width > 0 && height > 0) { 90 | float whRatio = width * 1f / height; 91 | if (width > height) { 92 | width = Math.max(minImgWidth, Math.min(width, maxImgWidth)); 93 | height = Math.max(minImgHeight, (int) (width / whRatio)); 94 | } else { 95 | height = Math.max(minImgHeight, Math.min(height, maxImgHeight)); 96 | width = Math.max(minImgWidth, (int) (height * whRatio)); 97 | } 98 | } else { 99 | width = cellWidth; 100 | height = cellHeight; 101 | } 102 | return new GridLayoutHelper(spanCount, width, height, margin); 103 | } 104 | 105 | if (spanCount > 3) { 106 | spanCount = (int) Math.ceil(Math.sqrt(spanCount)); 107 | } 108 | 109 | if (spanCount > 3) { 110 | spanCount = 3; 111 | } 112 | return new GridLayoutHelper(spanCount, cellWidth, cellHeight, margin); 113 | } 114 | 115 | @Override 116 | public int getItemCount() { 117 | return list.size(); 118 | } 119 | 120 | class ViewHolder extends RecyclerView.ViewHolder { 121 | TextView vDesc; 122 | NineImageView multiImageView; 123 | 124 | ViewHolder(View view) { 125 | super(view); 126 | vDesc = view.findViewById(R.id.desc); 127 | multiImageView = view.findViewById(R.id.multiImageView); 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/RecyclerViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.LinearLayout; 11 | import android.widget.TextView; 12 | import android.widget.Toast; 13 | 14 | import com.sunfusheng.GlideImageView; 15 | import com.sunfusheng.glideimageview.sample.model.ModelUtil; 16 | import com.sunfusheng.glideimageview.sample.model.NewsModel; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * @author sunfusheng on 2017/11/10. 22 | */ 23 | public class RecyclerViewActivity extends BaseActivity { 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.layout_recyclerview); 29 | 30 | RecyclerView recyclerView = findViewById(R.id.recycleView); 31 | LinearLayoutManager layoutManager = new LinearLayoutManager(this); 32 | recyclerView.setLayoutManager(layoutManager); 33 | RecyclerViewAdapter adapter = new RecyclerViewAdapter(ModelUtil.getNewsList()); 34 | recyclerView.setAdapter(adapter); 35 | } 36 | 37 | class RecyclerViewAdapter extends RecyclerView.Adapter { 38 | private List list; 39 | 40 | RecyclerViewAdapter(List list) { 41 | this.list = list; 42 | } 43 | 44 | @NonNull 45 | @Override 46 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { 47 | View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_right_image, viewGroup, false); 48 | return new ViewHolder(view); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { 53 | NewsModel entity = list.get(position); 54 | viewHolder.tvTitle.setText(entity.getTitle()); 55 | viewHolder.imageView.centerCrop().load(entity.getImage_url(), R.color.placeholder); 56 | viewHolder.llRootView.setOnClickListener(v -> Toast.makeText(mContext, entity.getTitle(), Toast.LENGTH_SHORT).show()); 57 | } 58 | 59 | @Override 60 | public int getItemCount() { 61 | return list.size(); 62 | } 63 | 64 | class ViewHolder extends RecyclerView.ViewHolder { 65 | LinearLayout llRootView; 66 | TextView tvTitle; 67 | GlideImageView imageView; 68 | 69 | ViewHolder(View view) { 70 | super(view); 71 | llRootView = view.findViewById(R.id.ll_root_view); 72 | tvTitle = view.findViewById(R.id.tv_title); 73 | imageView = view.findViewById(R.id.giv); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/about/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.about; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.design.widget.AppBarLayout; 7 | import android.support.design.widget.CollapsingToolbarLayout; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.KeyEvent; 10 | import android.view.View; 11 | import android.widget.TextView; 12 | 13 | import com.sunfusheng.GlideImageView; 14 | import com.sunfusheng.glideimageview.sample.BaseActivity; 15 | import com.sunfusheng.glideimageview.sample.R; 16 | import com.sunfusheng.glideimageview.sample.util.AppUtil; 17 | 18 | /** 19 | * Created by sunfusheng on 2017/6/18. 20 | */ 21 | public class AboutActivity extends BaseActivity { 22 | 23 | WebViewWrapper webViewWrapper; 24 | Toolbar toolbar; 25 | CollapsingToolbarLayout collapsingToolbarLayout; 26 | GlideImageView ivGirl; 27 | TextView tvTitle; 28 | AppBarLayout appBarLayout; 29 | 30 | private String url = "file:///android_asset/about.html"; 31 | 32 | public static void startActivity(Context context) { 33 | Intent intent = new Intent(context, AboutActivity.class); 34 | context.startActivity(intent); 35 | } 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setStatusBarTranslucent(false); 41 | setContentView(R.layout.activity_about); 42 | 43 | initView(); 44 | initToolBar(); 45 | webViewWrapper.loadUrl(url); 46 | } 47 | 48 | private void initView() { 49 | webViewWrapper = (WebViewWrapper) findViewById(R.id.webViewWrapper); 50 | toolbar = (Toolbar) findViewById(R.id.toolbar); 51 | collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout); 52 | ivGirl = (GlideImageView) findViewById(R.id.iv_girl); 53 | tvTitle = (TextView) findViewById(R.id.tv_title); 54 | appBarLayout = (AppBarLayout) findViewById(R.id.appBarLayout); 55 | } 56 | 57 | private void initToolBar() { 58 | setSupportActionBar(toolbar); 59 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 60 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | onBackPressed(); 64 | } 65 | }); 66 | collapsingToolbarLayout.setTitle(""); 67 | toolbar.setTitle(""); 68 | collapsingToolbarLayout.setExpandedTitleColor(getResources().getColor(R.color.transparent));//设置还没收缩时状态下字体颜色 69 | collapsingToolbarLayout.setCollapsedTitleTextColor(getResources().getColor(R.color.transparent));//设置收缩后Toolbar上字体的颜色 70 | tvTitle.setText(getString(R.string.app_name) + " (" + AppUtil.getVersionName(this) + ")"); 71 | appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { 72 | @Override 73 | public void onOffsetChanged(AppBarLayout appBar, int offset) { 74 | tvTitle.setAlpha(Math.abs(offset * 1f / appBar.getTotalScrollRange())); 75 | } 76 | }); 77 | } 78 | 79 | @Override 80 | protected void onResume() { 81 | super.onResume(); 82 | webViewWrapper.onResume(); 83 | } 84 | 85 | @Override 86 | protected void onPause() { 87 | super.onPause(); 88 | webViewWrapper.onPause(); 89 | } 90 | 91 | @Override 92 | protected void onDestroy() { 93 | webViewWrapper.onDestroy(); 94 | super.onDestroy(); 95 | } 96 | 97 | @Override 98 | public boolean onKeyDown(int keyCode, KeyEvent event) { 99 | if (keyCode == KeyEvent.KEYCODE_BACK && webViewWrapper.goBack()) { 100 | return true; 101 | } 102 | return super.onKeyDown(keyCode, event); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/about/WebViewWrapper.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.about; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.support.annotation.DrawableRes; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.webkit.WebChromeClient; 11 | import android.webkit.WebResourceError; 12 | import android.webkit.WebResourceRequest; 13 | import android.webkit.WebSettings; 14 | import android.webkit.WebView; 15 | import android.webkit.WebViewClient; 16 | import android.widget.ProgressBar; 17 | import android.widget.RelativeLayout; 18 | 19 | import com.sunfusheng.glideimageview.sample.R; 20 | 21 | /** 22 | * Created by sunfusheng on 2017/2/15. 23 | */ 24 | @SuppressLint("SetJavaScriptEnabled") 25 | public class WebViewWrapper extends RelativeLayout { 26 | 27 | private WebView webView; 28 | private ProgressBar progressBar; 29 | 30 | private String mUrl; 31 | 32 | public WebViewWrapper(Context context) { 33 | this(context, null); 34 | } 35 | 36 | public WebViewWrapper(Context context, AttributeSet attrs) { 37 | this(context, attrs, 0); 38 | } 39 | 40 | public WebViewWrapper(Context context, AttributeSet attrs, int defStyleAttr) { 41 | super(context, attrs, defStyleAttr); 42 | initView(context); 43 | initWebViewSettings(); 44 | initListener(); 45 | } 46 | 47 | private void initView(Context context) { 48 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 49 | View view = inflater.inflate(R.layout.layout_webview, this); 50 | webView = (WebView) view.findViewById(R.id.webView); 51 | progressBar = (ProgressBar) view.findViewById(R.id.progressBar); 52 | } 53 | 54 | private void initWebViewSettings() { 55 | WebSettings settings = webView.getSettings(); 56 | settings.setJavaScriptEnabled(true); // 默认false,设置true后我们才能在WebView里与我们的JS代码进行交互 57 | settings.setJavaScriptCanOpenWindowsAutomatically(true); // 设置JS是否可以打开WebView新窗口 58 | 59 | settings.setSupportZoom(true); // 支持缩放 60 | settings.setBuiltInZoomControls(true); // 支持手势缩放 61 | settings.setDisplayZoomControls(false); // 不显示缩放按钮 62 | 63 | settings.setDatabaseEnabled(true); 64 | settings.setSaveFormData(true); 65 | settings.setDomStorageEnabled(true); 66 | settings.setGeolocationEnabled(true); 67 | settings.setAppCacheEnabled(true); 68 | 69 | settings.setUseWideViewPort(true); // 将图片调整到适合WebView的大小 70 | settings.setLoadWithOverviewMode(true); // 自适应屏幕 71 | 72 | webView.setHorizontalScrollBarEnabled(false); 73 | webView.setScrollbarFadingEnabled(true); 74 | webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); 75 | webView.setOverScrollMode(View.OVER_SCROLL_NEVER); // 取消WebView中滚动或拖动到顶部、底部时的阴影 76 | } 77 | 78 | private void initListener() { 79 | webView.setWebViewClient(new WebViewClient() { 80 | @Override 81 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { 82 | return super.shouldOverrideUrlLoading(view, request); 83 | } 84 | 85 | @Override 86 | public void onPageStarted(WebView view, String url, Bitmap favicon) { 87 | super.onPageStarted(view, url, favicon); 88 | progressBar.setVisibility(View.VISIBLE); 89 | } 90 | 91 | @Override 92 | public void onPageFinished(WebView view, String url) { 93 | super.onPageFinished(view, url); 94 | progressBar.setVisibility(View.GONE); 95 | } 96 | 97 | @Override 98 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 99 | super.onReceivedError(view, request, error); 100 | progressBar.setVisibility(View.GONE); 101 | } 102 | }); 103 | 104 | webView.setWebChromeClient(new WebChromeClient() { 105 | @Override 106 | public void onProgressChanged(WebView view, int newProgress) { 107 | if (newProgress >= 100) { 108 | progressBar.setVisibility(View.GONE); 109 | } else { 110 | if (progressBar.getVisibility() == View.GONE) { 111 | progressBar.setVisibility(View.VISIBLE); 112 | } 113 | progressBar.setProgress(newProgress); 114 | } 115 | super.onProgressChanged(view, newProgress); 116 | 117 | } 118 | }); 119 | 120 | 121 | } 122 | 123 | public void loadUrl(String url) { 124 | mUrl = url; 125 | webView.loadUrl(url); 126 | } 127 | 128 | public void setProgressDrawable(@DrawableRes int id) { 129 | progressBar.setProgressDrawable(progressBar.getContext().getResources().getDrawable(id)); 130 | } 131 | 132 | public WebView getWebView() { 133 | return webView; 134 | } 135 | 136 | public String getUrl() { 137 | return mUrl; 138 | } 139 | 140 | public boolean goBack() { 141 | if (webView.canGoBack()) { 142 | webView.goBack(); 143 | return true; 144 | } 145 | return false; 146 | } 147 | 148 | public void onResume() { 149 | webView.getSettings().setJavaScriptEnabled(true); 150 | webView.onResume(); 151 | } 152 | 153 | public void onPause() { 154 | webView.getSettings().setJavaScriptEnabled(false); 155 | webView.onPause(); 156 | } 157 | 158 | public void onDestroy() { 159 | webView.setVisibility(GONE); 160 | webView.destroy(); 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/image/FixedViewPager.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.image; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | 8 | /** 修复图片在ViewPager控件中缩放报错的BUG */ 9 | public class FixedViewPager extends ViewPager { 10 | 11 | public FixedViewPager(Context context) { 12 | super(context); 13 | } 14 | 15 | public FixedViewPager(Context context, AttributeSet attrs) { 16 | super(context, attrs); 17 | } 18 | 19 | @Override 20 | public boolean onTouchEvent(MotionEvent ev) { 21 | try { 22 | return super.onTouchEvent(ev); 23 | } catch (IllegalArgumentException ex) { 24 | ex.printStackTrace(); 25 | } 26 | return false; 27 | } 28 | 29 | @Override 30 | public boolean onInterceptTouchEvent(MotionEvent ev) { 31 | try { 32 | return super.onInterceptTouchEvent(ev); 33 | } catch (IllegalArgumentException ex) { 34 | ex.printStackTrace(); 35 | } 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/image/ImagesActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.image; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | import android.app.Activity; 6 | import android.content.Intent; 7 | import android.graphics.Color; 8 | import android.os.Bundle; 9 | import android.support.v4.view.ViewPager; 10 | import android.view.ViewTreeObserver; 11 | import android.widget.RelativeLayout; 12 | import android.widget.TextView; 13 | 14 | import com.github.chrisbanes.photoview.PhotoView; 15 | import com.sunfusheng.glideimageview.sample.R; 16 | import com.sunfusheng.glideimageview.sample.util.ColorUtil; 17 | import com.sunfusheng.glideimageview.sample.util.StatusBarUtil; 18 | import com.sunfusheng.widget.ImageData; 19 | import com.sunfusheng.util.Utils; 20 | 21 | import java.util.List; 22 | 23 | public class ImagesActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { 24 | 25 | public static final String IMAGE_ATTR = "image_attr"; 26 | public static final String CUR_POSITION = "cur_position"; 27 | public static final int ANIM_DURATION = 300; // ms 28 | 29 | private RelativeLayout rootView; 30 | private ViewPager viewPager; 31 | private TextView tvTip; 32 | private ImagesAdapter mAdapter; 33 | private List imageAttrs; 34 | private boolean isAnimating; 35 | 36 | private int curPosition; 37 | private int screenWidth; 38 | private int screenHeight; 39 | private float scaleX; 40 | private float scaleY; 41 | private float translationX; 42 | private float translationY; 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_preview); 48 | StatusBarUtil.setStatusBarTranslucent(this, false); 49 | 50 | viewPager = (ViewPager) findViewById(R.id.viewPager); 51 | tvTip = (TextView) findViewById(R.id.tv_tip); 52 | rootView = (RelativeLayout) findViewById(R.id.rootView); 53 | screenWidth = Utils.getWindowWidth(this); 54 | screenHeight = Utils.getWindowHeight(this); 55 | 56 | Intent intent = getIntent(); 57 | imageAttrs = (List) intent.getSerializableExtra(IMAGE_ATTR); 58 | curPosition = intent.getIntExtra(CUR_POSITION, 0); 59 | tvTip.setText(String.format(getString(R.string.image_index), (curPosition + 1), imageAttrs.size())); 60 | 61 | mAdapter = new ImagesAdapter(this, imageAttrs); 62 | viewPager.setAdapter(mAdapter); 63 | viewPager.setCurrentItem(curPosition); 64 | viewPager.getViewTreeObserver().addOnPreDrawListener(this); 65 | viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { 66 | @Override 67 | public void onPageSelected(int position) { 68 | curPosition = position; 69 | tvTip.setText(String.format(getString(R.string.image_index), (curPosition + 1), imageAttrs.size())); 70 | } 71 | }); 72 | } 73 | 74 | @Override 75 | public void onBackPressed() { 76 | finishWithAnim(); 77 | } 78 | 79 | private void initImageAttr(PhotoView photoView, ImageData attr, boolean isFinish) { 80 | // int originalWidth = attr.width; 81 | // int originalHeight = attr.height; 82 | // int originalCenterX = attr.left + originalWidth / 2; 83 | // int originalCenterY = attr.top + originalHeight / 2; 84 | // 85 | // float widthRatio = screenWidth * 1.0f / attr.realWidth; 86 | // float heightRatio = screenHeight * 1.0f / attr.realHeight; 87 | // int finalHeight = (int) (attr.realHeight * widthRatio); 88 | // int finalWidth = screenWidth; //imageAttrs.size() == 1 ? screenWidth : finalHeight; 89 | // 90 | // scaleX = originalWidth * 1.0f / finalWidth; 91 | // scaleY = originalHeight * 1.0f / finalHeight; 92 | // translationX = originalCenterX - screenWidth / 2; 93 | // translationY = originalCenterY - screenHeight / 2; 94 | // 95 | // Log.d("--->", "(left, top): (" + attr.left + ", " + attr.top + ")"); 96 | // Log.d("--->", "originalWidth: " + originalWidth + " originalHeight: " + originalHeight); 97 | // Log.d("--->", "finalWidth: " + finalWidth + " finalHeight: " + finalHeight); 98 | // Log.d("--->", "scaleX: " + scaleX + " scaleY: " + scaleY); 99 | // Log.d("--->", "translationX: " + translationX + " translationY: " + translationY); 100 | // Log.d("--->", "" + attr.toString()); 101 | // Log.d("--->", "----------------------------------------------------------------"); 102 | } 103 | 104 | @Override 105 | public boolean onPreDraw() { 106 | // if (isAnimating) return true; 107 | // rootView.getViewTreeObserver().removeOnPreDrawListener(this); 108 | // PhotoView photoView = mAdapter.getPhotoView(curPosition); 109 | // ImageAttr attr = imageAttrs.get(curPosition); 110 | // initImageAttr(photoView, attr, false); 111 | // 112 | // translateXAnim(photoView, translationX, 0); 113 | // translateYAnim(photoView, translationY, 0); 114 | // scaleXAnim(photoView, scaleX, 1); 115 | // scaleYAnim(photoView, scaleY, 1); 116 | // setBackgroundColor(0f, 1f, new Animator.AnimatorListener() { 117 | // @Override 118 | // public void onAnimationStart(Animator animation) { 119 | // isAnimating = true; 120 | // } 121 | // 122 | // @Override 123 | // public void onAnimationEnd(Animator animation) { 124 | // isAnimating = false; 125 | // } 126 | // 127 | // @Override 128 | // public void onAnimationCancel(Animator animation) { 129 | // } 130 | // 131 | // @Override 132 | // public void onAnimationRepeat(Animator animation) { 133 | // } 134 | // }); 135 | return true; 136 | } 137 | 138 | public void finishWithAnim() { 139 | if (isAnimating) return; 140 | PhotoView photoView = mAdapter.getPhotoView(curPosition); 141 | photoView.setScale(1f); 142 | ImageData attr = imageAttrs.get(curPosition); 143 | initImageAttr(photoView, attr, true); 144 | 145 | translateXAnim(photoView, 0, translationX); 146 | translateYAnim(photoView, 0, translationY); 147 | scaleXAnim(photoView, 1, scaleX); 148 | scaleYAnim(photoView, 1, scaleY); 149 | setBackgroundColor(1f, 0f, new Animator.AnimatorListener() { 150 | @Override 151 | public void onAnimationStart(Animator animation) { 152 | isAnimating = true; 153 | } 154 | 155 | @Override 156 | public void onAnimationEnd(Animator animation) { 157 | isAnimating = false; 158 | finish(); 159 | overridePendingTransition(0, 0); 160 | } 161 | 162 | @Override 163 | public void onAnimationCancel(Animator animation) { 164 | } 165 | 166 | @Override 167 | public void onAnimationRepeat(Animator animation) { 168 | } 169 | }); 170 | } 171 | 172 | private void translateXAnim(PhotoView photoView, float from, float to) { 173 | ValueAnimator anim = ValueAnimator.ofFloat(from, to); 174 | anim.addUpdateListener(it -> photoView.setX((Float) it.getAnimatedValue())); 175 | anim.setDuration(ANIM_DURATION); 176 | anim.start(); 177 | } 178 | 179 | private void translateYAnim(PhotoView photoView, float from, float to) { 180 | ValueAnimator anim = ValueAnimator.ofFloat(from, to); 181 | anim.addUpdateListener(it -> photoView.setY((Float) it.getAnimatedValue())); 182 | anim.setDuration(ANIM_DURATION); 183 | anim.start(); 184 | } 185 | 186 | private void scaleXAnim(PhotoView photoView, float from, float to) { 187 | ValueAnimator anim = ValueAnimator.ofFloat(from, to); 188 | anim.addUpdateListener(it -> photoView.setScaleX((Float) it.getAnimatedValue())); 189 | anim.setDuration(ANIM_DURATION); 190 | anim.start(); 191 | } 192 | 193 | private void scaleYAnim(PhotoView photoView, float from, float to) { 194 | ValueAnimator anim = ValueAnimator.ofFloat(from, to); 195 | anim.addUpdateListener(it -> photoView.setScaleY((Float) it.getAnimatedValue())); 196 | anim.setDuration(ANIM_DURATION); 197 | anim.start(); 198 | } 199 | 200 | private void setBackgroundColor(float from, float to, Animator.AnimatorListener listener) { 201 | ValueAnimator anim = ValueAnimator.ofFloat(from, to); 202 | anim.addUpdateListener(it -> rootView.setBackgroundColor(ColorUtil.evaluate((Float) it.getAnimatedValue(), Color.TRANSPARENT, Color.BLACK))); 203 | anim.setDuration(ANIM_DURATION); 204 | if (listener != null) { 205 | anim.addListener(listener); 206 | } 207 | anim.start(); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/image/ImagesAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.image; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.v4.view.PagerAdapter; 6 | import android.util.SparseArray; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | 12 | import com.github.chrisbanes.photoview.OnOutsidePhotoTapListener; 13 | import com.github.chrisbanes.photoview.OnPhotoTapListener; 14 | import com.github.chrisbanes.photoview.PhotoView; 15 | import com.sunfusheng.glideimageview.sample.R; 16 | import com.sunfusheng.widget.ImageData; 17 | import com.sunfusheng.progress.CircleProgressView; 18 | 19 | import java.util.List; 20 | 21 | public class ImagesAdapter extends PagerAdapter implements OnPhotoTapListener, OnOutsidePhotoTapListener { 22 | 23 | private Context mContext; 24 | private LayoutInflater mInflater; 25 | private List images; 26 | private SparseArray photoViews = new SparseArray<>(); 27 | 28 | public ImagesAdapter(Context context, @NonNull List images) { 29 | super(); 30 | this.mContext = context; 31 | this.mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 32 | this.images = images; 33 | } 34 | 35 | @Override 36 | public int getCount() { 37 | return images.size(); 38 | } 39 | 40 | @Override 41 | public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { 42 | return view == object; 43 | } 44 | 45 | @Override 46 | public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 47 | super.setPrimaryItem(container, position, object); 48 | } 49 | 50 | public PhotoView getPhotoView(int index) { 51 | return photoViews.get(index); 52 | } 53 | 54 | @Override 55 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 56 | View view = mInflater.inflate(R.layout.item_photoview, container, false); 57 | CircleProgressView progressView = (CircleProgressView) view.findViewById(R.id.progressView); 58 | PhotoView photoView = (PhotoView) view.findViewById(R.id.photoView); 59 | photoView.setScaleType(ImageView.ScaleType.FIT_CENTER); 60 | photoView.setOnPhotoTapListener(this); 61 | photoView.setOnOutsidePhotoTapListener(this); 62 | photoViews.put(position, photoView); 63 | 64 | // GlideImageLoader imageLoader = GlideImageLoader.create(photoView); 65 | // imageLoader.setOnGlideImageViewListener(url, (percent, isDone, exception) -> { 66 | // progressView.setProgress(percent); 67 | // progressView.setVisibility(isDone ? View.GONE : View.VISIBLE); 68 | // }); 69 | // RequestOptions requestOptions = imageLoader.requestOptions(R.color.placeholder) 70 | // .centerCrop() 71 | // .skipMemoryCache(false) 72 | // .diskCacheStrategy(DiskCacheStrategy.RESOURCE) 73 | // .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); 74 | // RequestBuilder requestBuilder = imageLoader.requestBuilder(url, requestOptions) 75 | // .transition(DrawableTransitionOptions.withCrossFade()); 76 | // requestBuilder.into(new SimpleTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) { 77 | // @Override 78 | // public void onResourceReady(Drawable resource, Transition transition) { 79 | // if (resource.getIntrinsicHeight() > DisplayUtil.getScreenHeight(mContext)) { 80 | // photoView.setScaleType(ImageView.ScaleType.CENTER_CROP); 81 | // } 82 | // requestBuilder.into(photoView); 83 | // } 84 | // }); 85 | 86 | // container.addView(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 87 | return view; 88 | } 89 | 90 | @Override 91 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 92 | container.removeView((View) object); 93 | } 94 | 95 | @Override 96 | public void onPhotoTap(ImageView view, float x, float y) { 97 | ((ImagesActivity) mContext).finishWithAnim(); 98 | } 99 | 100 | @Override 101 | public void onOutsidePhotoTap(ImageView imageView) { 102 | ((ImagesActivity) mContext).finishWithAnim(); 103 | } 104 | } -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/image/NineImageViewEventAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.image; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | 8 | import com.sunfusheng.widget.ImageData; 9 | import com.sunfusheng.widget.NineImageView; 10 | 11 | import java.io.Serializable; 12 | import java.util.List; 13 | 14 | 15 | public class NineImageViewEventAdapter { 16 | 17 | protected void onImageItemClick(Context context, NineImageView nineImageView, int index, List images) { 18 | // for (int i = 0; i < images.size(); i++) { 19 | // ImageData attr = images.get(i); 20 | // View imageView = nineImageView.getChildAt(i); 21 | // if (i >= nineImageView.getMaxSize()) { 22 | // imageView = nineImageView.getChildAt(nineImageView.getMaxSize() - 1); 23 | // } 24 | // attr.width = imageView.getWidth(); 25 | // attr.height = imageView.getHeight(); 26 | // int[] points = new int[2]; 27 | // imageView.getLocationInWindow(points); 28 | // attr.left = points[0]; 29 | // attr.top = points[1]; 30 | // } 31 | 32 | Intent intent = new Intent(context, ImagesActivity.class); 33 | Bundle bundle = new Bundle(); 34 | bundle.putSerializable(ImagesActivity.IMAGE_ATTR, (Serializable) images); 35 | bundle.putInt(ImagesActivity.CUR_POSITION, index); 36 | intent.putExtras(bundle); 37 | context.startActivity(intent); 38 | ((Activity) context).overridePendingTransition(0, 0); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/image/SingleImageActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.image; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.sunfusheng.GlideImageView; 9 | import com.sunfusheng.glideimageview.sample.R; 10 | import com.sunfusheng.progress.CircleProgressView; 11 | 12 | /** 13 | * @author by sunfusheng on 2017/6/15. 14 | */ 15 | public class SingleImageActivity extends AppCompatActivity { 16 | 17 | public static final String KEY_IMAGE_URL = "image_url"; 18 | public static final String KEY_IMAGE_URL_THUMBNAIL = "image_url_thumbnail"; 19 | 20 | GlideImageView glideImageView; 21 | CircleProgressView progressView; 22 | 23 | String image_url; 24 | String image_url_thumbnail; 25 | 26 | @Override 27 | protected void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_image); 30 | 31 | image_url = getIntent().getStringExtra(KEY_IMAGE_URL); 32 | image_url_thumbnail = getIntent().getStringExtra(KEY_IMAGE_URL_THUMBNAIL); 33 | 34 | glideImageView = findViewById(R.id.glideImageView); 35 | progressView = findViewById(R.id.progressView); 36 | glideImageView.setOnClickListener(v -> onBackPressed()); 37 | 38 | loadImage(); 39 | } 40 | 41 | private void loadImage() { 42 | glideImageView.load(image_url, R.color.transparent, (isComplete, percentage, bytesRead, totalBytes) -> { 43 | if (isComplete) { 44 | progressView.setVisibility(View.GONE); 45 | } else { 46 | progressView.setVisibility(View.VISIBLE); 47 | progressView.setProgress(percentage); 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/model/ImageModel.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.model; 2 | 3 | import com.sunfusheng.widget.ImageData; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * @author by sunfusheng on 2017/6/27. 10 | */ 11 | public class ImageModel implements Serializable { 12 | public String desc; 13 | public List images; 14 | 15 | public ImageModel(String desc, List images) { 16 | this.desc = desc; 17 | this.images = images; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/model/ModelUtil.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.model; 2 | 3 | import com.sunfusheng.widget.ImageData; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author by sunfusheng on 2017/6/27. 10 | */ 11 | public class ModelUtil { 12 | 13 | public static List getImages() { 14 | List list = new ArrayList<>(); 15 | 16 | List images = new ArrayList<>(); 17 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=3040385967,1031044866&fm=21&gp=0.jpg")); 18 | images.add(new ImageData("http://img1.imgtn.bdimg.com/it/u=1832737924,144748431&fm=21&gp=0.jpg")); 19 | images.add(new ImageData("http://img.zcool.cn/community/01d6dd554b93f0000001bf72b4f6ec.jpg")); 20 | list.add(new ImageModel("2张图片和1张GIF动态图", images)); 21 | 22 | images = new ArrayList<>(); 23 | images.add(new ImageData("http://5b0988e595225.cdn.sohucs.com/images/20171202/a1cc52d5522f48a8a2d6e7426b13f82b.gif")); 24 | list.add(new ImageModel("1张GIF动态图", images)); 25 | 26 | images = new ArrayList<>(); 27 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg")); 28 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg")); 29 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=1424970962,1243597989&fm=21&gp=0.jpg")); 30 | list.add(new ImageModel("3张图片", images)); 31 | 32 | images = new ArrayList<>(); 33 | ImageData imageData = new ImageData("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1529402445474&di=b5da3b2f6a466e618e1e32d4dd2bda4d&imgtype=0&src=http%3A%2F%2F2b.zol-img.com.cn%2Fproduct%2F133_500x2000%2F801%2Fce21ke76FRh4A.jpg"); 34 | imageData.realWidth = 500; 35 | imageData.realHeight = 281; 36 | images.add(imageData); 37 | list.add(new ImageModel("一个小猫咪", images)); 38 | 39 | images = new ArrayList<>(); 40 | imageData = new ImageData("http://pic.58pic.com/58pic/13/62/02/07d58PICcxz_1024.jpg"); 41 | imageData.realWidth = 1024; 42 | imageData.realHeight = 529; 43 | images.add(imageData); 44 | list.add(new ImageModel("画卷:天道酬勤", images)); 45 | 46 | images = new ArrayList<>(); 47 | imageData = new ImageData("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1498629002766&di=6fac924b9c9bc0858074a5eb455e4bd8&imgtype=0&src=http%3A%2F%2Fimg1.3lian.com%2F2015%2Fw21%2F8%2Fd%2F85.jpg"); 48 | imageData.realWidth = 450; 49 | imageData.realHeight = 798; 50 | images.add(imageData); 51 | list.add(new ImageModel("又一个小猫咪", images)); 52 | 53 | images = new ArrayList<>(); 54 | images.add(new ImageData("http://img15.3lian.com/2015/h1/308/d/199.jpg")); 55 | images.add(new ImageData("http://pic1.win4000.com/wallpaper/f/566a714a786cc.jpg")); 56 | images.add(new ImageData("http://img15.3lian.com/2015/h1/308/d/204.jpg")); 57 | images.add(new ImageData("http://imglf1.ph.126.net/DIe00tFQ1SZOdKUDG8AO1g==/2068278128970036688.jpg")); 58 | list.add(new ImageModel("世界著名建筑", images)); 59 | 60 | images = new ArrayList<>(); 61 | imageData = new ImageData("http://wx4.sinaimg.cn/mw690/e59bcb0dly1fgqlue0vtvj20c83htx3d.jpg"); 62 | imageData.realWidth = 440; 63 | imageData.realHeight = 4529; 64 | images.add(imageData); 65 | list.add(new ImageModel("开发者头条的截图(440X4529)", images)); 66 | 67 | images = new ArrayList<>(); 68 | images.add(new ImageData("http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg")); 69 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg")); 70 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg")); 71 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=3191365283,111438732&fm=21&gp=0.jpg")); 72 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=482494496,1350922497&fm=206&gp=0.jpg")); 73 | images.add(new ImageData("http://img4.imgtn.bdimg.com/it/u=2440866214,1867472386&fm=21&gp=0.jpg")); 74 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=3040385967,1031044866&fm=21&gp=0.jpg")); 75 | images.add(new ImageData("http://img1.imgtn.bdimg.com/it/u=1832737924,144748431&fm=21&gp=0.jpg")); 76 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg")); 77 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg")); 78 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=1424970962,1243597989&fm=21&gp=0.jpg")); 79 | list.add(new ImageModel("11张图片", images)); 80 | 81 | images = new ArrayList<>(); 82 | images.add(new ImageData("http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg")); 83 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg")); 84 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg")); 85 | list.add(new ImageModel("3张图片", images)); 86 | 87 | images = new ArrayList<>(); 88 | images.add(new ImageData("http://img.zcool.cn/community/01d6dd554b93f0000001bf72b4f6ec.jpg")); 89 | images.add(new ImageData("http://5b0988e595225.cdn.sohucs.com/images/20171202/a1cc52d5522f48a8a2d6e7426b13f82b.gif")); 90 | list.add(new ImageModel("2张GIF动态图", images)); 91 | 92 | images = new ArrayList<>(); 93 | images.add(new ImageData("http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg")); 94 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg")); 95 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg")); 96 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=3191365283,111438732&fm=21&gp=0.jpg")); 97 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=482494496,1350922497&fm=206&gp=0.jpg")); 98 | images.add(new ImageData("http://img4.imgtn.bdimg.com/it/u=2440866214,1867472386&fm=21&gp=0.jpg")); 99 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=3040385967,1031044866&fm=21&gp=0.jpg")); 100 | images.add(new ImageData("http://img1.imgtn.bdimg.com/it/u=1832737924,144748431&fm=21&gp=0.jpg")); 101 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg")); 102 | list.add(new ImageModel("9张图片", images)); 103 | 104 | images = new ArrayList<>(); 105 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg")); 106 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg")); 107 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=3191365283,111438732&fm=21&gp=0.jpg")); 108 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=482494496,1350922497&fm=206&gp=0.jpg")); 109 | images.add(new ImageData("http://img4.imgtn.bdimg.com/it/u=2440866214,1867472386&fm=21&gp=0.jpg")); 110 | list.add(new ImageModel("5张图片", images)); 111 | 112 | images = new ArrayList<>(); 113 | images.add(new ImageData("http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg")); 114 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg")); 115 | images.add(new ImageData("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg")); 116 | images.add(new ImageData("http://img5.imgtn.bdimg.com/it/u=3191365283,111438732&fm=21&gp=0.jpg")); 117 | list.add(new ImageModel("4张图片", images)); 118 | 119 | return list; 120 | } 121 | 122 | public static List getNewsList() { 123 | List list = new ArrayList<>(); 124 | 125 | list.add(new NewsModel("为迎接伊万卡等宾客访问 印度一座城市将驱逐乞丐", 126 | "http://cms-bucket.nosdn.127.net/c80973c27a4541cda761f6a49045854720171110113147.png?imageView&thumbnail=140y88&quality=85")); 127 | 128 | list.add(new NewsModel("英国“脱欧”终于有眉目!政府将敲定具体离开时间", 129 | "http://cms-bucket.nosdn.127.net/f5e164f5805e4a4480b30d34826c70b920171110090734.png?imageView&thumbnail=140y88&quality=85")); 130 | 131 | list.add(new NewsModel("沙特:因无足够证据 先释放部分因涉贪腐被捕人员", 132 | "http://cms-bucket.nosdn.127.net/49d4eb3d6969440590cfb326b513d97b20171109234915.png?imageView&thumbnail=140y88&quality=85")); 133 | 134 | list.add(new NewsModel("关系骤然紧张!伊朗总统喊话沙特 "宿敌"死结何解?", 135 | "http://cms-bucket.nosdn.127.net/629515b9eb9946cfa65d33401bb1016120171109153300.png?imageView&thumbnail=140y88&quality=85")); 136 | 137 | list.add(new NewsModel("为迎接伊万卡等宾客访问 印度一座城市将驱逐乞丐", 138 | "http://cms-bucket.nosdn.127.net/c80973c27a4541cda761f6a49045854720171110113147.png?imageView&thumbnail=140y88&quality=85")); 139 | 140 | list.add(new NewsModel("英国“脱欧”终于有眉目!政府将敲定具体离开时间", 141 | "http://cms-bucket.nosdn.127.net/f5e164f5805e4a4480b30d34826c70b920171110090734.png?imageView&thumbnail=140y88&quality=85")); 142 | 143 | list.add(new NewsModel("沙特:因无足够证据 先释放部分因涉贪腐被捕人员", 144 | "http://cms-bucket.nosdn.127.net/49d4eb3d6969440590cfb326b513d97b20171109234915.png?imageView&thumbnail=140y88&quality=85")); 145 | 146 | list.add(new NewsModel("关系骤然紧张!伊朗总统喊话沙特 "宿敌"死结何解?", 147 | "http://cms-bucket.nosdn.127.net/629515b9eb9946cfa65d33401bb1016120171109153300.png?imageView&thumbnail=140y88&quality=85")); 148 | 149 | list.add(new NewsModel("为迎接伊万卡等宾客访问 印度一座城市将驱逐乞丐", 150 | "http://cms-bucket.nosdn.127.net/c80973c27a4541cda761f6a49045854720171110113147.png?imageView&thumbnail=140y88&quality=85")); 151 | 152 | list.add(new NewsModel("英国“脱欧”终于有眉目!政府将敲定具体离开时间", 153 | "http://cms-bucket.nosdn.127.net/f5e164f5805e4a4480b30d34826c70b920171110090734.png?imageView&thumbnail=140y88&quality=85")); 154 | 155 | list.add(new NewsModel("沙特:因无足够证据 先释放部分因涉贪腐被捕人员", 156 | "http://cms-bucket.nosdn.127.net/49d4eb3d6969440590cfb326b513d97b20171109234915.png?imageView&thumbnail=140y88&quality=85")); 157 | 158 | list.add(new NewsModel("关系骤然紧张!伊朗总统喊话沙特 "宿敌"死结何解?", 159 | "http://cms-bucket.nosdn.127.net/629515b9eb9946cfa65d33401bb1016120171109153300.png?imageView&thumbnail=140y88&quality=85")); 160 | 161 | return list; 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/model/NewsModel.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * @author sunfusheng on 2017/11/10. 8 | */ 9 | public class NewsModel implements Serializable { 10 | 11 | private String title; 12 | private String image_url; 13 | private ArrayList images; 14 | private int type; 15 | 16 | public NewsModel(String title, String image_url) { 17 | this.title = title; 18 | this.image_url = image_url; 19 | } 20 | 21 | public String getTitle() { 22 | return title; 23 | } 24 | 25 | public void setTitle(String title) { 26 | this.title = title; 27 | } 28 | 29 | public String getImage_url() { 30 | return image_url; 31 | } 32 | 33 | public void setImage_url(String image_url) { 34 | this.image_url = image_url; 35 | } 36 | 37 | public ArrayList getImages() { 38 | return images; 39 | } 40 | 41 | public void setImages(ArrayList images) { 42 | this.images = images; 43 | } 44 | 45 | public int getType() { 46 | return type; 47 | } 48 | 49 | public void setType(int type) { 50 | this.type = type; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/util/AppUtil.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.util; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.net.ConnectivityManager; 7 | import android.net.NetworkInfo; 8 | import android.text.TextUtils; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by sunfusheng on 2017/1/17. 14 | */ 15 | public class AppUtil { 16 | 17 | public static boolean notEmpty(List list) { 18 | return !isEmpty(list); 19 | } 20 | 21 | public static boolean isEmpty(List list) { 22 | if (list == null || list.size() == 0) { 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | // 判断网络是否可用 29 | public static boolean isNetworkAvailable(Context context) { 30 | try { 31 | ConnectivityManager connectivity = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); 32 | if (connectivity != null) { 33 | NetworkInfo info = connectivity.getActiveNetworkInfo(); 34 | if (info != null && info.isConnected()) { 35 | if (info.getState() == NetworkInfo.State.CONNECTED) { 36 | return true; 37 | } 38 | } 39 | } 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | return false; 43 | } 44 | return false; 45 | } 46 | 47 | // WiFi是否连接 48 | public static boolean isWiFiAvailable(Context context) { 49 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); 50 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); 51 | if (networkInfo != null && networkInfo.isAvailable() && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | // 获取当前应用的版本号 58 | public static String getVersionName(Context context) { 59 | try { 60 | PackageManager packageManager = context.getApplicationContext().getPackageManager(); 61 | PackageInfo packInfo = packageManager.getPackageInfo(context.getApplicationContext().getPackageName(), 0); 62 | String version = packInfo.versionName; 63 | if (!TextUtils.isEmpty(version)) { 64 | return "V" + version; 65 | } 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | return "V1.0"; 70 | } 71 | 72 | // 获取当前应用的版本号 73 | public static int getVersionCode(Context context) { 74 | try { 75 | PackageManager packageManager = context.getApplicationContext().getPackageManager(); 76 | PackageInfo packInfo = packageManager.getPackageInfo(context.getApplicationContext().getPackageName(), 0); 77 | return packInfo.versionCode; 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | } 81 | return 1; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/util/ColorUtil.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by sunfusheng on 16/4/22. 7 | */ 8 | public class ColorUtil { 9 | 10 | // 合成新的颜色值 11 | public static int getNewColorByStartEndColor(Context context, float fraction, int startValue, int endValue) { 12 | return evaluate(fraction, context.getResources().getColor(startValue), context.getResources().getColor(endValue)); 13 | } 14 | /** 15 | * 合成新的颜色值 16 | * @param fraction 颜色取值的级别 (0.0f ~ 1.0f) 17 | * @param startValue 开始显示的颜色 18 | * @param endValue 结束显示的颜色 19 | * @return 返回生成新的颜色值 20 | */ 21 | public static int evaluate(float fraction, int startValue, int endValue) { 22 | int startA = (startValue >> 24) & 0xff; 23 | int startR = (startValue >> 16) & 0xff; 24 | int startG = (startValue >> 8) & 0xff; 25 | int startB = startValue & 0xff; 26 | 27 | int endA = (endValue >> 24) & 0xff; 28 | int endR = (endValue >> 16) & 0xff; 29 | int endG = (endValue >> 8) & 0xff; 30 | int endB = endValue & 0xff; 31 | 32 | return ((startA + (int) (fraction * (endA - startA))) << 24) | 33 | ((startR + (int) (fraction * (endR - startR))) << 16) | 34 | ((startG + (int) (fraction * (endG - startG))) << 8) | 35 | ((startB + (int) (fraction * (endB - startB)))); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/util/StatusBarUtil.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.util; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.view.View; 7 | import android.view.Window; 8 | import android.view.WindowManager; 9 | 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | 13 | /** 14 | * Created by sunfusheng on 16/11/20. 15 | */ 16 | public class StatusBarUtil { 17 | 18 | // 设置状态栏透明与字体颜色 19 | public static void setStatusBarTranslucent(Activity activity, boolean isLightStatusBar) { 20 | if (activity == null) return; 21 | Window window = activity.getWindow(); 22 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 23 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 24 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 25 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 26 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 27 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 28 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 29 | window.setStatusBarColor(Color.TRANSPARENT); 30 | } 31 | 32 | if (isXiaomi()) { 33 | setXiaomiStatusBar(window, isLightStatusBar); 34 | } else if (isMeizu()) { 35 | setMeizuStatusBar(window, isLightStatusBar); 36 | } 37 | } 38 | 39 | // 是否是小米手机 40 | public static boolean isXiaomi() { 41 | return "Xiaomi".equals(Build.MANUFACTURER); 42 | } 43 | 44 | // 设置小米状态栏 45 | public static void setXiaomiStatusBar(Window window, boolean isLightStatusBar) { 46 | Class clazz = window.getClass(); 47 | try { 48 | Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); 49 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); 50 | int darkModeFlag = field.getInt(layoutParams); 51 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); 52 | extraFlagField.invoke(window, isLightStatusBar ? darkModeFlag : 0, darkModeFlag); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | // 是否是魅族手机 59 | public static boolean isMeizu() { 60 | try { 61 | Method method = Build.class.getMethod("hasSmartBar"); 62 | return method != null; 63 | } catch (NoSuchMethodException e) { 64 | } 65 | return false; 66 | } 67 | 68 | // 设置魅族状态栏 69 | public static void setMeizuStatusBar(Window window, boolean isLightStatusBar) { 70 | WindowManager.LayoutParams params = window.getAttributes(); 71 | try { 72 | Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); 73 | Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags"); 74 | darkFlag.setAccessible(true); 75 | meizuFlags.setAccessible(true); 76 | int bit = darkFlag.getInt(null); 77 | int value = meizuFlags.getInt(params); 78 | if (isLightStatusBar) { 79 | value |= bit; 80 | } else { 81 | value &= ~bit; 82 | } 83 | meizuFlags.setInt(params, value); 84 | window.setAttributes(params); 85 | darkFlag.setAccessible(false); 86 | meizuFlags.setAccessible(false); 87 | } catch (Exception e) { 88 | e.printStackTrace(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/widget/DraggableFrameLayout.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.support.annotation.AttrRes; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.widget.ViewDragHelper; 9 | import android.util.AttributeSet; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.widget.FrameLayout; 13 | 14 | import com.sunfusheng.util.Utils; 15 | 16 | /** 17 | * @author by sunfusheng on 2017/6/27. 18 | */ 19 | public class DraggableFrameLayout extends FrameLayout { 20 | 21 | private ViewDragHelper dragHelper; 22 | private int screenWidth; 23 | private int margin = 10; 24 | 25 | public DraggableFrameLayout(@NonNull Context context) { 26 | this(context, null); 27 | } 28 | 29 | public DraggableFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) { 30 | this(context, attrs, 0); 31 | } 32 | 33 | public DraggableFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, 34 | @AttrRes int defStyleAttr) { 35 | super(context, attrs, defStyleAttr); 36 | init(); 37 | } 38 | 39 | private void init() { 40 | screenWidth = Utils.getWindowWidth(getContext()); 41 | margin = Utils.dp2px(getContext(), margin); 42 | 43 | dragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() { 44 | 45 | @Override 46 | public boolean tryCaptureView(@NonNull View child, int pointerId) { 47 | return true; 48 | } 49 | 50 | @Override 51 | public void onViewCaptured(@NonNull View capturedChild, int activePointerId) { 52 | super.onViewCaptured(capturedChild, activePointerId); 53 | } 54 | 55 | @Override 56 | public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) { 57 | return left; 58 | } 59 | 60 | @Override 61 | public int clampViewPositionVertical(@NonNull View child, int top, int dy) { 62 | return top; 63 | } 64 | 65 | @Override 66 | public int getViewHorizontalDragRange(@NonNull View child) { 67 | return getMeasuredWidth() - child.getMeasuredWidth(); 68 | } 69 | 70 | @Override 71 | public int getViewVerticalDragRange(@NonNull View child) { 72 | return getMeasuredHeight() - child.getMeasuredHeight(); 73 | } 74 | 75 | @Override 76 | public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) { 77 | super.onViewReleased(releasedChild, xvel, yvel); 78 | int viewWidth = releasedChild.getWidth(); 79 | int viewHeight = releasedChild.getHeight(); 80 | int curLeft = releasedChild.getLeft(); 81 | int curTop = releasedChild.getTop(); 82 | 83 | int finalLeft = margin; 84 | int finalTop = Math.max(curTop, margin); 85 | 86 | if ((curLeft + viewWidth / 2) > screenWidth / 2) { 87 | finalLeft = screenWidth - viewWidth - margin; 88 | } 89 | 90 | if ((finalTop + viewHeight) > getHeight()) { 91 | finalTop = getHeight() - viewHeight - margin; 92 | } 93 | 94 | dragHelper.settleCapturedViewAt(finalLeft, finalTop); 95 | invalidate(); 96 | } 97 | }); 98 | } 99 | 100 | @Override 101 | public boolean onInterceptTouchEvent(MotionEvent ev) { 102 | return dragHelper.shouldInterceptTouchEvent(ev); 103 | } 104 | 105 | @Override 106 | public boolean onTouchEvent(MotionEvent event) { 107 | dragHelper.processTouchEvent(event); 108 | return isTouchChildView(event); 109 | } 110 | 111 | @Override 112 | public void computeScroll() { 113 | super.computeScroll(); 114 | if (dragHelper.continueSettling(true)) { 115 | invalidate(); 116 | } 117 | } 118 | 119 | private boolean isTouchChildView(MotionEvent ev) { 120 | Rect rect = new Rect(); 121 | for (int i = 0; i < getChildCount(); i++) { 122 | View view = getChildAt(i); 123 | rect.set((int) view.getX(), (int) view.getY(), (int) view.getX() + view.getWidth(), 124 | (int) view.getY() + view.getHeight()); 125 | if (rect.contains((int) ev.getX(), (int) ev.getY())) { 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Sample/src/main/java/com/sunfusheng/glideimageview/sample/widget/SlideVerticallyLayout.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.glideimageview.sample.widget; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ValueAnimator; 6 | import android.content.Context; 7 | import android.os.Build; 8 | import android.support.v4.view.ViewCompat; 9 | import android.util.AttributeSet; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.widget.FrameLayout; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class SlideVerticallyLayout extends FrameLayout { 18 | 19 | private int mDownY; 20 | private int mEndY; 21 | private ValueAnimator mSlideAnimator; 22 | private boolean isCanScroll; 23 | private boolean isTouchWithAnimRunning; 24 | private final int MIN_SCROLL_OFFSET = 50; 25 | private final static int ANIM_DURATION = 280; 26 | private final static int THRESHOLD = 4; 27 | private List mSlideView = new ArrayList<>(); 28 | private List slideCblist = new ArrayList<>(); 29 | private List stateCblist = new ArrayList<>(); 30 | private boolean isSlideShown = true; 31 | 32 | public void addSlideCallback(ISlideCallback callback) { 33 | slideCblist.add(callback); 34 | } 35 | 36 | public void addStateCallback(IStateCallback callback) { 37 | stateCblist.add(callback); 38 | } 39 | 40 | public SlideVerticallyLayout(Context context) { 41 | this(context, null); 42 | } 43 | 44 | public SlideVerticallyLayout(Context context, AttributeSet attrs) { 45 | this(context, attrs, 0); 46 | } 47 | 48 | public SlideVerticallyLayout(Context context, AttributeSet attrs, int defStyleAttr) { 49 | super(context, attrs, defStyleAttr); 50 | init(); 51 | } 52 | 53 | void init() { 54 | mSlideAnimator = ValueAnimator.ofFloat(0, 1.0f).setDuration(ANIM_DURATION); 55 | mSlideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 56 | @Override 57 | public void onAnimationUpdate(ValueAnimator animation) { 58 | float factor = (float) animation.getAnimatedValue(); 59 | int diffY = mEndY - mDownY; 60 | for (ISlideCallback cb : slideCblist) { 61 | cb.onPositionChange((int) (mDownY + diffY * factor)); 62 | } 63 | } 64 | }); 65 | mSlideAnimator.addListener(new AnimatorListenerAdapter() { 66 | @Override 67 | public void onAnimationEnd(Animator animation) { 68 | if (isSlideShown && mEndY == getHeight()) { 69 | isSlideShown = false; 70 | for (IStateCallback cb : stateCblist) { 71 | cb.onHide(); 72 | } 73 | } else if (!isSlideShown && mEndY == 0) { 74 | isSlideShown = true; 75 | for (IStateCallback cb : stateCblist) { 76 | cb.onShow(); 77 | } 78 | } 79 | mDownY = mEndY; 80 | isCanScroll = false; 81 | } 82 | }); 83 | addSlideCallback(offsetY -> { 84 | float factor = (float) (getHeight() - offsetY) / (float) getHeight(); 85 | setBackgroundColor(((int) (factor * 0xc4)) << 24); 86 | }); 87 | addSlideCallback(offsetY -> { 88 | for (View view : mSlideView) { 89 | view.setTranslationY(offsetY); 90 | } 91 | }); 92 | } 93 | 94 | public void addSlideView(View view) { 95 | mSlideView.add(view); 96 | } 97 | 98 | public void slideDown(boolean anim) { 99 | if (!isSlideShown) return; 100 | if (anim) { 101 | mEndY = getHeight(); 102 | mDownY = 0; 103 | mSlideAnimator.start(); 104 | } else { 105 | for (ISlideCallback cb : slideCblist) { 106 | cb.onPositionChange(getHeight()); 107 | } 108 | isSlideShown = false; 109 | } 110 | } 111 | 112 | public void slideUp(boolean anim) { 113 | if (isSlideShown) return; 114 | if (anim) { 115 | mEndY = 0; 116 | mDownY = getHeight(); 117 | mSlideAnimator.start(); 118 | } else { 119 | for (ISlideCallback cb : slideCblist) { 120 | cb.onPositionChange(0); 121 | } 122 | isSlideShown = true; 123 | } 124 | } 125 | 126 | @Override 127 | public boolean onInterceptTouchEvent(MotionEvent event) { 128 | if (!canChildScrollUp()) { 129 | final int y = (int) event.getY(); 130 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 131 | case MotionEvent.ACTION_DOWN: 132 | isTouchWithAnimRunning = mSlideAnimator.isRunning(); 133 | mDownY = y; 134 | break; 135 | case MotionEvent.ACTION_MOVE: 136 | if (isGreaterThanMinSize(mDownY, y) && !isTouchWithAnimRunning) { 137 | isCanScroll = true; 138 | return true; 139 | } 140 | break; 141 | } 142 | } 143 | return super.onInterceptTouchEvent(event); 144 | } 145 | 146 | @Override 147 | public boolean onTouchEvent(MotionEvent event) { 148 | final int y = (int) event.getY(); 149 | int offsetY = y - mDownY; 150 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 151 | case MotionEvent.ACTION_MOVE: 152 | if (isGreaterThanMinSize(mDownY, y) && isCanScroll) { 153 | for (ISlideCallback cb : slideCblist) { 154 | cb.onPositionChange(getPositionChangeY(offsetY)); 155 | } 156 | } else if (isCanScroll) { 157 | for (ISlideCallback cb : slideCblist) { 158 | cb.onPositionChange(0); 159 | } 160 | } 161 | return true; 162 | case MotionEvent.ACTION_POINTER_DOWN: 163 | case MotionEvent.ACTION_UP: 164 | if (isGreaterThanMinSize(mDownY, y) && isCanScroll) { 165 | mDownY = getPositionChangeY(offsetY); 166 | fixPosition(offsetY); 167 | mSlideAnimator.start(); 168 | } 169 | break; 170 | } 171 | return super.onTouchEvent(event); 172 | } 173 | 174 | private boolean canChildScrollUp() { 175 | for (View view : mSlideView) { 176 | if (canChildScrollUp(view)) return true; 177 | } 178 | return false; 179 | } 180 | 181 | private boolean canChildScrollUp(View view) { 182 | if (Build.VERSION.SDK_INT < 14) { 183 | return ViewCompat.canScrollVertically(view, -1) || view.getScrollY() > 0; 184 | } else { 185 | return ViewCompat.canScrollVertically(view, -1); 186 | } 187 | } 188 | 189 | private int getPositionChangeY(int offsetY) { 190 | if (isSlideShown) { 191 | return Math.abs(offsetY) - MIN_SCROLL_OFFSET; 192 | } else { 193 | return getHeight() - (Math.abs(offsetY)) - MIN_SCROLL_OFFSET; 194 | } 195 | } 196 | 197 | private boolean isGreaterThanMinSize(int y1, int y2) { 198 | if (isSlideShown) { 199 | return y2 - y1 > MIN_SCROLL_OFFSET; 200 | } else { 201 | return y1 - y2 > MIN_SCROLL_OFFSET; 202 | } 203 | } 204 | 205 | private void fixPosition(int offsetY) { 206 | int absOffsetY = Math.abs(offsetY); 207 | if (isSlideShown && absOffsetY > getHeight() / THRESHOLD) { 208 | mEndY = getHeight(); 209 | } else if (!isSlideShown && absOffsetY > getHeight() / THRESHOLD) { 210 | mEndY = 0; 211 | } 212 | } 213 | 214 | public interface ISlideCallback { 215 | void onPositionChange(int offsetY); 216 | } 217 | 218 | public interface IStateCallback { 219 | void onShow(); 220 | 221 | void onHide(); 222 | } 223 | 224 | } 225 | -------------------------------------------------------------------------------- /Sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /Sample/src/main/res/drawable/drawable_corner_icon_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | -------------------------------------------------------------------------------- /Sample/src/main/res/drawable/gif_robot_walk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/drawable/gif_robot_walk.gif -------------------------------------------------------------------------------- /Sample/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /Sample/src/main/res/drawable/progressbar_orange_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 22 | 23 | 31 | 32 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/activity_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 25 | 26 | 27 | 40 | 41 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 18 | 19 | 25 | 26 | 32 | 33 | 39 | 40 | 46 | 47 | 53 | 54 | 55 | 60 | 61 | 66 | 67 | 72 | 73 | 78 | 79 | 84 | 85 | 86 | 92 | 93 | 98 | 99 | 112 | 113 | 114 | 120 | 121 | 126 | 127 | 141 | 142 | 143 | 151 | 152 | 153 | 154 | 155 | 158 | 159 | 166 | 167 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/activity_preview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 22 | 23 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/item_nine_images.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 22 | 23 | 28 | 29 | 35 | 36 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/item_photoview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 26 | 27 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/item_right_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 17 | 18 | 30 | 31 | 36 | 37 | 38 | 44 | 45 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/item_three_images.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 23 | 24 | 29 | 30 | 34 | 35 | 43 | 44 | 45 | 50 | 51 | 59 | 60 | 61 | 66 | 67 | 75 | 76 | 77 | 78 | 84 | 85 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/item_top_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 23 | 24 | 29 | 30 | 38 | 39 | 40 | 46 | 47 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/layout_image_cell.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 42 | 43 | 53 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/layout_recyclerview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/layout_roundimageview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Sample/src/main/res/layout/layout_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 18 | -------------------------------------------------------------------------------- /Sample/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-xhdpi/ic_multi_imageview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-xhdpi/ic_multi_imageview.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-xxhdpi/ic_multi_imageview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-xxhdpi/ic_multi_imageview.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Sample/src/main/res/mipmap-xxxhdpi/she.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/Sample/src/main/res/mipmap-xxxhdpi/she.png -------------------------------------------------------------------------------- /Sample/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 19 | 20 | -------------------------------------------------------------------------------- /Sample/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #607d8b 5 | #607d8b 6 | #607d8b 7 | 8 | 9 | #ff000000 10 | #D9000000 11 | #8C000000 12 | #66000000 13 | #1A000000 14 | #C34A42 15 | #FF9800 16 | #009734 17 | #46AE36 18 | #47B000 19 | #007AFF 20 | #1194F6 21 | #9D1BB2 22 | 23 | #00000000 24 | #0B000000 25 | #1A000000 26 | #33000000 27 | #4D000000 28 | #66000000 29 | #80000000 30 | #9A000000 31 | #B3000000 32 | #CC000000 33 | #E5000000 34 | #FF000000 35 | 36 | #00ffffff 37 | #1Affffff 38 | #33ffffff 39 | #4Dffffff 40 | #66ffffff 41 | #80ffffff 42 | #9Affffff 43 | #B3ffffff 44 | #CCffffff 45 | #E5ffffff 46 | #FFffffff 47 | 48 | #33000000 49 | #33fbc02d 50 | #33f57c00 51 | 52 | #FFFFFF 53 | #fbc02d 54 | #FFD700 55 | #f57c00 56 | #d01716 57 | #808080 58 | #0a7e07 59 | #455ede 60 | #000000 61 | 62 | 63 | -------------------------------------------------------------------------------- /Sample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28sp 5 | 26sp 6 | 24sp 7 | 20sp 8 | 17sp 9 | 16sp 10 | 14sp 11 | 12sp 12 | 10sp 13 | 8sp 14 | 15 | 16 | 1dp 17 | 2dp 18 | 4dp 19 | 8dp 20 | 12dp 21 | 16dp 22 | 24dp 23 | 24 | 25 | 73dp 26 | 36dp 27 | 28dp 28 | 22dp 29 | 15dp 30 | 31 | 0dp 32 | 33 | 34 | -------------------------------------------------------------------------------- /Sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GlideImageView 4 | the image of transition 5 | %1$d/%2$d 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 18 | 19 | 28 | 29 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | mavenCentral() 6 | maven { url "https://jitpack.io" } 7 | maven { url 'https://maven.google.com' } 8 | maven { url 'https://dl.bintray.com/sfsheng0322/maven' } 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.5.1' 13 | classpath 'com.novoda:bintray-release:0.9' 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | mavenCentral() 22 | maven { url "https://jitpack.io" } 23 | maven { url 'https://maven.google.com' } 24 | maven { url 'https://dl.bintray.com/sfsheng0322/maven' } 25 | } 26 | 27 | ext { 28 | COMPILE_SDK_VERSION = 28 29 | BUILD_TOOL_VERSION = '28.0.3' 30 | SUPPORT_LIBRARY_VERSION = '28.0.0' 31 | GLIDE_VERSION = '4.9.0' 32 | 33 | MIN_SDK_VERSION = 14 34 | TARGET_SDK_VERSION = 28 35 | VERSION_CODE = 8 36 | VERSION_NAME = '2.1.0' 37 | } 38 | } 39 | 40 | task clean(type: Delete) { 41 | delete rootProject.buildDir 42 | } 43 | 44 | ext { 45 | compileSdkVersion = 27 46 | buildToolsVersion = '27.1.1' 47 | supportLibraryVersion = '27.1.1' 48 | 49 | minSdkVersion = 14 50 | targetSdkVersion = 27 51 | versionCode = 7 52 | versionName = "2.0.2" 53 | } -------------------------------------------------------------------------------- /glideimageview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /glideimageview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release' 3 | 4 | android { 5 | compileSdkVersion COMPILE_SDK_VERSION 6 | defaultConfig { 7 | minSdkVersion MIN_SDK_VERSION 8 | targetSdkVersion TARGET_SDK_VERSION 9 | versionCode VERSION_CODE 10 | versionName VERSION_NAME 11 | } 12 | 13 | compileOptions { 14 | sourceCompatibility JavaVersion.VERSION_1_8 15 | targetCompatibility JavaVersion.VERSION_1_8 16 | } 17 | 18 | lintOptions { 19 | abortOnError false 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | api 'com.android.support:support-v4:' + SUPPORT_LIBRARY_VERSION 32 | api 'com.github.bumptech.glide:glide:' + GLIDE_VERSION 33 | api 'com.github.bumptech.glide:annotations:' + GLIDE_VERSION 34 | annotationProcessor 'com.github.bumptech.glide:compiler:' + GLIDE_VERSION 35 | api 'com.github.bumptech.glide:okhttp3-integration:' + GLIDE_VERSION 36 | } 37 | 38 | publish { 39 | userOrg = 'sfsheng0322' 40 | groupId = 'com.sunfusheng' 41 | artifactId = 'GlideImageView' 42 | publishVersion = VERSION_NAME 43 | desc = 'GlideImageView is an image loading library which you can listen to the progress of loading.' 44 | website = 'https://github.com/sunfusheng/GlideImageView' 45 | } 46 | -------------------------------------------------------------------------------- /glideimageview/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 /Users/sunfusheng/Android/Studio/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 | 27 | -keep public class extends com.bumptech.glide.module.AppGlideModule 28 | -keep class com.bumptech.glide.GeneratedAppGlideModuleImpl -------------------------------------------------------------------------------- /glideimageview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/GlideImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | import android.net.Uri; 7 | import android.support.annotation.DrawableRes; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.Nullable; 10 | import android.widget.ImageView; 11 | 12 | import com.bumptech.glide.load.Transformation; 13 | import com.bumptech.glide.request.target.DrawableImageViewTarget; 14 | import com.bumptech.glide.request.transition.Transition; 15 | import com.sunfusheng.progress.GlideApp; 16 | import com.sunfusheng.progress.GlideRequest; 17 | import com.sunfusheng.progress.OnProgressListener; 18 | import com.sunfusheng.progress.ProgressManager; 19 | 20 | import java.lang.ref.WeakReference; 21 | 22 | /** 23 | * @author by sunfusheng on 2017/6/6. 24 | */ 25 | public class GlideImageLoader { 26 | 27 | protected static final String ANDROID_RESOURCE = "android.resource://"; 28 | protected static final String FILE = "file://"; 29 | protected static final String SEPARATOR = "/"; 30 | 31 | private String url; 32 | private WeakReference imageViewWeakReference; 33 | private GlideRequest glideRequest; 34 | 35 | public static GlideImageLoader create(ImageView imageView) { 36 | return new GlideImageLoader(imageView); 37 | } 38 | 39 | private GlideImageLoader(ImageView imageView) { 40 | imageViewWeakReference = new WeakReference<>(imageView); 41 | glideRequest = GlideApp.with(getContext()).asDrawable(); 42 | } 43 | 44 | public ImageView getImageView() { 45 | if (imageViewWeakReference != null) { 46 | return imageViewWeakReference.get(); 47 | } 48 | return null; 49 | } 50 | 51 | public Context getContext() { 52 | if (getImageView() != null) { 53 | return getImageView().getContext(); 54 | } 55 | return null; 56 | } 57 | 58 | public String getUrl() { 59 | return url; 60 | } 61 | 62 | public GlideRequest getGlideRequest() { 63 | if (glideRequest == null) { 64 | glideRequest = GlideApp.with(getContext()).asDrawable(); 65 | } 66 | return glideRequest; 67 | } 68 | 69 | protected Uri resId2Uri(@DrawableRes int resId) { 70 | return Uri.parse(ANDROID_RESOURCE + getContext().getPackageName() + SEPARATOR + resId); 71 | } 72 | 73 | public GlideImageLoader load(@DrawableRes int resId, @DrawableRes int placeholder, @NonNull Transformation transformation) { 74 | return loadImage(resId2Uri(resId), placeholder, transformation); 75 | } 76 | 77 | protected GlideRequest loadImage(Object obj) { 78 | if (obj instanceof String) { 79 | url = (String) obj; 80 | } 81 | return glideRequest.load(obj); 82 | } 83 | 84 | 85 | protected GlideImageLoader loadImage(Object obj, @DrawableRes int placeholder, Transformation transformation) { 86 | glideRequest = loadImage(obj); 87 | if (placeholder != 0) { 88 | glideRequest = glideRequest.placeholder(placeholder); 89 | } 90 | 91 | if (transformation != null) { 92 | glideRequest = glideRequest.transform(transformation); 93 | } 94 | 95 | glideRequest.into(new GlideImageViewTarget(getImageView())); 96 | return this; 97 | } 98 | 99 | public GlideImageLoader listener(Object obj, OnProgressListener onProgressListener) { 100 | if (obj instanceof String) { 101 | url = (String) obj; 102 | } 103 | ProgressManager.addListener(url, onProgressListener); 104 | return this; 105 | } 106 | 107 | private class GlideImageViewTarget extends DrawableImageViewTarget { 108 | GlideImageViewTarget(ImageView view) { 109 | super(view); 110 | } 111 | 112 | @Override 113 | public void onLoadStarted(Drawable placeholder) { 114 | super.onLoadStarted(placeholder); 115 | } 116 | 117 | @Override 118 | public void onLoadFailed(@Nullable Drawable errorDrawable) { 119 | OnProgressListener onProgressListener = ProgressManager.getProgressListener(getUrl()); 120 | if (onProgressListener != null) { 121 | onProgressListener.onProgress(true, 100, 0, 0); 122 | ProgressManager.removeListener(getUrl()); 123 | } 124 | super.onLoadFailed(errorDrawable); 125 | } 126 | 127 | @Override 128 | public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { 129 | OnProgressListener onProgressListener = ProgressManager.getProgressListener(getUrl()); 130 | if (onProgressListener != null) { 131 | onProgressListener.onProgress(true, 100, 0, 0); 132 | ProgressManager.removeListener(getUrl()); 133 | } 134 | super.onResourceReady(resource, transition); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/GlideImageView.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.support.annotation.DrawableRes; 7 | import android.support.annotation.NonNull; 8 | import android.util.AttributeSet; 9 | import android.widget.ImageView; 10 | 11 | import com.bumptech.glide.load.Transformation; 12 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 13 | import com.bumptech.glide.request.RequestOptions; 14 | import com.sunfusheng.progress.OnProgressListener; 15 | import com.sunfusheng.transformation.CircleTransformation; 16 | import com.sunfusheng.transformation.RadiusTransformation; 17 | 18 | /** 19 | * @author sunfusheng on 2017/11/10. 20 | */ 21 | @SuppressLint("CheckResult") 22 | public class GlideImageView extends ImageView { 23 | 24 | private boolean enableState = false; 25 | private float pressedAlpha = 0.4f; 26 | private float unableAlpha = 0.3f; 27 | private GlideImageLoader imageLoader; 28 | 29 | public GlideImageView(Context context) { 30 | this(context, null); 31 | } 32 | 33 | public GlideImageView(Context context, AttributeSet attrs) { 34 | this(context, attrs, 0); 35 | } 36 | 37 | public GlideImageView(Context context, AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | init(); 40 | } 41 | 42 | private void init() { 43 | imageLoader = GlideImageLoader.create(this); 44 | } 45 | 46 | public GlideImageLoader getImageLoader() { 47 | if (imageLoader == null) { 48 | imageLoader = GlideImageLoader.create(this); 49 | } 50 | return imageLoader; 51 | } 52 | 53 | public GlideImageView apply(RequestOptions options) { 54 | getImageLoader().getGlideRequest().apply(options); 55 | return this; 56 | } 57 | 58 | public GlideImageView centerCrop() { 59 | getImageLoader().getGlideRequest().centerCrop(); 60 | return this; 61 | } 62 | 63 | public GlideImageView fitCenter() { 64 | getImageLoader().getGlideRequest().fitCenter(); 65 | return this; 66 | } 67 | 68 | public GlideImageView diskCacheStrategy(@NonNull DiskCacheStrategy strategy) { 69 | getImageLoader().getGlideRequest().diskCacheStrategy(strategy); 70 | return this; 71 | } 72 | 73 | public GlideImageView placeholder(@DrawableRes int resId) { 74 | getImageLoader().getGlideRequest().placeholder(resId); 75 | return this; 76 | } 77 | 78 | public GlideImageView error(@DrawableRes int resId) { 79 | getImageLoader().getGlideRequest().error(resId); 80 | return this; 81 | } 82 | 83 | public GlideImageView fallback(@DrawableRes int resId) { 84 | getImageLoader().getGlideRequest().fallback(resId); 85 | return this; 86 | } 87 | 88 | public GlideImageView dontAnimate() { 89 | getImageLoader().getGlideRequest().dontTransform(); 90 | return this; 91 | } 92 | 93 | public GlideImageView dontTransform() { 94 | getImageLoader().getGlideRequest().dontTransform(); 95 | return this; 96 | } 97 | 98 | public void load(String url) { 99 | load(url, 0); 100 | } 101 | 102 | public void load(String url, @DrawableRes int placeholder) { 103 | load(url, placeholder, 0); 104 | } 105 | 106 | public void load(String url, @DrawableRes int placeholder, int radius) { 107 | load(url, placeholder, radius, null); 108 | } 109 | 110 | public void load(String url, @DrawableRes int placeholder, OnProgressListener onProgressListener) { 111 | load(url, placeholder, null, onProgressListener); 112 | } 113 | 114 | public void load(String url, @DrawableRes int placeholder, int radius, OnProgressListener onProgressListener) { 115 | load(url, placeholder, new RadiusTransformation(getContext(), radius), onProgressListener); 116 | } 117 | 118 | public void load(Object obj, @DrawableRes int placeholder, Transformation transformation) { 119 | getImageLoader().loadImage(obj, placeholder, transformation); 120 | } 121 | 122 | public void load(Object obj, @DrawableRes int placeholder, Transformation transformation, OnProgressListener onProgressListener) { 123 | getImageLoader().listener(obj, onProgressListener).loadImage(obj, placeholder, transformation); 124 | } 125 | 126 | public void loadCircle(String url) { 127 | loadCircle(url, 0); 128 | } 129 | 130 | public void loadCircle(String url, @DrawableRes int placeholder) { 131 | loadCircle(url, placeholder, null); 132 | } 133 | 134 | public void loadCircle(String url, @DrawableRes int placeholder, OnProgressListener onProgressListener) { 135 | load(url, placeholder, new CircleTransformation(), onProgressListener); 136 | } 137 | 138 | public void loadDrawable(@DrawableRes int resId) { 139 | loadDrawable(resId, 0); 140 | } 141 | 142 | public void loadDrawable(@DrawableRes int resId, @DrawableRes int placeholder) { 143 | loadDrawable(resId, placeholder, null); 144 | } 145 | 146 | public void loadDrawable(@DrawableRes int resId, @DrawableRes int placeholder, @NonNull Transformation transformation) { 147 | getImageLoader().load(resId, placeholder, transformation); 148 | } 149 | 150 | @Override 151 | protected void drawableStateChanged() { 152 | super.drawableStateChanged(); 153 | if (enableState) { 154 | if (isPressed()) { 155 | setAlpha(pressedAlpha); 156 | } else if (!isEnabled()) { 157 | setAlpha(unableAlpha); 158 | } else { 159 | setAlpha(1.0f); 160 | } 161 | } 162 | } 163 | 164 | public GlideImageView enableState(boolean enableState) { 165 | this.enableState = enableState; 166 | return this; 167 | } 168 | 169 | public GlideImageView pressedAlpha(float pressedAlpha) { 170 | this.pressedAlpha = pressedAlpha; 171 | return this; 172 | } 173 | 174 | public GlideImageView unableAlpha(float unableAlpha) { 175 | this.unableAlpha = unableAlpha; 176 | return this; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/progress/OnProgressListener.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.progress; 2 | 3 | /** 4 | * @author by sunfusheng on 2017/6/14. 5 | */ 6 | public interface OnProgressListener { 7 | void onProgress(boolean isComplete, int percentage, long bytesRead, long totalBytes); 8 | } 9 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/progress/ProgressAppGlideModule.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.progress; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | 6 | import com.bumptech.glide.Glide; 7 | import com.bumptech.glide.Registry; 8 | import com.bumptech.glide.annotation.GlideModule; 9 | import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; 10 | import com.bumptech.glide.load.model.GlideUrl; 11 | import com.bumptech.glide.module.AppGlideModule; 12 | 13 | import java.io.InputStream; 14 | 15 | /** 16 | * @author by sunfusheng on 2017/6/14. 17 | */ 18 | @GlideModule 19 | public class ProgressAppGlideModule extends AppGlideModule { 20 | @Override 21 | public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { 22 | super.registerComponents(context, glide, registry); 23 | registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(ProgressManager.getOkHttpClient())); 24 | } 25 | } -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/progress/ProgressManager.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.progress; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.util.Collections; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import okhttp3.OkHttpClient; 10 | import okhttp3.Request; 11 | import okhttp3.Response; 12 | 13 | /** 14 | * @author by sunfusheng on 2017/6/14. 15 | */ 16 | public class ProgressManager { 17 | 18 | private static Map listenersMap = Collections.synchronizedMap(new HashMap<>()); 19 | private static OkHttpClient okHttpClient; 20 | 21 | private ProgressManager() { 22 | } 23 | 24 | public static OkHttpClient getOkHttpClient() { 25 | if (okHttpClient == null) { 26 | okHttpClient = new OkHttpClient.Builder() 27 | .addNetworkInterceptor(chain -> { 28 | Request request = chain.request(); 29 | Response response = chain.proceed(request); 30 | return response.newBuilder() 31 | .body(new ProgressResponseBody(request.url().toString(), LISTENER, response.body())) 32 | .build(); 33 | }) 34 | .build(); 35 | } 36 | return okHttpClient; 37 | } 38 | 39 | private static final ProgressResponseBody.InternalProgressListener LISTENER = (url, bytesRead, totalBytes) -> { 40 | OnProgressListener onProgressListener = getProgressListener(url); 41 | if (onProgressListener != null) { 42 | int percentage = (int) ((bytesRead * 1f / totalBytes) * 100f); 43 | boolean isComplete = percentage >= 100; 44 | onProgressListener.onProgress(isComplete, percentage, bytesRead, totalBytes); 45 | if (isComplete) { 46 | removeListener(url); 47 | } 48 | } 49 | }; 50 | 51 | public static void addListener(String url, OnProgressListener listener) { 52 | if (!TextUtils.isEmpty(url) && listener != null) { 53 | listenersMap.put(url, listener); 54 | listener.onProgress(false, 1, 0, 0); 55 | } 56 | } 57 | 58 | public static void removeListener(String url) { 59 | if (!TextUtils.isEmpty(url)) { 60 | listenersMap.remove(url); 61 | } 62 | } 63 | 64 | public static OnProgressListener getProgressListener(String url) { 65 | if (TextUtils.isEmpty(url) || listenersMap == null || listenersMap.size() == 0) { 66 | return null; 67 | } 68 | 69 | OnProgressListener listenerWeakReference = listenersMap.get(url); 70 | if (listenerWeakReference != null) { 71 | return listenerWeakReference; 72 | } 73 | return null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/progress/ProgressResponseBody.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.progress; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import android.support.annotation.NonNull; 6 | 7 | import java.io.IOException; 8 | 9 | import okhttp3.MediaType; 10 | import okhttp3.ResponseBody; 11 | import okio.Buffer; 12 | import okio.BufferedSource; 13 | import okio.ForwardingSource; 14 | import okio.Okio; 15 | import okio.Source; 16 | 17 | /** 18 | * @author by sunfusheng on 2017/6/14. 19 | */ 20 | public class ProgressResponseBody extends ResponseBody { 21 | 22 | private static final Handler mainThreadHandler = new Handler(Looper.getMainLooper()); 23 | 24 | private String url; 25 | private ProgressResponseBody.InternalProgressListener internalProgressListener; 26 | 27 | private ResponseBody responseBody; 28 | private BufferedSource bufferedSource; 29 | 30 | ProgressResponseBody(String url, ProgressResponseBody.InternalProgressListener internalProgressListener, ResponseBody responseBody) { 31 | this.url = url; 32 | this.internalProgressListener = internalProgressListener; 33 | this.responseBody = responseBody; 34 | } 35 | 36 | @Override 37 | public MediaType contentType() { 38 | return responseBody.contentType(); 39 | } 40 | 41 | @Override 42 | public long contentLength() { 43 | return responseBody.contentLength(); 44 | } 45 | 46 | @Override 47 | public BufferedSource source() { 48 | if (bufferedSource == null) { 49 | bufferedSource = Okio.buffer(source(responseBody.source())); 50 | } 51 | return bufferedSource; 52 | } 53 | 54 | private Source source(Source source) { 55 | return new ForwardingSource(source) { 56 | long totalBytesRead; 57 | long lastTotalBytesRead; 58 | 59 | @Override 60 | public long read(@NonNull Buffer sink, long byteCount) throws IOException { 61 | long bytesRead = super.read(sink, byteCount); 62 | totalBytesRead += (bytesRead == -1) ? 0 : bytesRead; 63 | 64 | if (internalProgressListener != null && lastTotalBytesRead != totalBytesRead) { 65 | lastTotalBytesRead = totalBytesRead; 66 | mainThreadHandler.post(() -> internalProgressListener.onProgress(url, totalBytesRead, contentLength())); 67 | } 68 | return bytesRead; 69 | } 70 | }; 71 | } 72 | 73 | interface InternalProgressListener { 74 | void onProgress(String url, long bytesRead, long totalBytes); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/transformation/BlurTransformation.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.transformation; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.os.Build; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.RequiresApi; 10 | 11 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 12 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 13 | import com.bumptech.glide.util.Util; 14 | import com.sunfusheng.util.BlurUtils; 15 | 16 | import java.security.MessageDigest; 17 | 18 | /** 19 | * @author sunfusheng on 2018/6/25. 20 | */ 21 | public class BlurTransformation extends BitmapTransformation { 22 | private final String ID = getClass().getName(); 23 | 24 | private static int MAX_RADIUS = 25; 25 | private static int DEFAULT_SAMPLING = 1; 26 | 27 | private Context context; 28 | private int radius; //模糊半径0~25 29 | private int sampling; //取样0~25 30 | 31 | public BlurTransformation(Context context) { 32 | this(context, MAX_RADIUS, DEFAULT_SAMPLING); 33 | } 34 | 35 | public BlurTransformation(Context context, int radius) { 36 | this(context, radius, DEFAULT_SAMPLING); 37 | } 38 | 39 | public BlurTransformation(Context context, int radius, int sampling) { 40 | this.context = context; 41 | this.radius = radius > MAX_RADIUS ? MAX_RADIUS : radius; 42 | this.sampling = sampling > MAX_RADIUS ? MAX_RADIUS : sampling; 43 | } 44 | 45 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) 46 | @Override 47 | protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { 48 | int width = toTransform.getWidth(); 49 | int height = toTransform.getHeight(); 50 | int scaledWidth = width / sampling; 51 | int scaledHeight = height / sampling; 52 | 53 | Bitmap bitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); 54 | Canvas canvas = new Canvas(bitmap); 55 | canvas.scale(1 / (float) sampling, 1 / (float) sampling); 56 | Paint paint = new Paint(); 57 | paint.setFlags(Paint.FILTER_BITMAP_FLAG); 58 | canvas.drawBitmap(toTransform, 0, 0, paint); 59 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 60 | bitmap = BlurUtils.rsBlur(context, bitmap, radius); 61 | } else { 62 | bitmap = BlurUtils.blur(bitmap, radius); 63 | } 64 | return bitmap; 65 | } 66 | 67 | @Override 68 | public boolean equals(Object obj) { 69 | if (obj instanceof BlurTransformation) { 70 | BlurTransformation other = (BlurTransformation) obj; 71 | return radius == other.radius && sampling == other.sampling; 72 | } 73 | return false; 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | return Util.hashCode(ID.hashCode(), Util.hashCode(radius, Util.hashCode(sampling))); 79 | } 80 | 81 | @Override 82 | public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { 83 | messageDigest.update((ID + radius * 10 + sampling).getBytes(CHARSET)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/transformation/CircleTransformation.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.transformation; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapShader; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.support.annotation.NonNull; 8 | 9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 10 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 11 | import com.bumptech.glide.util.Util; 12 | 13 | import java.security.MessageDigest; 14 | 15 | /** 16 | * @author by sunfusheng on 2017/6/6. 17 | */ 18 | public class CircleTransformation extends BitmapTransformation { 19 | private final String ID = getClass().getName(); 20 | 21 | @Override 22 | protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { 23 | int size = Math.min(toTransform.getWidth(), toTransform.getHeight()); 24 | int x = (toTransform.getWidth() - size) / 2; 25 | int y = (toTransform.getHeight() - size) / 2; 26 | 27 | Bitmap square = Bitmap.createBitmap(toTransform, x, y, size, size); 28 | Bitmap circle = pool.get(size, size, Bitmap.Config.ARGB_8888); 29 | 30 | Canvas canvas = new Canvas(circle); 31 | Paint paint = new Paint(); 32 | paint.setShader(new BitmapShader(square, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 33 | paint.setAntiAlias(true); 34 | float r = size / 2f; 35 | canvas.drawCircle(r, r, r, paint); 36 | return circle; 37 | } 38 | 39 | @Override 40 | public boolean equals(Object obj) { 41 | if (obj instanceof BlurTransformation) { 42 | return this == obj; 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return Util.hashCode(ID.hashCode()); 50 | } 51 | 52 | @Override 53 | public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { 54 | messageDigest.update(ID.getBytes(CHARSET)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/transformation/RadiusTransformation.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.transformation; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapShader; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.support.annotation.NonNull; 10 | 11 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 12 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 13 | import com.bumptech.glide.util.Util; 14 | import com.sunfusheng.util.Utils; 15 | 16 | import java.security.MessageDigest; 17 | 18 | /** 19 | * @author by sunfusheng on 2017/6/6. 20 | */ 21 | public class RadiusTransformation extends BitmapTransformation { 22 | private final String ID = getClass().getName(); 23 | 24 | private int radius; 25 | 26 | public RadiusTransformation(Context context, int radius) { 27 | this.radius = Utils.dp2px(context, radius); 28 | } 29 | 30 | @Override 31 | protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { 32 | int width = toTransform.getWidth(); 33 | int height = toTransform.getHeight(); 34 | 35 | Bitmap bitmap = pool.get(width, height, Bitmap.Config.ARGB_8888); 36 | bitmap.setHasAlpha(true); 37 | Canvas canvas = new Canvas(bitmap); 38 | Paint paint = new Paint(); 39 | paint.setAntiAlias(true); 40 | paint.setShader(new BitmapShader(toTransform, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 41 | canvas.drawRoundRect(new RectF(0, 0, width, height), radius, radius, paint); 42 | return bitmap; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object obj) { 47 | if (obj instanceof RadiusTransformation) { 48 | RadiusTransformation other = (RadiusTransformation) obj; 49 | return radius == other.radius; 50 | } 51 | return false; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Util.hashCode(ID.hashCode(), Util.hashCode(radius)); 57 | } 58 | 59 | @Override 60 | public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { 61 | messageDigest.update((ID + radius).getBytes(CHARSET)); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/util/BlurUtils.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.os.Build; 6 | import android.renderscript.Allocation; 7 | import android.renderscript.Element; 8 | import android.renderscript.RenderScript; 9 | import android.renderscript.ScriptIntrinsicBlur; 10 | import android.support.annotation.RequiresApi; 11 | 12 | /** 13 | * @author sunfusheng on 2018/6/25. 14 | */ 15 | public class BlurUtils { 16 | 17 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) 18 | public static Bitmap rsBlur(Context context, Bitmap toTransform, int radius) { 19 | RenderScript renderScript = RenderScript.create(context); 20 | Allocation input = Allocation.createFromBitmap(renderScript, toTransform); 21 | Allocation output = Allocation.createTyped(renderScript, input.getType()); 22 | ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript)); 23 | scriptIntrinsicBlur.setInput(input); 24 | scriptIntrinsicBlur.setRadius(radius); 25 | scriptIntrinsicBlur.forEach(output); 26 | output.copyTo(toTransform); 27 | renderScript.destroy(); 28 | return toTransform; 29 | } 30 | 31 | public static Bitmap blur(Bitmap toTransform, int radius) { 32 | if (radius < 1) { 33 | return (null); 34 | } 35 | 36 | int w = toTransform.getWidth(); 37 | int h = toTransform.getHeight(); 38 | 39 | int[] pix = new int[w * h]; 40 | toTransform.getPixels(pix, 0, w, 0, 0, w, h); 41 | 42 | int wm = w - 1; 43 | int hm = h - 1; 44 | int wh = w * h; 45 | int div = radius + radius + 1; 46 | 47 | int r[] = new int[wh]; 48 | int g[] = new int[wh]; 49 | int b[] = new int[wh]; 50 | int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; 51 | int vmin[] = new int[Math.max(w, h)]; 52 | 53 | int divsum = (div + 1) >> 1; 54 | divsum *= divsum; 55 | int dv[] = new int[256 * divsum]; 56 | for (i = 0; i < 256 * divsum; i++) { 57 | dv[i] = (i / divsum); 58 | } 59 | 60 | yw = yi = 0; 61 | 62 | int[][] stack = new int[div][3]; 63 | int stackpointer; 64 | int stackstart; 65 | int[] sir; 66 | int rbs; 67 | int r1 = radius + 1; 68 | int routsum, goutsum, boutsum; 69 | int rinsum, ginsum, binsum; 70 | 71 | for (y = 0; y < h; y++) { 72 | rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; 73 | for (i = -radius; i <= radius; i++) { 74 | p = pix[yi + Math.min(wm, Math.max(i, 0))]; 75 | sir = stack[i + radius]; 76 | sir[0] = (p & 0xff0000) >> 16; 77 | sir[1] = (p & 0x00ff00) >> 8; 78 | sir[2] = (p & 0x0000ff); 79 | rbs = r1 - Math.abs(i); 80 | rsum += sir[0] * rbs; 81 | gsum += sir[1] * rbs; 82 | bsum += sir[2] * rbs; 83 | if (i > 0) { 84 | rinsum += sir[0]; 85 | ginsum += sir[1]; 86 | binsum += sir[2]; 87 | } else { 88 | routsum += sir[0]; 89 | goutsum += sir[1]; 90 | boutsum += sir[2]; 91 | } 92 | } 93 | stackpointer = radius; 94 | 95 | for (x = 0; x < w; x++) { 96 | 97 | r[yi] = dv[rsum]; 98 | g[yi] = dv[gsum]; 99 | b[yi] = dv[bsum]; 100 | 101 | rsum -= routsum; 102 | gsum -= goutsum; 103 | bsum -= boutsum; 104 | 105 | stackstart = stackpointer - radius + div; 106 | sir = stack[stackstart % div]; 107 | 108 | routsum -= sir[0]; 109 | goutsum -= sir[1]; 110 | boutsum -= sir[2]; 111 | 112 | if (y == 0) { 113 | vmin[x] = Math.min(x + radius + 1, wm); 114 | } 115 | p = pix[yw + vmin[x]]; 116 | 117 | sir[0] = (p & 0xff0000) >> 16; 118 | sir[1] = (p & 0x00ff00) >> 8; 119 | sir[2] = (p & 0x0000ff); 120 | 121 | rinsum += sir[0]; 122 | ginsum += sir[1]; 123 | binsum += sir[2]; 124 | 125 | rsum += rinsum; 126 | gsum += ginsum; 127 | bsum += binsum; 128 | 129 | stackpointer = (stackpointer + 1) % div; 130 | sir = stack[(stackpointer) % div]; 131 | 132 | routsum += sir[0]; 133 | goutsum += sir[1]; 134 | boutsum += sir[2]; 135 | 136 | rinsum -= sir[0]; 137 | ginsum -= sir[1]; 138 | binsum -= sir[2]; 139 | 140 | yi++; 141 | } 142 | yw += w; 143 | } 144 | for (x = 0; x < w; x++) { 145 | rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; 146 | yp = -radius * w; 147 | for (i = -radius; i <= radius; i++) { 148 | yi = Math.max(0, yp) + x; 149 | 150 | sir = stack[i + radius]; 151 | 152 | sir[0] = r[yi]; 153 | sir[1] = g[yi]; 154 | sir[2] = b[yi]; 155 | 156 | rbs = r1 - Math.abs(i); 157 | 158 | rsum += r[yi] * rbs; 159 | gsum += g[yi] * rbs; 160 | bsum += b[yi] * rbs; 161 | 162 | if (i > 0) { 163 | rinsum += sir[0]; 164 | ginsum += sir[1]; 165 | binsum += sir[2]; 166 | } else { 167 | routsum += sir[0]; 168 | goutsum += sir[1]; 169 | boutsum += sir[2]; 170 | } 171 | 172 | if (i < hm) { 173 | yp += w; 174 | } 175 | } 176 | yi = x; 177 | stackpointer = radius; 178 | for (y = 0; y < h; y++) { 179 | pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; 180 | 181 | rsum -= routsum; 182 | gsum -= goutsum; 183 | bsum -= boutsum; 184 | 185 | stackstart = stackpointer - radius + div; 186 | sir = stack[stackstart % div]; 187 | 188 | routsum -= sir[0]; 189 | goutsum -= sir[1]; 190 | boutsum -= sir[2]; 191 | 192 | if (x == 0) { 193 | vmin[y] = Math.min(y + r1, hm) * w; 194 | } 195 | p = x + vmin[y]; 196 | 197 | sir[0] = r[p]; 198 | sir[1] = g[p]; 199 | sir[2] = b[p]; 200 | 201 | rinsum += sir[0]; 202 | ginsum += sir[1]; 203 | binsum += sir[2]; 204 | 205 | rsum += rinsum; 206 | gsum += ginsum; 207 | bsum += binsum; 208 | 209 | stackpointer = (stackpointer + 1) % div; 210 | sir = stack[stackpointer]; 211 | 212 | routsum += sir[0]; 213 | goutsum += sir[1]; 214 | boutsum += sir[2]; 215 | 216 | rinsum -= sir[0]; 217 | ginsum -= sir[1]; 218 | binsum -= sir[2]; 219 | 220 | yi += w; 221 | } 222 | } 223 | 224 | toTransform.setPixels(pix, 0, w, 0, 0, w, h); 225 | return toTransform; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/util/Utils.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.graphics.drawable.BitmapDrawable; 10 | import android.graphics.drawable.Drawable; 11 | import android.support.annotation.ColorRes; 12 | import android.text.TextUtils; 13 | import android.util.DisplayMetrics; 14 | import android.view.WindowManager; 15 | 16 | import java.util.Collection; 17 | 18 | public class Utils { 19 | 20 | private static WindowManager windowManager; 21 | 22 | private static WindowManager getWindowManager(Context context) { 23 | if (windowManager == null) { 24 | windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 25 | } 26 | return windowManager; 27 | } 28 | 29 | public static float getDensity(Context context) { 30 | return context.getResources().getDisplayMetrics().density; 31 | } 32 | 33 | public static float getFontDensity(Context context) { 34 | return context.getResources().getDisplayMetrics().scaledDensity; 35 | } 36 | 37 | public static DisplayMetrics getDisplayMetrics(Context context) { 38 | DisplayMetrics displayMetrics = new DisplayMetrics(); 39 | getWindowManager(context).getDefaultDisplay().getMetrics(displayMetrics); 40 | return displayMetrics; 41 | } 42 | 43 | public static int dp2px(Context context, float dp) { 44 | return (int) (getDensity(context) * dp + 0.5f); 45 | } 46 | 47 | public static int px2dp(Context context, float px) { 48 | return (int) (px / getDensity(context) + 0.5f); 49 | } 50 | 51 | public static int sp2px(Context context, float sp) { 52 | return (int) (getFontDensity(context) * sp + 0.5f); 53 | } 54 | 55 | public static int px2sp(Context context, float px) { 56 | return (int) (px / getFontDensity(context) + 0.5f); 57 | } 58 | 59 | public static int getWindowWidth(Context context) { 60 | return getDisplayMetrics(context).widthPixels; 61 | } 62 | 63 | public static int getWindowHeight(Context context) { 64 | return getDisplayMetrics(context).heightPixels; 65 | } 66 | 67 | public static String getPathFormat(String path) { 68 | if (!TextUtils.isEmpty(path)) { 69 | int lastPeriodIndex = path.lastIndexOf('.'); 70 | if (lastPeriodIndex > 0 && lastPeriodIndex + 1 < path.length()) { 71 | String format = path.substring(lastPeriodIndex + 1); 72 | if (!TextUtils.isEmpty(format)) { 73 | return format.toLowerCase(); 74 | } 75 | } 76 | } 77 | return ""; 78 | } 79 | 80 | public static boolean isGif(String url) { 81 | return "gif".equals(getPathFormat(url)); 82 | } 83 | 84 | public static Bitmap getTextBitmap(Context context, int width, int height, int radius, String text, int textSize, @ColorRes int bgColor) { 85 | radius = dp2px(context, radius); 86 | Bitmap bitmap = Bitmap.createBitmap(dp2px(context, width), dp2px(context, height), Bitmap.Config.ARGB_8888); 87 | Canvas canvas = new Canvas(bitmap); 88 | RectF rect = new RectF(0, 0, canvas.getWidth(), canvas.getHeight()); 89 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 90 | paint.setColor(context.getResources().getColor(bgColor)); 91 | canvas.drawRoundRect(new RectF(0, 0, rect.width(), rect.height()), radius, radius, paint); 92 | paint.setColor(Color.WHITE); 93 | paint.setTextSize(dp2px(context, textSize)); 94 | paint.setTextAlign(Paint.Align.CENTER); 95 | Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); 96 | float baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; 97 | canvas.drawText(text, rect.centerX(), baseline, paint); 98 | return bitmap; 99 | } 100 | 101 | public static Drawable getTextDrawable(Context context, int width, int height, int radius, String text, int textSize, @ColorRes int bgColor) { 102 | return new BitmapDrawable(getTextBitmap(context, width, height, radius, text, textSize, bgColor)); 103 | } 104 | 105 | public static boolean isEmpty(Collection collection) { 106 | return collection == null || collection.isEmpty(); 107 | } 108 | 109 | public static int getSize(Collection collection) { 110 | return collection == null ? 0 : collection.size(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/widget/GridLayoutHelper.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.widget; 2 | 3 | import android.graphics.Point; 4 | 5 | /** 6 | * @author sunfusheng on 2018/6/19. 7 | */ 8 | public class GridLayoutHelper implements LayoutHelper { 9 | private int spanCount; 10 | private int cellWidth; 11 | private int cellHeight; 12 | private int margin; 13 | 14 | public GridLayoutHelper(int spanCount, int cellWidth, int cellHeight, int margin) { 15 | this.spanCount = spanCount; 16 | this.cellWidth = cellWidth; 17 | this.cellHeight = cellHeight; 18 | this.margin = margin; 19 | } 20 | 21 | @Override 22 | public Point getCoordinate(int position) { 23 | Point point = new Point(); 24 | point.x = position % spanCount * (cellWidth + margin); 25 | point.y = position / spanCount * (cellHeight + margin); 26 | return point; 27 | } 28 | 29 | @Override 30 | public Point getSize(int position) { 31 | Point point = new Point(); 32 | point.x = cellWidth; 33 | point.y = cellHeight; 34 | return point; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/widget/ImageCell.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.BitmapDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.graphics.drawable.GradientDrawable; 10 | import android.support.annotation.ColorRes; 11 | import android.support.annotation.DrawableRes; 12 | import android.support.annotation.NonNull; 13 | import android.support.annotation.Nullable; 14 | import android.text.TextUtils; 15 | import android.util.AttributeSet; 16 | import android.widget.ImageView; 17 | 18 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 19 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; 20 | import com.bumptech.glide.load.resource.gif.GifDrawable; 21 | import com.bumptech.glide.request.target.DrawableImageViewTarget; 22 | import com.bumptech.glide.request.transition.Transition; 23 | import com.sunfusheng.glideimageview.R; 24 | import com.sunfusheng.progress.GlideApp; 25 | import com.sunfusheng.util.Utils; 26 | 27 | /** 28 | * @author sunfusheng on 2018/6/19. 29 | */ 30 | public class ImageCell extends ImageView { 31 | 32 | private static final float THUMBNAIL_RATIO = 0.1f; 33 | private ImageData imageData; 34 | private int radius; 35 | 36 | private static Drawable gifDrawable; 37 | private static Drawable longDrawable; 38 | private boolean isGif; 39 | private boolean loadGif; 40 | private int placeholderResId; 41 | private int errorResId; 42 | 43 | private boolean hasDrawCornerIcon; 44 | private Drawable cornerIconDrawable; 45 | private int cornerIconWidth; 46 | private int cornerIconHeight; 47 | private Rect cornerIconBounds; 48 | private int cornerIconMargin; 49 | 50 | private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 51 | private Paint.FontMetricsInt fontMetrics; 52 | 53 | public ImageCell(Context context) { 54 | this(context, null); 55 | } 56 | 57 | public ImageCell(Context context, AttributeSet attrs) { 58 | this(context, attrs, 0); 59 | } 60 | 61 | public ImageCell(Context context, AttributeSet attrs, int defStyleAttr) { 62 | super(context, attrs, defStyleAttr); 63 | init(); 64 | } 65 | 66 | private void init() { 67 | cornerIconBounds = new Rect(); 68 | cornerIconMargin = Utils.dp2px(getContext(), 3); 69 | textPaint.setTextAlign(Paint.Align.CENTER); 70 | } 71 | 72 | public void setData(ImageData imageData) { 73 | this.imageData = imageData; 74 | if (imageData != null) { 75 | load(imageData.url); 76 | } 77 | } 78 | 79 | public ImageCell setLoadGif(boolean loadGif) { 80 | this.loadGif = loadGif; 81 | return this; 82 | } 83 | 84 | public ImageCell setRadius(int radius) { 85 | this.radius = radius; 86 | return this; 87 | } 88 | 89 | public ImageCell placeholder(@DrawableRes int resId) { 90 | this.placeholderResId = resId; 91 | return this; 92 | } 93 | 94 | public ImageCell error(@DrawableRes int resId) { 95 | this.errorResId = resId; 96 | return this; 97 | } 98 | 99 | public void load(String url) { 100 | GlideApp.with(getContext()).load(url) 101 | .placeholder(placeholderResId) 102 | .error(errorResId) 103 | .fitCenter() 104 | .transition(new DrawableTransitionOptions().dontTransition()) 105 | .thumbnail(THUMBNAIL_RATIO) 106 | .diskCacheStrategy(DiskCacheStrategy.DATA) 107 | .into(new DrawableTarget(this) { 108 | @Override 109 | public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { 110 | Drawable drawable = resource; 111 | if (resource instanceof GifDrawable) { 112 | isGif = true; 113 | if (!loadGif) { 114 | drawable = new BitmapDrawable(((GifDrawable) resource).getFirstFrame()); 115 | } 116 | } else { 117 | isGif = false; 118 | } 119 | initCornerIcon(); 120 | super.onResourceReady(drawable, transition); 121 | } 122 | 123 | @Override 124 | public void onLoadFailed(@Nullable Drawable errorDrawable) { 125 | isGif = Utils.isGif(url); 126 | initCornerIcon(); 127 | super.onLoadFailed(errorDrawable); 128 | } 129 | }); 130 | } 131 | 132 | private void initCornerIcon() { 133 | if (isGif && !loadGif) { 134 | cornerIconDrawable = getGifDrawable(); 135 | } else if (isLongImage()) { 136 | cornerIconDrawable = getLongDrawable(); 137 | } else { 138 | cornerIconDrawable = null; 139 | } 140 | 141 | if (cornerIconDrawable != null) { 142 | cornerIconWidth = Utils.dp2px(getContext(), cornerIconDrawable.getIntrinsicWidth()); 143 | cornerIconHeight = Utils.dp2px(getContext(), cornerIconDrawable.getIntrinsicHeight()); 144 | if (!hasDrawCornerIcon) { 145 | postInvalidate(); 146 | } 147 | } 148 | } 149 | 150 | public boolean isGifImage() { 151 | return isGif; 152 | } 153 | 154 | public boolean isLongImage() { 155 | int realWidth = imageData != null ? imageData.realWidth : 0; 156 | int realHeight = imageData != null ? imageData.realHeight : 0; 157 | if (realWidth == 0 || realHeight == 0 || realWidth >= realHeight) { 158 | return false; 159 | } 160 | return (realHeight / realWidth) >= 4; 161 | } 162 | 163 | public Drawable getGifDrawable() { 164 | if (gifDrawable == null) { 165 | gifDrawable = Utils.getTextDrawable(getContext().getApplicationContext(), 24, 14, 2, "GIF", 11, R.color.nine_image_text_background_color); 166 | } 167 | return gifDrawable; 168 | } 169 | 170 | public Drawable getLongDrawable() { 171 | if (longDrawable == null) { 172 | longDrawable = Utils.getTextDrawable(getContext().getApplicationContext(), 25, 14, 2, "长图", 10, R.color.nine_image_text_background_color); 173 | } 174 | return longDrawable; 175 | } 176 | 177 | @Override 178 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 179 | super.onLayout(changed, l, t, r, b); 180 | if (cornerIconDrawable != null) { 181 | cornerIconBounds.set(r - l - cornerIconMargin - cornerIconWidth, 182 | b - t - cornerIconHeight - cornerIconMargin, 183 | r - l - cornerIconMargin, 184 | b - t - cornerIconMargin); 185 | } 186 | } 187 | 188 | @Override 189 | public void draw(Canvas canvas) { 190 | super.draw(canvas); 191 | if (cornerIconDrawable != null) { 192 | hasDrawCornerIcon = true; 193 | cornerIconDrawable.setBounds(cornerIconBounds); 194 | cornerIconDrawable.draw(canvas); 195 | } 196 | 197 | if (!TextUtils.isEmpty(imageData.text)) { 198 | canvas.drawColor(getResources().getColor(R.color.nine_image_text_background_color)); 199 | float textX = getWidth() / 2f; 200 | float textY = getHeight() / 2f + (fontMetrics.bottom - fontMetrics.top) / 2f - fontMetrics.bottom; 201 | canvas.drawText(imageData.text, textX, textY, textPaint); 202 | } 203 | } 204 | 205 | public ImageCell setText(String text) { 206 | if (imageData != null) { 207 | imageData.text = text; 208 | postInvalidate(); 209 | } 210 | return this; 211 | } 212 | 213 | public ImageCell setTextColor(@ColorRes int color) { 214 | textPaint.setColor(getResources().getColor(color)); 215 | return this; 216 | } 217 | 218 | public ImageCell setTextSize(int size) { 219 | textPaint.setTextSize(Utils.dp2px(getContext(), size)); 220 | fontMetrics = textPaint.getFontMetricsInt(); 221 | return this; 222 | } 223 | 224 | private class DrawableTarget extends DrawableImageViewTarget { 225 | DrawableTarget(ImageView view) { 226 | super(view); 227 | } 228 | 229 | private void setBackground() { 230 | if (radius == 0) { 231 | getView().setBackgroundResource(R.drawable.drawable_image_bg_0dp); 232 | } else if (radius == 5) { 233 | getView().setBackgroundResource(R.drawable.drawable_image_bg_5dp); 234 | } else { 235 | GradientDrawable drawable = (GradientDrawable) getResources().getDrawable(R.drawable.drawable_image_bg_0dp); 236 | drawable.setCornerRadius(radius); 237 | getView().setBackgroundDrawable(drawable); 238 | } 239 | } 240 | 241 | @Override 242 | public void onLoadStarted(Drawable placeholder) { 243 | setBackground(); 244 | getView().setScaleType(ImageView.ScaleType.FIT_CENTER); 245 | super.onLoadStarted(placeholder); 246 | } 247 | 248 | @Override 249 | public void onLoadFailed(@Nullable Drawable errorDrawable) { 250 | setBackground(); 251 | getView().setScaleType(ImageView.ScaleType.FIT_CENTER); 252 | super.onLoadFailed(errorDrawable); 253 | } 254 | 255 | @Override 256 | public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { 257 | getView().setBackgroundResource(0); 258 | getView().setScaleType(ImageView.ScaleType.CENTER_CROP); 259 | super.onResourceReady(resource, transition); 260 | } 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/widget/ImageData.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.widget; 2 | 3 | import android.graphics.Point; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author sunfusheng on 2018/6/19. 9 | */ 10 | public class ImageData implements Serializable { 11 | public String url; 12 | public String text; 13 | 14 | public int realWidth; 15 | public int realHeight; 16 | 17 | public int startX; 18 | public int startY; 19 | public int width; 20 | public int height; 21 | 22 | public ImageData(String url) { 23 | this.url = url; 24 | } 25 | 26 | public ImageData from(ImageData imageData, LayoutHelper layoutHelper, int position) { 27 | if (imageData != null && layoutHelper != null) { 28 | Point coordinate = layoutHelper.getCoordinate(position); 29 | if (coordinate != null) { 30 | imageData.startX = coordinate.x; 31 | imageData.startY = coordinate.y; 32 | } 33 | 34 | Point size = layoutHelper.getSize(position); 35 | if (size != null) { 36 | imageData.width = size.x; 37 | imageData.height = size.y; 38 | } 39 | } 40 | return imageData; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /glideimageview/src/main/java/com/sunfusheng/widget/LayoutHelper.java: -------------------------------------------------------------------------------- 1 | package com.sunfusheng.widget; 2 | 3 | import android.graphics.Point; 4 | 5 | /** 6 | * @author sunfusheng on 2018/6/19. 7 | */ 8 | public interface LayoutHelper { 9 | Point getCoordinate(int position); 10 | 11 | Point getSize(int position); 12 | } 13 | -------------------------------------------------------------------------------- /glideimageview/src/main/res/drawable/drawable_image_bg_0dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /glideimageview/src/main/res/drawable/drawable_image_bg_5dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /glideimageview/src/main/res/mipmap-hdpi/image_load_err.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/glideimageview/src/main/res/mipmap-hdpi/image_load_err.png -------------------------------------------------------------------------------- /glideimageview/src/main/res/mipmap-hdpi/image_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/glideimageview/src/main/res/mipmap-hdpi/image_loading.png -------------------------------------------------------------------------------- /glideimageview/src/main/res/mipmap-xhdpi/image_load_err.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/glideimageview/src/main/res/mipmap-xhdpi/image_load_err.png -------------------------------------------------------------------------------- /glideimageview/src/main/res/mipmap-xhdpi/image_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/glideimageview/src/main/res/mipmap-xhdpi/image_loading.png -------------------------------------------------------------------------------- /glideimageview/src/main/res/mipmap-xxhdpi/image_load_err.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/glideimageview/src/main/res/mipmap-xxhdpi/image_load_err.png -------------------------------------------------------------------------------- /glideimageview/src/main/res/mipmap-xxhdpi/image_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/glideimageview/src/main/res/mipmap-xxhdpi/image_loading.png -------------------------------------------------------------------------------- /glideimageview/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4D000000 4 | #FFFFFF 5 | 6 | 7 | -------------------------------------------------------------------------------- /glideimageview/src/main/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 08 11:31:11 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-5.4.1-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 | -------------------------------------------------------------------------------- /resources/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/cat.jpg -------------------------------------------------------------------------------- /resources/cat_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/cat_thumbnail.jpg -------------------------------------------------------------------------------- /resources/gif1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/gif1.gif -------------------------------------------------------------------------------- /resources/gif2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/gif2.gif -------------------------------------------------------------------------------- /resources/gif3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/gif3.gif -------------------------------------------------------------------------------- /resources/gif4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/gif4.gif -------------------------------------------------------------------------------- /resources/gif5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/gif5.gif -------------------------------------------------------------------------------- /resources/gif6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/gif6.gif -------------------------------------------------------------------------------- /resources/girl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/girl.jpg -------------------------------------------------------------------------------- /resources/girl_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/girl_thumbnail.jpg -------------------------------------------------------------------------------- /resources/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/image1.png -------------------------------------------------------------------------------- /resources/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/image2.png -------------------------------------------------------------------------------- /resources/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/image3.png -------------------------------------------------------------------------------- /resources/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/image4.png -------------------------------------------------------------------------------- /resources/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/resources/image5.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sample', ':glideimageview' 2 | -------------------------------------------------------------------------------- /signings/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/signings/keystore.jks -------------------------------------------------------------------------------- /signings/keystore.jks.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunfusheng/GlideImageView/138876da6a424b6c72de7a834e4dd059e854532c/signings/keystore.jks.enc -------------------------------------------------------------------------------- /signings/signing.properties: -------------------------------------------------------------------------------- 1 | KEYSTORE_FILEPATH=../signings/keystore.jks 2 | STORE_PASSWORD=sunfusheng 3 | KEY_ALIAS=sunfusheng 4 | KEY_PASSWORD=sunfusheng --------------------------------------------------------------------------------