├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── cat.jpg
│ │ │ │ ├── code1.png
│ │ │ │ ├── code2.png
│ │ │ │ ├── code3.png
│ │ │ │ ├── gif1.gif
│ │ │ │ ├── gif2.gif
│ │ │ │ ├── gif3.gif
│ │ │ │ ├── gif4.gif
│ │ │ │ ├── gif5.gif
│ │ │ │ ├── gif6.gif
│ │ │ │ ├── girl.jpg
│ │ │ │ ├── image1.png
│ │ │ │ ├── image2.png
│ │ │ │ ├── image3.png
│ │ │ │ ├── image4.png
│ │ │ │ ├── image5.png
│ │ │ │ ├── cat_thumbnail.jpg
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── girl_thumbnail.jpg
│ │ │ │ ├── cat_thumbnail_high.jpg
│ │ │ │ └── girl_thumbnail_high.jpg
│ │ │ ├── drawable
│ │ │ │ ├── gif_robot_walk.gif
│ │ │ │ └── progressbar_orange_selector.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── colors.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_recycle_view.xml
│ │ │ │ ├── activity_preview.xml
│ │ │ │ ├── item_photoview.xml
│ │ │ │ ├── item_recycle_view.xml
│ │ │ │ ├── activity_image.xml
│ │ │ │ └── activity_main.xml
│ │ │ └── values-w820dp
│ │ │ │ └── dimens.xml
│ │ ├── java
│ │ │ └── cy
│ │ │ │ └── wcdb
│ │ │ │ └── yyh
│ │ │ │ └── com
│ │ │ │ └── myglidefactoryview
│ │ │ │ ├── widget
│ │ │ │ ├── NineImageView
│ │ │ │ │ ├── ImageAttr.java
│ │ │ │ │ ├── NineImageViewAdapter.java
│ │ │ │ │ ├── ImageViewWrapper.java
│ │ │ │ │ └── NineImageView.java
│ │ │ │ ├── DraggableFrameLayout.java
│ │ │ │ └── SlideVerticallyLayout.java
│ │ │ │ ├── model
│ │ │ │ ├── ImageEntity.java
│ │ │ │ └── ModelUtil.java
│ │ │ │ ├── image
│ │ │ │ ├── FixedViewPager.java
│ │ │ │ ├── NineImageViewEventAdapter.java
│ │ │ │ ├── SingleImageActivity.java
│ │ │ │ ├── ImagesAdapter.java
│ │ │ │ └── ImagesActivity.java
│ │ │ │ ├── util
│ │ │ │ ├── ColorUtil.java
│ │ │ │ ├── AppUtil.java
│ │ │ │ └── StatusBarUtil.java
│ │ │ │ ├── BaseActivity.java
│ │ │ │ ├── RecycleViewActivity.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── cy
│ │ │ └── wcdb
│ │ │ └── yyh
│ │ │ └── com
│ │ │ └── myglidefactoryview
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── cy
│ │ └── wcdb
│ │ └── yyh
│ │ └── com
│ │ └── myglidefactoryview
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── GlideImageView
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── style.xml
│ │ ├── java
│ │ └── com
│ │ │ └── sunfusheng
│ │ │ └── glideimageview
│ │ │ ├── progress
│ │ │ ├── OnGlideImageViewListener.java
│ │ │ ├── OnProgressListener.java
│ │ │ ├── ProgressAppGlideModule.java
│ │ │ ├── ProgressResponseBody.java
│ │ │ ├── ProgressManager.java
│ │ │ └── CircleProgressView.java
│ │ │ ├── transformation
│ │ │ └── GlideCircleTransformation.java
│ │ │ ├── util
│ │ │ └── DisplayUtil.java
│ │ │ ├── GlideImageView.java
│ │ │ ├── GlideImageLoader.java
│ │ │ └── ShapeImageView.java
│ │ └── AndroidManifest.xml
├── build.gradle
└── proguard-rules.pro
├── settings.gradle
├── .idea
├── copyright
│ └── profiles_settings.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/GlideImageView/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':GlideImageView'
2 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/GlideImageView/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GlideImageView
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/cat.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/code1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/code1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/code2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/code2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/code3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/code3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/gif1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/gif1.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/gif2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/gif2.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/gif3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/gif3.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/gif4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/gif4.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/gif5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/gif5.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/gif6.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/gif6.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/girl.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/girl.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/image1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/image1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/image2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/image2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/image3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/image3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/image4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/image4.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/image5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/image5.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gif_robot_walk.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/drawable/gif_robot_walk.gif
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cat_thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/cat_thumbnail.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/girl_thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/girl_thumbnail.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cat_thumbnail_high.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/cat_thumbnail_high.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/girl_thumbnail_high.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeGoogler/MyGlideFactoryView/HEAD/app/src/main/res/mipmap-mdpi/girl_thumbnail_high.jpg
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | GlideImageView
4 | the image of transition
5 | %1$d/%2$d
6 |
7 |
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_recycle_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/progress/OnGlideImageViewListener.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.progress;
2 |
3 | import com.bumptech.glide.load.engine.GlideException;
4 |
5 | /**
6 | * Created by sunfusheng on 2017/6/14.
7 | */
8 | public interface OnGlideImageViewListener {
9 |
10 | void onProgress(int percent, boolean isDone, GlideException exception);
11 | }
12 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/progress/OnProgressListener.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.progress;
2 |
3 | import com.bumptech.glide.load.engine.GlideException;
4 |
5 | /**
6 | * Created by sunfusheng on 2017/6/14.
7 | */
8 | public interface OnProgressListener {
9 |
10 | void onProgress(String imageUrl, long bytesRead, long totalBytes, boolean isDone, GlideException exception);
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/test/java/cy/wcdb/yyh/com/myglidefactoryview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\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 |
--------------------------------------------------------------------------------
/app/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 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/widget/NineImageView/ImageAttr.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView;
2 |
3 | import java.io.Serializable;
4 |
5 | public class ImageAttr implements Serializable {
6 |
7 | public String url;
8 | public String thumbnailUrl;
9 |
10 | // 显示的宽高
11 | public int width;
12 | public int height;
13 |
14 | // 左上角坐标
15 | public int left;
16 | public int top;
17 |
18 | @Override
19 | public String toString() {
20 | return "ImageAttr{" +
21 | "url='" + url + '\'' +
22 | ", width=" + width +
23 | ", height=" + height +
24 | ", left=" + left +
25 | ", top=" + top +
26 | '}';
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/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
18 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/progress/ProgressAppGlideModule.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.progress;
2 |
3 | import android.content.Context;
4 |
5 | import com.bumptech.glide.Registry;
6 | import com.bumptech.glide.annotation.GlideModule;
7 | import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
8 | import com.bumptech.glide.load.model.GlideUrl;
9 | import com.bumptech.glide.module.AppGlideModule;
10 |
11 | import java.io.InputStream;
12 |
13 | /**
14 | * Created by sunfusheng on 2017/6/14.
15 | */
16 | @GlideModule
17 | public class ProgressAppGlideModule extends AppGlideModule {
18 |
19 | @Override
20 | public void registerComponents(Context context, Registry registry) {
21 | registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(ProgressManager.getOkHttpClient()));
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/model/ImageEntity.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 |
6 | /**
7 | * Created by sunfusheng on 2017/6/27.
8 | */
9 | public class ImageEntity implements Serializable {
10 |
11 | private String title;
12 | private ArrayList images;
13 |
14 | public ImageEntity(String title, ArrayList images) {
15 | this.title = title;
16 | this.images = images;
17 | }
18 |
19 | public String getTitle() {
20 | return title;
21 | }
22 |
23 | public void setTitle(String title) {
24 | this.title = title;
25 | }
26 |
27 | public ArrayList getImages() {
28 | return images;
29 | }
30 |
31 | public void setImages(ArrayList images) {
32 | this.images = images;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/cy/wcdb/yyh/com/myglidefactoryview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("cy.wcdb.yyh.com.myglidefactoryview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/GlideImageView/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release'
3 |
4 | android {
5 | compileSdkVersion 25
6 | buildToolsVersion "25.0.3"
7 |
8 | defaultConfig {
9 | minSdkVersion 19
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0.0"
13 | }
14 |
15 | lintOptions {
16 | abortOnError false
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | compile fileTree(dir: 'libs', include: ['*.jar'])
29 | compile 'com.android.support:support-v4:25.3.1'
30 | compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
31 | compile 'com.github.bumptech.glide:compiler:4.0.0-RC0'
32 | compile "com.github.bumptech.glide:okhttp3-integration:4.0.0-RC0"
33 | }
34 |
--------------------------------------------------------------------------------
/app/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_photoview.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/image/FixedViewPager.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/widget/NineImageView/NineImageViewAdapter.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView;
2 |
3 | import android.content.Context;
4 | import android.widget.ImageView;
5 |
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 | public abstract class NineImageViewAdapter implements Serializable {
10 |
11 | protected Context context;
12 | private List imageAttrs;
13 |
14 | public NineImageViewAdapter(Context context, List images) {
15 | this.context = context;
16 | this.imageAttrs = images;
17 | }
18 |
19 | protected void onImageItemClick(Context context, NineImageView nineImageView, int index, List images) {
20 | }
21 |
22 | protected ImageView generateImageView(Context context) {
23 | ImageViewWrapper imageView = new ImageViewWrapper(context);
24 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
25 | return imageView;
26 | }
27 |
28 | public List getImageAttrs() {
29 | return imageAttrs;
30 | }
31 |
32 | public void setImageAttrs(List images) {
33 | this.imageAttrs = images;
34 | }
35 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 | defaultConfig {
7 | applicationId "cy.wcdb.yyh.com.myglidefactoryview"
8 | minSdkVersion 19
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.3.1'
28 | compile 'com.android.support:percent:25.3.1'
29 | compile 'com.android.support:design:25.3.1'
30 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
31 | compile 'com.github.chrisbanes:PhotoView:2.0.0'
32 | testCompile 'junit:junit:4.12'
33 | compile project(':GlideImageView')
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_recycle_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
22 |
23 |
28 |
29 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/util/ColorUtil.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/transformation/GlideCircleTransformation.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.transformation;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapShader;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 |
8 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
9 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
10 |
11 | import java.security.MessageDigest;
12 |
13 | /**
14 | * Created by sunfusheng on 2017/6/6.
15 | */
16 | public class GlideCircleTransformation extends BitmapTransformation {
17 |
18 | public GlideCircleTransformation() {
19 | }
20 |
21 | @Override
22 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
23 | return circleCrop(pool, toTransform);
24 | }
25 |
26 | private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
27 | if (source == null) return null;
28 |
29 | int size = Math.min(source.getWidth(), source.getHeight());
30 | int x = (source.getWidth() - size) / 2;
31 | int y = (source.getHeight() - size) / 2;
32 |
33 | Bitmap square = Bitmap.createBitmap(source, x, y, size, size);
34 | Bitmap circle = pool.get(size, size, Bitmap.Config.ARGB_8888);
35 |
36 | Canvas canvas = new Canvas(circle);
37 | Paint paint = new Paint();
38 | paint.setShader(new BitmapShader(square, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
39 | paint.setAntiAlias(true);
40 | float r = size / 2f;
41 | canvas.drawCircle(r, r, r, paint);
42 | return circle;
43 | }
44 |
45 | @Override
46 | public void updateDiskCacheKey(MessageDigest messageDigest) {
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
18 |
19 |
28 |
29 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/image/NineImageViewEventAdapter.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.image;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.view.View;
8 |
9 |
10 | import java.io.Serializable;
11 | import java.util.List;
12 |
13 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.ImageAttr;
14 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.NineImageView;
15 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.NineImageViewAdapter;
16 |
17 |
18 | public class NineImageViewEventAdapter extends NineImageViewAdapter {
19 |
20 | public NineImageViewEventAdapter(Context context, List imageAttr) {
21 | super(context, imageAttr);
22 | }
23 |
24 | @Override
25 | protected void onImageItemClick(Context context, NineImageView nineImageView, int index, List images) {
26 | for (int i = 0; i < images.size(); i++) {
27 | ImageAttr attr = images.get(i);
28 | View imageView = nineImageView.getChildAt(i);
29 | if (i >= nineImageView.getMaxSize()) {
30 | imageView = nineImageView.getChildAt(nineImageView.getMaxSize() - 1);
31 | }
32 | attr.width = imageView.getWidth();
33 | attr.height = imageView.getHeight();
34 | int[] points = new int[2];
35 | imageView.getLocationInWindow(points);
36 | attr.left = points[0];
37 | attr.top = points[1];
38 | }
39 |
40 | Intent intent = new Intent(context, ImagesActivity.class);
41 | Bundle bundle = new Bundle();
42 | bundle.putSerializable(ImagesActivity.IMAGE_ATTR, (Serializable) images);
43 | bundle.putInt(ImagesActivity.CUR_POSITION, index);
44 | intent.putExtras(bundle);
45 | context.startActivity(intent);
46 | ((Activity) context).overridePendingTransition(0, 0);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/progress/ProgressResponseBody.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.progress;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import java.io.IOException;
6 |
7 | import okhttp3.MediaType;
8 | import okhttp3.ResponseBody;
9 | import okio.Buffer;
10 | import okio.BufferedSource;
11 | import okio.ForwardingSource;
12 | import okio.Okio;
13 | import okio.Source;
14 |
15 | /**
16 | * Created by sunfusheng on 2017/6/14.
17 | */
18 | public class ProgressResponseBody extends ResponseBody {
19 |
20 | private String imageUrl;
21 | private ResponseBody responseBody;
22 | private OnProgressListener progressListener;
23 | private BufferedSource bufferedSource;
24 |
25 | public ProgressResponseBody(String url, ResponseBody responseBody, OnProgressListener progressListener) {
26 | this.imageUrl = url;
27 | this.responseBody = responseBody;
28 | this.progressListener = progressListener;
29 | }
30 |
31 | @Override
32 | public MediaType contentType() {
33 | return responseBody.contentType();
34 | }
35 |
36 | @Override
37 | public long contentLength() {
38 | return responseBody.contentLength();
39 | }
40 |
41 | @Override
42 | public BufferedSource source() {
43 | if (bufferedSource == null) {
44 | bufferedSource = Okio.buffer(source(responseBody.source()));
45 | }
46 | return bufferedSource;
47 | }
48 |
49 | private Source source(Source source) {
50 | return new ForwardingSource(source) {
51 | long totalBytesRead = 0;
52 |
53 | @Override
54 | public long read(@NonNull Buffer sink, long byteCount) throws IOException {
55 | long bytesRead = super.read(sink, byteCount);
56 | totalBytesRead += (bytesRead == -1) ? 0 : bytesRead;
57 |
58 | if (progressListener != null) {
59 | progressListener.onProgress(imageUrl, totalBytesRead, contentLength(), (bytesRead == -1), null);
60 | }
61 | return bytesRead;
62 | }
63 | };
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/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 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview;
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 |
9 | import cy.wcdb.yyh.com.myglidefactoryview.util.StatusBarUtil;
10 |
11 |
12 | /**
13 | * Created by sunfusheng on 2016/12/24.
14 | */
15 | public abstract class BaseActivity extends Activity {
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #00796b
5 | #00796b
6 | #00796b
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 | #1A000000
49 |
50 | #FFFFFF
51 | #fbc02d
52 | #FFD700
53 | #f57c00
54 | #d01716
55 | #808080
56 | #0a7e07
57 | #455ede
58 | #000000
59 |
60 |
61 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/util/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.util;
2 |
3 | import android.content.Context;
4 | import android.util.DisplayMetrics;
5 | import android.view.WindowManager;
6 |
7 | public class DisplayUtil {
8 |
9 | private static WindowManager windowManager;
10 |
11 | private static WindowManager getWindowManager(Context context) {
12 | if (windowManager == null) {
13 | windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
14 | }
15 | return windowManager;
16 | }
17 |
18 | // 根据手机的分辨率将dp的单位转成px(像素)
19 | public static int dip2px(Context context, float dpValue) {
20 | final float scale = context.getResources().getDisplayMetrics().density;
21 | return (int) (dpValue * scale + 0.5f);
22 | }
23 |
24 | // 根据手机的分辨率将px(像素)的单位转成dp
25 | public static int px2dip(Context context, float pxValue) {
26 | final float scale = context.getResources().getDisplayMetrics().density;
27 | return (int) (pxValue / scale + 0.5f);
28 | }
29 |
30 | // 将px值转换为sp值
31 | public static int px2sp(Context context, float pxValue) {
32 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
33 | return (int) (pxValue / fontScale + 0.5f);
34 | }
35 |
36 | // 将sp值转换为px值
37 | public static int sp2px(Context context, float spValue) {
38 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
39 | return (int) (spValue * fontScale + 0.5f);
40 | }
41 |
42 | // 屏幕宽度(像素)
43 | public static int getScreenWidth(Context context) {
44 | DisplayMetrics metric = new DisplayMetrics();
45 | getWindowManager(context).getDefaultDisplay().getMetrics(metric);
46 | return metric.widthPixels;
47 | }
48 |
49 | // 屏幕高度(像素)
50 | public static int getScreenHeight(Context context) {
51 | DisplayMetrics metric = new DisplayMetrics();
52 | getWindowManager(context).getDefaultDisplay().getMetrics(metric);
53 | return metric.heightPixels;
54 | }
55 |
56 | public static float getScreenDensity(Context context) {
57 | try {
58 | DisplayMetrics displayMetrics = new DisplayMetrics();
59 | getWindowManager(context).getDefaultDisplay().getMetrics(displayMetrics);
60 | return displayMetrics.density;
61 | } catch (Throwable e) {
62 | e.printStackTrace();
63 | return 1.0f;
64 | }
65 | }
66 |
67 | public static int getDensityDpi(Context context) {
68 | try {
69 | DisplayMetrics displayMetrics = new DisplayMetrics();
70 | getWindowManager(context).getDefaultDisplay().getMetrics(displayMetrics);
71 | return displayMetrics.densityDpi;
72 | } catch (Throwable e) {
73 | e.printStackTrace();
74 | return 320;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/util/AppUtil.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/RecycleViewActivity.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.TextView;
10 |
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import cy.wcdb.yyh.com.myglidefactoryview.image.NineImageViewEventAdapter;
16 | import cy.wcdb.yyh.com.myglidefactoryview.model.ImageEntity;
17 | import cy.wcdb.yyh.com.myglidefactoryview.model.ModelUtil;
18 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.ImageAttr;
19 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.NineImageView;
20 |
21 | public class RecycleViewActivity extends BaseActivity {
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_recycle_view);
27 |
28 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycleView);
29 | LinearLayoutManager layoutManager = new LinearLayoutManager(this);
30 | recyclerView.setLayoutManager(layoutManager);
31 | RecyclerViewAdapter adapter = new RecyclerViewAdapter(ModelUtil.getImages());
32 | recyclerView.setAdapter(adapter);
33 | }
34 |
35 | class RecyclerViewAdapter extends RecyclerView.Adapter {
36 |
37 | private List list;
38 |
39 | RecyclerViewAdapter(List list) {
40 | this.list = list;
41 | }
42 |
43 | @Override
44 | public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
45 | View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_recycle_view, viewGroup, false);
46 | return new ViewHolder(view);
47 | }
48 |
49 | @Override
50 | public void onBindViewHolder(ViewHolder viewHolder, int position) {
51 | ImageEntity entity = list.get(position);
52 |
53 | viewHolder.tvTitle.setText(entity.getTitle());
54 |
55 | ArrayList imageAttrs = new ArrayList<>();
56 | for (String url : entity.getImages()) {
57 | ImageAttr attr = new ImageAttr();
58 | attr.url = url;
59 | imageAttrs.add(attr);
60 | }
61 | if (viewHolder.nineImageView.getAdapter() != null) {
62 | viewHolder.nineImageView.setAdapter(viewHolder.nineImageView.getAdapter());
63 | } else {
64 | viewHolder.nineImageView.setAdapter(new NineImageViewEventAdapter(viewHolder.nineImageView.getContext(), imageAttrs));
65 | }
66 | }
67 |
68 | @Override
69 | public int getItemCount() {
70 | return list.size();
71 | }
72 |
73 | class ViewHolder extends RecyclerView.ViewHolder {
74 | TextView tvTitle;
75 | NineImageView nineImageView;
76 |
77 | ViewHolder(View view) {
78 | super(view);
79 | tvTitle = (TextView) view.findViewById(R.id.tv_title);
80 | nineImageView = (NineImageView) view.findViewById(R.id.nineImageView);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
26 |
34 |
35 |
47 |
48 |
62 |
63 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/model/ModelUtil.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Created by sunfusheng on 2017/6/27.
8 | */
9 | public class ModelUtil {
10 |
11 | public static List getImages() {
12 | List list = new ArrayList<>();
13 |
14 | ArrayList images = new ArrayList<>();
15 | images.add("http://pic.58pic.com/58pic/13/62/02/07d58PICcxz_1024.jpg");
16 | list.add(new ImageEntity("画卷:天道酬勤", images));
17 |
18 | images = new ArrayList<>();
19 | images.add("http://img.pconline.com.cn/images/photo2/591572/1100105945280.jpg");
20 | images.add("http://www.pop-photo.com.cn/data/attachment/forum/myspace/image/2011/07/0/46/76/467693_233590968.jpg");
21 | images.add("http://www.52design.com/pic/20121/201211313245374.jpg");
22 | list.add(new ImageEntity("微距离摄影", images));
23 |
24 | images = new ArrayList<>();
25 | images.add("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");
26 | list.add(new ImageEntity("又一个小猫咪(450X798)", images));
27 |
28 | images = new ArrayList<>();
29 | images.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1498628972675&di=329747bae23548dfd988fbc6dcaf76b7&imgtype=0&src=http%3A%2F%2Fwww.17sucai.com%2Fupload%2F534358%2F2016-06-13%2Facdf7f6e040aee07147f9e3508833c8a_big.jpg");
30 | list.add(new ImageEntity("一个小猫咪(650X406)", images));
31 |
32 | images = new ArrayList<>();
33 | images.add("http://img15.3lian.com/2015/h1/308/d/199.jpg");
34 | images.add("http://pic1.win4000.com/wallpaper/f/566a714a786cc.jpg");
35 | images.add("http://img15.3lian.com/2015/h1/308/d/204.jpg");
36 | images.add("http://imglf1.ph.126.net/DIe00tFQ1SZOdKUDG8AO1g==/2068278128970036688.jpg");
37 | list.add(new ImageEntity("世界著名建筑", images));
38 |
39 | images = new ArrayList<>();
40 | images.add("http://wx4.sinaimg.cn/mw690/e59bcb0dly1fgqlue0vtvj20c83htx3d.jpg");
41 | list.add(new ImageEntity("开发者头条的截图(440X4529)", images));
42 |
43 | images = new ArrayList<>();
44 | images.add("http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg");
45 | images.add("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg");
46 | images.add("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg");
47 | images.add("http://img5.imgtn.bdimg.com/it/u=1467751238,3257336851&fm=11&gp=0.jpg");
48 | images.add("http://img5.imgtn.bdimg.com/it/u=3191365283,111438732&fm=21&gp=0.jpg");
49 | images.add("http://img5.imgtn.bdimg.com/it/u=482494496,1350922497&fm=206&gp=0.jpg");
50 | images.add("http://img4.imgtn.bdimg.com/it/u=2440866214,1867472386&fm=21&gp=0.jpg");
51 | images.add("http://img3.imgtn.bdimg.com/it/u=3040385967,1031044866&fm=21&gp=0.jpg");
52 | images.add("http://img1.imgtn.bdimg.com/it/u=1832737924,144748431&fm=21&gp=0.jpg");
53 | images.add("http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg");
54 | images.add("http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg");
55 | images.add("http://img5.imgtn.bdimg.com/it/u=1424970962,1243597989&fm=21&gp=0.jpg");
56 | list.add(new ImageEntity("一共12张图片", images));
57 |
58 | return list;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/progress/ProgressManager.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.progress;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.bumptech.glide.load.engine.GlideException;
6 |
7 | import java.io.IOException;
8 | import java.lang.ref.WeakReference;
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | import okhttp3.Interceptor;
14 | import okhttp3.OkHttpClient;
15 | import okhttp3.Request;
16 | import okhttp3.Response;
17 |
18 | /**
19 | * Created by sunfusheng on 2017/6/14.
20 | */
21 | public class ProgressManager {
22 |
23 | private static List> listeners = Collections.synchronizedList(new ArrayList>());
24 | private static OkHttpClient okHttpClient;
25 |
26 | private ProgressManager() {
27 | }
28 |
29 | public static OkHttpClient getOkHttpClient() {
30 | if (okHttpClient == null) {
31 | okHttpClient = new OkHttpClient.Builder()
32 | .addNetworkInterceptor(new Interceptor() {
33 | @Override
34 | public Response intercept(@NonNull Chain chain) throws IOException {
35 | Request request = chain.request();
36 | Response response = chain.proceed(request);
37 | return response.newBuilder()
38 | .body(new ProgressResponseBody(request.url().toString(), response.body(), LISTENER))
39 | .build();
40 | }
41 | })
42 | .build();
43 | }
44 | return okHttpClient;
45 | }
46 |
47 | private static final OnProgressListener LISTENER = new OnProgressListener() {
48 | @Override
49 | public void onProgress(String imageUrl, long bytesRead, long totalBytes, boolean isDone, GlideException exception) {
50 | if (listeners == null || listeners.size() == 0) return;
51 |
52 | for (int i = 0; i < listeners.size(); i++) {
53 | WeakReference listener = listeners.get(i);
54 | OnProgressListener progressListener = listener.get();
55 | if (progressListener == null) {
56 | listeners.remove(i);
57 | } else {
58 | progressListener.onProgress(imageUrl, bytesRead, totalBytes, isDone, exception);
59 | }
60 | }
61 | }
62 | };
63 |
64 | public static void addProgressListener(OnProgressListener progressListener) {
65 | if (progressListener == null) return;
66 |
67 | if (findProgressListener(progressListener) == null) {
68 | listeners.add(new WeakReference<>(progressListener));
69 | }
70 | }
71 |
72 | public static void removeProgressListener(OnProgressListener progressListener) {
73 | if (progressListener == null) return;
74 |
75 | WeakReference listener = findProgressListener(progressListener);
76 | if (listener != null) {
77 | listeners.remove(listener);
78 | }
79 | }
80 |
81 | private static WeakReference findProgressListener(OnProgressListener listener) {
82 | if (listener == null) return null;
83 | if (listeners == null || listeners.size() == 0) return null;
84 |
85 | for (int i = 0; i < listeners.size(); i++) {
86 | WeakReference progressListener = listeners.get(i);
87 | if (progressListener.get() == listener) {
88 | return progressListener;
89 | }
90 | }
91 | return null;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/util/StatusBarUtil.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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 extends Window> 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 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/GlideImageView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.support.annotation.DrawableRes;
6 | import android.util.AttributeSet;
7 |
8 | import com.bumptech.glide.request.RequestOptions;
9 | import com.sunfusheng.glideimageview.progress.OnGlideImageViewListener;
10 | import com.sunfusheng.glideimageview.progress.OnProgressListener;
11 |
12 | /**
13 | * Created by sunfusheng on 2017/6/6.
14 | */
15 | public class GlideImageView extends ShapeImageView {
16 |
17 | private GlideImageLoader mImageLoader;
18 |
19 | public GlideImageView(Context context) {
20 | this(context, null);
21 | }
22 |
23 | public GlideImageView(Context context, AttributeSet attrs) {
24 | this(context, attrs, 0);
25 | }
26 |
27 | public GlideImageView(Context context, AttributeSet attrs, int defStyleAttr) {
28 | super(context, attrs, defStyleAttr);
29 | init();
30 | }
31 |
32 | private void init() {
33 | mImageLoader = GlideImageLoader.create(this);
34 | }
35 |
36 | public GlideImageLoader getImageLoader() {
37 | if (mImageLoader == null) {
38 | mImageLoader = GlideImageLoader.create(this);
39 | }
40 | return mImageLoader;
41 | }
42 |
43 | public String getImageUrl() {
44 | return getImageLoader().getImageUrl();
45 | }
46 |
47 | public RequestOptions requestOptions(int placeholderResId) {
48 | return getImageLoader().requestOptions(placeholderResId);
49 | }
50 |
51 | public RequestOptions circleRequestOptions(int placeholderResId) {
52 | return getImageLoader().circleRequestOptions(placeholderResId);
53 | }
54 |
55 | public GlideImageView load(int resId, RequestOptions options) {
56 | getImageLoader().load(resId, options);
57 | return this;
58 | }
59 |
60 | public GlideImageView load(Uri uri, RequestOptions options) {
61 | getImageLoader().load(uri, options);
62 | return this;
63 | }
64 |
65 | public GlideImageView load(String url, RequestOptions options) {
66 | getImageLoader().load(url, options);
67 | return this;
68 | }
69 |
70 | public GlideImageView loadImage(String url, int placeholderResId) {
71 | getImageLoader().loadImage(url, placeholderResId);
72 | return this;
73 | }
74 |
75 | public GlideImageView loadLocalImage(@DrawableRes int resId, int placeholderResId) {
76 | getImageLoader().loadLocalImage(resId, placeholderResId);
77 | return this;
78 | }
79 |
80 | public GlideImageView loadLocalImage(String localPath, int placeholderResId) {
81 | getImageLoader().loadLocalImage(localPath, placeholderResId);
82 | return this;
83 | }
84 |
85 | public GlideImageView loadCircleImage(String url, int placeholderResId) {
86 | setShapeType(ShapeType.CIRCLE);
87 | getImageLoader().loadCircleImage(url, placeholderResId);
88 | return this;
89 | }
90 |
91 | public GlideImageView loadLocalCircleImage(int resId, int placeholderResId) {
92 | setShapeType(ShapeType.CIRCLE);
93 | getImageLoader().loadLocalCircleImage(resId, placeholderResId);
94 | return this;
95 | }
96 |
97 | public GlideImageView loadLocalCircleImage(String localPath, int placeholderResId) {
98 | setShapeType(ShapeType.CIRCLE);
99 | getImageLoader().loadLocalCircleImage(localPath, placeholderResId);
100 | return this;
101 | }
102 |
103 | public GlideImageView listener(OnGlideImageViewListener listener) {
104 | getImageLoader().setOnGlideImageViewListener(getImageUrl(), listener);
105 | return this;
106 | }
107 |
108 | public GlideImageView listener(OnProgressListener listener) {
109 | getImageLoader().setOnProgressListener(getImageUrl(), listener);
110 | return this;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/widget/DraggableFrameLayout.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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.glideimageview.util.DisplayUtil;
15 |
16 | /**
17 | * Created 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, @AttrRes int defStyleAttr) {
34 | super(context, attrs, defStyleAttr);
35 | init();
36 | }
37 |
38 | private void init() {
39 | screenWidth = DisplayUtil.getScreenWidth(getContext());
40 | margin = DisplayUtil.dip2px(getContext(), margin);
41 |
42 | dragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
43 |
44 | @Override
45 | public boolean tryCaptureView(View child, int pointerId) {
46 | return true;
47 | }
48 |
49 | @Override
50 | public void onViewCaptured(View capturedChild, int activePointerId) {
51 | super.onViewCaptured(capturedChild, activePointerId);
52 | }
53 |
54 | @Override
55 | public int clampViewPositionHorizontal(View child, int left, int dx) {
56 | return left;
57 | }
58 |
59 | @Override
60 | public int clampViewPositionVertical(View child, int top, int dy) {
61 | return top;
62 | }
63 |
64 | @Override
65 | public int getViewHorizontalDragRange(View child) {
66 | return getMeasuredWidth() - child.getMeasuredWidth();
67 | }
68 |
69 | @Override
70 | public int getViewVerticalDragRange(View child) {
71 | return getMeasuredHeight() - child.getMeasuredHeight();
72 | }
73 |
74 | @Override
75 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
76 | super.onViewReleased(releasedChild, xvel, yvel);
77 | int viewWidth = releasedChild.getWidth();
78 | int viewHeight = releasedChild.getHeight();
79 | int curLeft = releasedChild.getLeft();
80 | int curTop = releasedChild.getTop();
81 |
82 | int finalLeft = margin;
83 | int finalTop = curTop < margin ? margin : curTop;
84 |
85 | if ((curLeft + viewWidth / 2) > screenWidth / 2) {
86 | finalLeft = screenWidth - viewWidth - margin;
87 | }
88 |
89 | if ((finalTop + viewHeight) > getHeight()) {
90 | finalTop = getHeight() - viewHeight - margin;
91 | }
92 |
93 | dragHelper.settleCapturedViewAt(finalLeft, finalTop);
94 | invalidate();
95 | }
96 | });
97 | }
98 |
99 | @Override
100 | public boolean onInterceptTouchEvent(MotionEvent ev) {
101 | return dragHelper.shouldInterceptTouchEvent(ev);
102 | }
103 |
104 | @Override
105 | public boolean onTouchEvent(MotionEvent event) {
106 | dragHelper.processTouchEvent(event);
107 | return isTouchChildView(event);
108 | }
109 |
110 | @Override
111 | public void computeScroll() {
112 | super.computeScroll();
113 | if (dragHelper.continueSettling(true)) {
114 | invalidate();
115 | }
116 | }
117 |
118 | private boolean isTouchChildView(MotionEvent ev) {
119 | Rect rect = new Rect();
120 | for (int i = 0; i < getChildCount(); i++) {
121 | View view = getChildAt(i);
122 | rect.set((int) view.getX(), (int) view.getY(), (int) view.getX() + view.getWidth(), (int) view.getY() + view.getHeight());
123 | if (rect.contains((int) ev.getX(), (int) ev.getY())) {
124 | return true;
125 | }
126 | }
127 | return false;
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/widget/NineImageView/ImageViewWrapper.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.PorterDuff;
8 | import android.graphics.drawable.Drawable;
9 | import android.support.v4.view.ViewCompat;
10 | import android.text.TextPaint;
11 | import android.util.AttributeSet;
12 | import android.util.TypedValue;
13 | import android.view.MotionEvent;
14 | import android.widget.ImageView;
15 |
16 | public class ImageViewWrapper extends ImageView {
17 |
18 | private int moreNum = 0; //显示更多的数量
19 | private int maskColor = 0x88000000; //默认的遮盖颜色
20 | private float textSize = 30; //显示文字的大小单位sp
21 | private int textColor = 0xFFFFFFFF; //显示文字的颜色
22 |
23 | private TextPaint textPaint; //文字的画笔
24 | private String msg = ""; //要绘制的文字
25 |
26 | public ImageViewWrapper(Context context) {
27 | this(context, null);
28 | }
29 |
30 | public ImageViewWrapper(Context context, AttributeSet attrs) {
31 | this(context, attrs, 0);
32 | }
33 |
34 | public ImageViewWrapper(Context context, AttributeSet attrs, int defStyleAttr) {
35 | super(context, attrs, defStyleAttr);
36 |
37 | //转化单位
38 | textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, getContext().getResources().getDisplayMetrics());
39 |
40 | textPaint = new TextPaint();
41 | textPaint.setTextAlign(Paint.Align.CENTER); //文字居中对齐
42 | textPaint.setAntiAlias(true); //抗锯齿
43 | textPaint.setTextSize(textSize); //设置文字大小
44 | textPaint.setColor(textColor); //设置文字颜色
45 | }
46 |
47 | @Override
48 | protected void onDraw(Canvas canvas) {
49 | super.onDraw(canvas);
50 | if (moreNum > 0) {
51 | canvas.drawColor(maskColor);
52 | float baseY = getHeight() / 2 - (textPaint.ascent() + textPaint.descent()) / 2;
53 | canvas.drawText(msg, getWidth() / 2, baseY, textPaint);
54 | }
55 | }
56 |
57 | @Override
58 | public boolean onTouchEvent(MotionEvent event) {
59 | switch (event.getAction()) {
60 | case MotionEvent.ACTION_DOWN:
61 | Drawable drawable = getDrawable();
62 | if (drawable != null) {
63 | /**
64 | * 默认情况下,所有的从同一资源(R.drawable.XXX)加载来的drawable实例都共享一个共用的状态,
65 | * 如果你更改一个实例的状态,其他所有的实例都会收到相同的通知。
66 | * 使用使 mutate 可以让这个drawable变得状态不定。这个操作不能还原(变为不定后就不能变为原来的状态)。
67 | * 一个状态不定的drawable可以保证它不与其他任何一个drawabe共享它的状态。
68 | * 此处应该是要使用的 mutate(),但是在部分手机上会出现点击后变白的现象,所以没有使用
69 | * 目前这种解决方案没有问题
70 | */
71 | drawable.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
72 | ViewCompat.postInvalidateOnAnimation(this);
73 | }
74 | break;
75 | case MotionEvent.ACTION_MOVE:
76 | break;
77 | case MotionEvent.ACTION_CANCEL:
78 | case MotionEvent.ACTION_UP:
79 | Drawable drawableUp = getDrawable();
80 | if (drawableUp != null) {
81 | drawableUp.clearColorFilter();
82 | ViewCompat.postInvalidateOnAnimation(this);
83 | }
84 | break;
85 | }
86 | return super.onTouchEvent(event);
87 | }
88 |
89 | @Override
90 | protected void onDetachedFromWindow() {
91 | super.onDetachedFromWindow();
92 | setImageDrawable(null);
93 | }
94 |
95 | public int getMoreNum() {
96 | return moreNum;
97 | }
98 |
99 | public void setMoreNum(int moreNum) {
100 | this.moreNum = moreNum;
101 | msg = "+" + moreNum;
102 | invalidate();
103 | }
104 |
105 | public int getMaskColor() {
106 | return maskColor;
107 | }
108 |
109 | public void setMaskColor(int maskColor) {
110 | this.maskColor = maskColor;
111 | invalidate();
112 | }
113 |
114 | public float getTextSize() {
115 | return textSize;
116 | }
117 |
118 | public void setTextSize(float textSize) {
119 | this.textSize = textSize;
120 | textPaint.setTextSize(textSize);
121 | invalidate();
122 | }
123 |
124 | public int getTextColor() {
125 | return textColor;
126 | }
127 |
128 | public void setTextColor(int textColor) {
129 | this.textColor = textColor;
130 | textPaint.setColor(textColor);
131 | invalidate();
132 | }
133 | }
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/image/SingleImageActivity.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.image;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.ActivityCompat;
7 | import android.text.TextUtils;
8 | import android.view.View;
9 | import android.widget.Toast;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
13 | import com.bumptech.glide.load.engine.GlideException;
14 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
15 | import com.bumptech.glide.request.RequestOptions;
16 | import com.sunfusheng.glideimageview.GlideImageLoader;
17 | import com.sunfusheng.glideimageview.GlideImageView;
18 | import com.sunfusheng.glideimageview.progress.CircleProgressView;
19 | import com.sunfusheng.glideimageview.progress.OnGlideImageViewListener;
20 |
21 | import java.util.Random;
22 |
23 | import static cy.wcdb.yyh.com.myglidefactoryview.MainActivity.isLoadAgain;
24 | import cy.wcdb.yyh.com.myglidefactoryview.R;
25 |
26 | /**
27 | * Created by sunfusheng on 2017/6/15.
28 | */
29 | public class SingleImageActivity extends Activity {
30 |
31 | GlideImageView glideImageView;
32 | CircleProgressView progressView;
33 |
34 | CircleProgressView progressView1;
35 | CircleProgressView progressView2;
36 | CircleProgressView progressView3;
37 | View maskView;
38 |
39 | public static final String KEY_IMAGE_URL = "image_url";
40 | public static final String KEY_IMAGE_URL_THUMBNAIL = "image_url_thumbnail";
41 |
42 | String image_url;
43 | String image_url_thumbnail;
44 |
45 | @Override
46 | protected void onCreate(@Nullable Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.activity_image);
49 |
50 | glideImageView = (GlideImageView) findViewById(R.id.glideImageView);
51 | progressView1 = (CircleProgressView) findViewById(R.id.progressView1);
52 | progressView2 = (CircleProgressView) findViewById(R.id.progressView2);
53 | progressView3 = (CircleProgressView) findViewById(R.id.progressView3);
54 | maskView = findViewById(R.id.maskView);
55 |
56 | image_url = getIntent().getStringExtra(KEY_IMAGE_URL);
57 | image_url_thumbnail = getIntent().getStringExtra(KEY_IMAGE_URL_THUMBNAIL);
58 |
59 | initProgressView();
60 | loadImage();
61 | }
62 |
63 | private void initProgressView() {
64 | isLoadAgain = new Random().nextInt(3) == 1;
65 | int randomNum = new Random().nextInt(3);
66 | switch (randomNum) {
67 | case 1:
68 | progressView = progressView2;
69 | break;
70 | case 2:
71 | progressView = progressView3;
72 | break;
73 | case 0:
74 | default:
75 | progressView = progressView1;
76 | break;
77 | }
78 | progressView1.setVisibility(View.GONE);
79 | progressView2.setVisibility(View.GONE);
80 | progressView3.setVisibility(View.GONE);
81 | progressView.setVisibility(View.VISIBLE);
82 | }
83 |
84 | private void loadImage() {
85 | glideImageView.setOnClickListener(new View.OnClickListener() {
86 | @Override
87 | public void onClick(View v) {
88 | ActivityCompat.finishAfterTransition(SingleImageActivity.this);
89 | }
90 | });
91 |
92 | RequestOptions requestOptions = glideImageView.requestOptions(R.color.black)
93 | .centerCrop();
94 | RequestOptions requestOptionsWithoutCache = glideImageView.requestOptions(R.color.black)
95 | .centerCrop()
96 | .skipMemoryCache(true)
97 | .diskCacheStrategy(DiskCacheStrategy.NONE);
98 |
99 | GlideImageLoader imageLoader = glideImageView.getImageLoader();
100 |
101 | imageLoader.setOnGlideImageViewListener(image_url, new OnGlideImageViewListener() {
102 | @Override
103 | public void onProgress(int percent, boolean isDone, GlideException exception) {
104 | if (exception != null && !TextUtils.isEmpty(exception.getMessage())) {
105 | Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
106 | }
107 | progressView.setProgress(percent);
108 | progressView.setVisibility(isDone ? View.GONE : View.VISIBLE);
109 | maskView.setVisibility(isDone ? View.GONE : View.VISIBLE);
110 | }
111 | });
112 |
113 | imageLoader.requestBuilder(image_url, requestOptionsWithoutCache)
114 | .thumbnail(Glide.with(SingleImageActivity.this)
115 | .load(image_url_thumbnail)
116 | .apply(requestOptions))
117 | .transition(DrawableTransitionOptions.withCrossFade())
118 | .into(glideImageView);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/image/ImagesAdapter.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.image;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.annotation.NonNull;
6 | import android.support.v4.view.PagerAdapter;
7 | import android.text.TextUtils;
8 | import android.util.SparseArray;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.ImageView;
13 |
14 | import com.bumptech.glide.RequestBuilder;
15 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
16 | import com.bumptech.glide.load.engine.GlideException;
17 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
18 | import com.bumptech.glide.request.RequestOptions;
19 | import com.bumptech.glide.request.target.SimpleTarget;
20 | import com.bumptech.glide.request.target.Target;
21 | import com.bumptech.glide.request.transition.Transition;
22 | import com.github.chrisbanes.photoview.OnOutsidePhotoTapListener;
23 | import com.github.chrisbanes.photoview.OnPhotoTapListener;
24 | import com.github.chrisbanes.photoview.PhotoView;
25 | import com.sunfusheng.glideimageview.GlideImageLoader;
26 | import com.sunfusheng.glideimageview.progress.CircleProgressView;
27 | import com.sunfusheng.glideimageview.progress.OnGlideImageViewListener;
28 | import com.sunfusheng.glideimageview.util.DisplayUtil;
29 |
30 | import java.util.List;
31 |
32 | import cy.wcdb.yyh.com.myglidefactoryview.R;
33 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.ImageAttr;
34 |
35 | public class ImagesAdapter extends PagerAdapter implements OnPhotoTapListener, OnOutsidePhotoTapListener {
36 |
37 | private Context mContext;
38 | private LayoutInflater mInflater;
39 | private List images;
40 | private SparseArray photoViews = new SparseArray<>();
41 |
42 | public ImagesAdapter(Context context, @NonNull List images) {
43 | super();
44 | this.mContext = context;
45 | this.mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
46 | this.images = images;
47 | }
48 |
49 | @Override
50 | public int getCount() {
51 | return images.size();
52 | }
53 |
54 | @Override
55 | public boolean isViewFromObject(View view, Object object) {
56 | return view == object;
57 | }
58 |
59 | @Override
60 | public void setPrimaryItem(ViewGroup container, int position, Object object) {
61 | super.setPrimaryItem(container, position, object);
62 | }
63 |
64 | public PhotoView getPhotoView(int index) {
65 | return photoViews.get(index);
66 | }
67 |
68 | @Override
69 | public Object instantiateItem(ViewGroup container, int position) {
70 | View view = (ViewGroup) mInflater.inflate(R.layout.item_photoview, container, false);
71 | final CircleProgressView progressView = (CircleProgressView) view.findViewById(R.id.progressView);
72 | final PhotoView photoView = (PhotoView) view.findViewById(R.id.photoView);
73 | photoView.setScaleType(ImageView.ScaleType.FIT_CENTER);
74 | photoView.setOnPhotoTapListener(this);
75 | photoView.setOnOutsidePhotoTapListener(this);
76 | photoViews.put(position, photoView);
77 |
78 | ImageAttr attr = images.get(position);
79 | String url = TextUtils.isEmpty(attr.thumbnailUrl) ? attr.url : attr.thumbnailUrl;
80 |
81 | GlideImageLoader imageLoader = GlideImageLoader.create(photoView);
82 | imageLoader.setOnGlideImageViewListener(url, new OnGlideImageViewListener() {
83 | @Override
84 | public void onProgress(int percent, boolean isDone, GlideException exception) {
85 | progressView.setProgress(percent);
86 | progressView.setVisibility(isDone ? View.GONE : View.VISIBLE);
87 | }
88 | });
89 |
90 | RequestOptions requestOptions = imageLoader.requestOptions(R.color.placeholder_color)
91 | .centerCrop()
92 | .skipMemoryCache(false)
93 | .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
94 | .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
95 | final RequestBuilder requestBuilder = imageLoader.requestBuilder(url, requestOptions)
96 | .transition(DrawableTransitionOptions.withCrossFade());
97 | requestBuilder.into(new SimpleTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
98 | @Override
99 | public void onResourceReady(Drawable resource, Transition super Drawable> transition) {
100 | if (resource.getIntrinsicHeight() > DisplayUtil.getScreenHeight(mContext)) {
101 | photoView.setScaleType(ImageView.ScaleType.CENTER_CROP);
102 | }
103 | requestBuilder.into(photoView);
104 | }
105 | });
106 |
107 | container.addView(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
108 | return view;
109 | }
110 |
111 | @Override
112 | public void destroyItem(ViewGroup container, int position, Object object) {
113 | container.removeView((View) object);
114 | }
115 |
116 | @Override
117 | public void onPhotoTap(ImageView view, float x, float y) {
118 | ((ImagesActivity) mContext).finishWithAnim();
119 | }
120 |
121 | @Override
122 | public void onOutsidePhotoTap(ImageView imageView) {
123 | ((ImagesActivity) mContext).finishWithAnim();
124 | }
125 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/widget/SlideVerticallyLayout.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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(new ISlideCallback() {
84 | @Override
85 | public void onPositionChange(int offsetY) {
86 | float factor = (float) (getHeight() - offsetY) / (float) getHeight();
87 | setBackgroundColor(((int) (factor * 0xc4)) << 24);
88 | }
89 | });
90 | addSlideCallback(new ISlideCallback() {
91 | @Override
92 | public void onPositionChange(int offsetY) {
93 | for (View view : mSlideView) {
94 | view.setTranslationY(offsetY);
95 | }
96 | }
97 | });
98 | }
99 |
100 | public void addSlideView(View view) {
101 | mSlideView.add(view);
102 | }
103 |
104 | public void slideDown(boolean anim) {
105 | if (!isSlideShown) return;
106 | if (anim) {
107 | mEndY = getHeight();
108 | mDownY = 0;
109 | mSlideAnimator.start();
110 | } else {
111 | for (ISlideCallback cb : slideCblist) {
112 | cb.onPositionChange(getHeight());
113 | }
114 | isSlideShown = false;
115 | }
116 | }
117 |
118 | public void slideUp(boolean anim) {
119 | if (isSlideShown) return;
120 | if (anim) {
121 | mEndY = 0;
122 | mDownY = getHeight();
123 | mSlideAnimator.start();
124 | } else {
125 | for (ISlideCallback cb : slideCblist) {
126 | cb.onPositionChange(0);
127 | }
128 | isSlideShown = true;
129 | }
130 | }
131 |
132 | @Override
133 | public boolean onInterceptTouchEvent(MotionEvent event) {
134 | if (!canChildScrollUp()) {
135 | final int y = (int) event.getY();
136 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
137 | case MotionEvent.ACTION_DOWN:
138 | isTouchWithAnimRunning = mSlideAnimator.isRunning();
139 | mDownY = y;
140 | break;
141 | case MotionEvent.ACTION_MOVE:
142 | if (isGreaterThanMinSize(mDownY, y) && !isTouchWithAnimRunning) {
143 | isCanScroll = true;
144 | return true;
145 | }
146 | break;
147 | }
148 | }
149 | return super.onInterceptTouchEvent(event);
150 | }
151 |
152 | @Override
153 | public boolean onTouchEvent(MotionEvent event) {
154 | final int y = (int) event.getY();
155 | int offsetY = y - mDownY;
156 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
157 | case MotionEvent.ACTION_MOVE:
158 | if (isGreaterThanMinSize(mDownY, y) && isCanScroll) {
159 | for (ISlideCallback cb : slideCblist) {
160 | cb.onPositionChange(getPositionChangeY(offsetY));
161 | }
162 | } else if (isCanScroll) {
163 | for (ISlideCallback cb : slideCblist) {
164 | cb.onPositionChange(0);
165 | }
166 | }
167 | return true;
168 | case MotionEvent.ACTION_POINTER_DOWN:
169 | case MotionEvent.ACTION_UP:
170 | if (isGreaterThanMinSize(mDownY, y) && isCanScroll) {
171 | mDownY = getPositionChangeY(offsetY);
172 | fixPosition(offsetY);
173 | mSlideAnimator.start();
174 | }
175 | break;
176 | }
177 | return super.onTouchEvent(event);
178 | }
179 |
180 | private boolean canChildScrollUp() {
181 | for (View view : mSlideView) {
182 | if (canChildScrollUp(view)) return true;
183 | }
184 | return false;
185 | }
186 |
187 | private boolean canChildScrollUp(View view) {
188 | if (Build.VERSION.SDK_INT < 14) {
189 | return ViewCompat.canScrollVertically(view, -1) || view.getScrollY() > 0;
190 | } else {
191 | return ViewCompat.canScrollVertically(view, -1);
192 | }
193 | }
194 |
195 | private int getPositionChangeY(int offsetY) {
196 | if (isSlideShown) {
197 | return Math.abs(offsetY) - MIN_SCROLL_OFFSET;
198 | } else {
199 | return getHeight() - (Math.abs(offsetY)) - MIN_SCROLL_OFFSET;
200 | }
201 | }
202 |
203 | private boolean isGreaterThanMinSize(int y1, int y2) {
204 | if (isSlideShown) {
205 | return y2 - y1 > MIN_SCROLL_OFFSET;
206 | } else {
207 | return y1 - y2 > MIN_SCROLL_OFFSET;
208 | }
209 | }
210 |
211 | private void fixPosition(int offsetY) {
212 | int absOffsetY = Math.abs(offsetY);
213 | if (isSlideShown && absOffsetY > getHeight() / THRESHOLD) {
214 | mEndY = getHeight();
215 | } else if (!isSlideShown && absOffsetY > getHeight() / THRESHOLD) {
216 | mEndY = 0;
217 | }
218 | }
219 |
220 | public interface ISlideCallback {
221 | void onPositionChange(int offsetY);
222 | }
223 |
224 | public interface IStateCallback {
225 | void onShow();
226 |
227 | void onHide();
228 | }
229 |
230 | }
231 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/GlideImageLoader.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.net.Uri;
6 | import android.os.Handler;
7 | import android.os.Looper;
8 | import android.support.annotation.DrawableRes;
9 | import android.support.annotation.Nullable;
10 | import android.widget.ImageView;
11 |
12 | import com.bumptech.glide.Glide;
13 | import com.bumptech.glide.RequestBuilder;
14 | import com.bumptech.glide.load.DataSource;
15 | import com.bumptech.glide.load.engine.GlideException;
16 | import com.bumptech.glide.request.RequestListener;
17 | import com.bumptech.glide.request.RequestOptions;
18 | import com.bumptech.glide.request.target.Target;
19 | import com.sunfusheng.glideimageview.progress.OnGlideImageViewListener;
20 | import com.sunfusheng.glideimageview.progress.OnProgressListener;
21 | import com.sunfusheng.glideimageview.progress.ProgressManager;
22 | import com.sunfusheng.glideimageview.transformation.GlideCircleTransformation;
23 |
24 | import java.lang.ref.WeakReference;
25 |
26 | /**
27 | * Created by sunfusheng on 2017/6/6.
28 | */
29 | public class GlideImageLoader {
30 |
31 | private static final String ANDROID_RESOURCE = "android.resource://";
32 | private static final String FILE = "file://";
33 | private static final String SEPARATOR = "/";
34 | private static final String HTTP = "http";
35 |
36 | private WeakReference mImageView;
37 | private Object mImageUrlObj;
38 | private long mTotalBytes = 0;
39 | private long mLastBytesRead = 0;
40 | private boolean mLastStatus = false;
41 | private Handler mMainThreadHandler;
42 |
43 | private OnProgressListener internalProgressListener;
44 | private OnGlideImageViewListener onGlideImageViewListener;
45 | private OnProgressListener onProgressListener;
46 |
47 | public static GlideImageLoader create(ImageView imageView) {
48 | return new GlideImageLoader(imageView);
49 | }
50 |
51 | private GlideImageLoader(ImageView imageView) {
52 | mImageView = new WeakReference<>(imageView);
53 | mMainThreadHandler = new Handler(Looper.getMainLooper());
54 | }
55 |
56 | public ImageView getImageView() {
57 | if (mImageView != null) {
58 | return mImageView.get();
59 | }
60 | return null;
61 | }
62 |
63 | public Context getContext() {
64 | if (getImageView() != null) {
65 | return getImageView().getContext();
66 | }
67 | return null;
68 | }
69 |
70 | public String getImageUrl() {
71 | if (mImageUrlObj == null) return null;
72 | if (!(mImageUrlObj instanceof String)) return null;
73 | return (String) mImageUrlObj;
74 | }
75 |
76 | public Uri resId2Uri(int resourceId) {
77 | if (getContext() == null) return null;
78 | return Uri.parse(ANDROID_RESOURCE + getContext().getPackageName() + SEPARATOR + resourceId);
79 | }
80 |
81 | public void load(int resId, RequestOptions options) {
82 | load(resId2Uri(resId), options);
83 | }
84 |
85 | public void load(Uri uri, RequestOptions options) {
86 | if (uri == null || getContext() == null) return;
87 | requestBuilder(uri, options).into(getImageView());
88 | }
89 |
90 | public void load(String url, RequestOptions options) {
91 | if (url == null || getContext() == null) return;
92 | requestBuilder(url, options).into(getImageView());
93 | }
94 |
95 | public RequestBuilder requestBuilder(Object obj, RequestOptions options) {
96 | this.mImageUrlObj = obj;
97 | return Glide.with(getContext())
98 | .load(obj)
99 | .apply(options)
100 | .listener(new RequestListener() {
101 | @Override
102 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
103 | mainThreadCallback(mLastBytesRead, mTotalBytes, true, e);
104 | ProgressManager.removeProgressListener(internalProgressListener);
105 | return false;
106 | }
107 |
108 | @Override
109 | public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
110 | mainThreadCallback(mLastBytesRead, mTotalBytes, true, null);
111 | ProgressManager.removeProgressListener(internalProgressListener);
112 | return false;
113 | }
114 | });
115 | }
116 |
117 | public RequestOptions requestOptions(int placeholderResId) {
118 | return requestOptions(placeholderResId, placeholderResId);
119 | }
120 |
121 | public RequestOptions requestOptions(int placeholderResId, int errorResId) {
122 | return new RequestOptions()
123 | .placeholder(placeholderResId)
124 | .error(errorResId);
125 | }
126 |
127 | public RequestOptions circleRequestOptions(int placeholderResId) {
128 | return circleRequestOptions(placeholderResId, placeholderResId);
129 | }
130 |
131 | public RequestOptions circleRequestOptions(int placeholderResId, int errorResId) {
132 | return requestOptions(placeholderResId, errorResId)
133 | .transform(new GlideCircleTransformation());
134 | }
135 |
136 | public void loadImage(String url, int placeholderResId) {
137 | load(url, requestOptions(placeholderResId));
138 | }
139 |
140 | public void loadLocalImage(@DrawableRes int resId, int placeholderResId) {
141 | load(resId, requestOptions(placeholderResId));
142 | }
143 |
144 | public void loadLocalImage(String localPath, int placeholderResId) {
145 | load(FILE + localPath, requestOptions(placeholderResId));
146 | }
147 |
148 | public void loadCircleImage(String url, int placeholderResId) {
149 | load(url, circleRequestOptions(placeholderResId));
150 | }
151 |
152 | public void loadLocalCircleImage(int resId, int placeholderResId) {
153 | load(resId, circleRequestOptions(placeholderResId));
154 | }
155 |
156 | public void loadLocalCircleImage(String localPath, int placeholderResId) {
157 | load(FILE + localPath, circleRequestOptions(placeholderResId));
158 | }
159 |
160 | private void addProgressListener() {
161 | if (getImageUrl() == null) return;
162 | final String url = getImageUrl();
163 | if (!url.startsWith(HTTP)) return;
164 |
165 | internalProgressListener = new OnProgressListener() {
166 | @Override
167 | public void onProgress(String imageUrl, long bytesRead, long totalBytes, boolean isDone, GlideException exception) {
168 | if (totalBytes == 0) return;
169 | if (!url.equals(imageUrl)) return;
170 | if (mLastBytesRead == bytesRead && mLastStatus == isDone) return;
171 |
172 | mLastBytesRead = bytesRead;
173 | mTotalBytes = totalBytes;
174 | mLastStatus = isDone;
175 | mainThreadCallback(bytesRead, totalBytes, isDone, exception);
176 |
177 | if (isDone) {
178 | ProgressManager.removeProgressListener(this);
179 | }
180 | }
181 | };
182 | ProgressManager.addProgressListener(internalProgressListener);
183 | }
184 |
185 | private void mainThreadCallback(final long bytesRead, final long totalBytes, final boolean isDone, final GlideException exception) {
186 | mMainThreadHandler.post(new Runnable() {
187 | @Override
188 | public void run() {
189 | final int percent = (int) ((bytesRead * 1.0f / totalBytes) * 100.0f);
190 | if (onProgressListener != null) {
191 | onProgressListener.onProgress((String) mImageUrlObj, bytesRead, totalBytes, isDone, exception);
192 | }
193 |
194 | if (onGlideImageViewListener != null) {
195 | onGlideImageViewListener.onProgress(percent, isDone, exception);
196 | }
197 | }
198 | });
199 | }
200 |
201 | public void setOnGlideImageViewListener(String imageUrl, OnGlideImageViewListener onGlideImageViewListener) {
202 | this.mImageUrlObj = imageUrl;
203 | this.onGlideImageViewListener = onGlideImageViewListener;
204 | addProgressListener();
205 | }
206 |
207 | public void setOnProgressListener(String imageUrl, OnProgressListener onProgressListener) {
208 | this.mImageUrlObj = imageUrl;
209 | this.onProgressListener = onProgressListener;
210 | addProgressListener();
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/image/ImagesActivity.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.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.util.Log;
11 | import android.view.ViewTreeObserver;
12 | import android.widget.RelativeLayout;
13 | import android.widget.TextView;
14 |
15 | import com.github.chrisbanes.photoview.PhotoView;
16 | import com.sunfusheng.glideimageview.util.DisplayUtil;
17 |
18 | import java.util.List;
19 |
20 | import cy.wcdb.yyh.com.myglidefactoryview.R;
21 | import cy.wcdb.yyh.com.myglidefactoryview.util.ColorUtil;
22 | import cy.wcdb.yyh.com.myglidefactoryview.util.StatusBarUtil;
23 | import cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView.ImageAttr;
24 |
25 | public class ImagesActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
26 |
27 | public static final String IMAGE_ATTR = "image_attr";
28 | public static final String CUR_POSITION = "cur_position";
29 | public static final int ANIM_DURATION = 300; // ms
30 |
31 | private RelativeLayout rootView;
32 | private ViewPager viewPager;
33 | private TextView tvTip;
34 | private ImagesAdapter mAdapter;
35 | private List imageAttrs;
36 |
37 | private int curPosition;
38 | private int screenWidth;
39 | private int screenHeight;
40 | private float scaleX;
41 | private float scaleY;
42 | private float translationX;
43 | private float translationY;
44 |
45 | @Override
46 | protected void onCreate(Bundle savedInstanceState) {
47 | super.onCreate(savedInstanceState);
48 | setContentView(R.layout.activity_preview);
49 | StatusBarUtil.setStatusBarTranslucent(this, false);
50 |
51 | viewPager = (ViewPager) findViewById(R.id.viewPager);
52 | tvTip = (TextView) findViewById(R.id.tv_tip);
53 | rootView = (RelativeLayout) findViewById(R.id.rootView);
54 | screenWidth = DisplayUtil.getScreenWidth(this);
55 | screenHeight = DisplayUtil.getScreenHeight(this);
56 |
57 | Intent intent = getIntent();
58 | imageAttrs = (List) intent.getSerializableExtra(IMAGE_ATTR);
59 | curPosition = intent.getIntExtra(CUR_POSITION, 0);
60 | tvTip.setText(String.format(getString(R.string.image_index), (curPosition + 1), imageAttrs.size()));
61 |
62 | mAdapter = new ImagesAdapter(this, imageAttrs);
63 | viewPager.setAdapter(mAdapter);
64 | viewPager.setCurrentItem(curPosition);
65 | viewPager.getViewTreeObserver().addOnPreDrawListener(this);
66 | viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
67 | @Override
68 | public void onPageSelected(int position) {
69 | curPosition = position;
70 | tvTip.setText(String.format(getString(R.string.image_index), (curPosition + 1), imageAttrs.size()));
71 | }
72 | });
73 | }
74 |
75 | @Override
76 | public void onBackPressed() {
77 | finishWithAnim();
78 | }
79 |
80 | private void initImageAttr(ImageAttr attr) {
81 | int originalWidth = attr.width;
82 | int originalHeight = attr.height;
83 | int originalCenterX = attr.left + originalWidth / 2;
84 | int originalCenterY = attr.top + originalHeight / 2;
85 |
86 | float widthRatio = screenWidth * 1.0f / originalWidth;
87 | float heightRatio = screenHeight * 1.0f / originalHeight;
88 | float ratio = widthRatio > heightRatio ? heightRatio : widthRatio;
89 | int finalWidth = (int) (originalWidth * ratio);
90 | int finalHeight = (int) (originalHeight * ratio);
91 |
92 | scaleX = originalWidth * 1.0f / finalWidth;
93 | scaleY = originalHeight * 1.0f / finalHeight;
94 | translationX = originalCenterX - screenWidth / 2;
95 | translationY = originalCenterY - screenHeight / 2;
96 |
97 | Log.d("--->", "(left, top): (" + attr.left + ", " + attr.top + ")");
98 | Log.d("--->", "originalWidth: " + originalWidth + " originalHeight: " + originalHeight);
99 | Log.d("--->", "finalWidth: " + finalWidth + " finalHeight: " + finalHeight);
100 | Log.d("--->", "scaleX: " + scaleX + " scaleY: " + scaleY);
101 | Log.d("--->", "translationX: " + translationX + " translationY: " + translationY);
102 | Log.d("--->", "" + attr.toString());
103 | Log.d("--->", "----------------------------------------------------------------");
104 | }
105 |
106 | @Override
107 | public boolean onPreDraw() {
108 | rootView.getViewTreeObserver().removeOnPreDrawListener(this);
109 | PhotoView photoView = mAdapter.getPhotoView(curPosition);
110 | ImageAttr attr = imageAttrs.get(curPosition);
111 | initImageAttr(attr);
112 |
113 | setBackgroundColor(0f, 1f, null);
114 | translateXAnim(photoView, translationX, 0);
115 | translateYAnim(photoView, translationY, 0);
116 | scaleXAnim(photoView, scaleX, 1);
117 | scaleYAnim(photoView, scaleY, 1);
118 | return true;
119 | }
120 |
121 | public void finishWithAnim() {
122 | PhotoView photoView = mAdapter.getPhotoView(curPosition);
123 | photoView.setScale(1f);
124 | ImageAttr attr = imageAttrs.get(curPosition);
125 | initImageAttr(attr);
126 |
127 | translateXAnim(photoView, 0, translationX);
128 | translateYAnim(photoView, 0, translationY);
129 | scaleXAnim(photoView, 1, scaleX);
130 | scaleYAnim(photoView, 1, scaleY);
131 | setBackgroundColor(1f, 0f, new Animator.AnimatorListener() {
132 | @Override
133 | public void onAnimationStart(Animator animation) {
134 | }
135 |
136 | @Override
137 | public void onAnimationEnd(Animator animation) {
138 | finish();
139 | overridePendingTransition(0, 0);
140 | }
141 |
142 | @Override
143 | public void onAnimationCancel(Animator animation) {
144 | }
145 |
146 | @Override
147 | public void onAnimationRepeat(Animator animation) {
148 | }
149 | });
150 | }
151 |
152 | private void translateXAnim(final PhotoView photoView, float from, float to) {
153 | ValueAnimator anim = ValueAnimator.ofFloat(from, to);
154 | anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
155 | @Override
156 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
157 | photoView.setX((Float) valueAnimator.getAnimatedValue());
158 | }
159 | });
160 | anim.setDuration(ANIM_DURATION);
161 | anim.start();
162 | }
163 |
164 | private void translateYAnim(final PhotoView photoView, float from, float to) {
165 | ValueAnimator anim = ValueAnimator.ofFloat(from, to);
166 | anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
167 | @Override
168 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
169 | photoView.setY((Float) valueAnimator.getAnimatedValue());
170 | }
171 | });
172 | anim.setDuration(ANIM_DURATION);
173 | anim.start();
174 | }
175 |
176 | private void scaleXAnim(final PhotoView photoView, float from, float to) {
177 | ValueAnimator anim = ValueAnimator.ofFloat(from, to);
178 | anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
179 | @Override
180 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
181 | photoView.setScaleX((Float) valueAnimator.getAnimatedValue());
182 | }
183 | });
184 | anim.setDuration(ANIM_DURATION);
185 | anim.start();
186 | }
187 |
188 | private void scaleYAnim(final PhotoView photoView, float from, float to) {
189 | ValueAnimator anim = ValueAnimator.ofFloat(from, to);
190 | anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
191 | @Override
192 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
193 | photoView.setScaleY((Float) valueAnimator.getAnimatedValue());
194 | }
195 | });
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(new ValueAnimator.AnimatorUpdateListener() {
203 | @Override
204 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
205 | rootView.setBackgroundColor(ColorUtil.evaluate((Float) valueAnimator.getAnimatedValue(), Color.TRANSPARENT, Color.BLACK));
206 | }
207 | });
208 | anim.setDuration(ANIM_DURATION);
209 | if (listener != null) {
210 | anim.addListener(listener);
211 | }
212 | anim.start();
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/ShapeImageView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.PorterDuff;
10 | import android.graphics.PorterDuffXfermode;
11 | import android.graphics.RectF;
12 | import android.graphics.drawable.BitmapDrawable;
13 | import android.graphics.drawable.ColorDrawable;
14 | import android.graphics.drawable.Drawable;
15 | import android.support.annotation.ColorRes;
16 | import android.support.annotation.IntDef;
17 | import android.util.AttributeSet;
18 | import android.view.MotionEvent;
19 | import android.widget.ImageView;
20 |
21 | import com.sunfusheng.glideimageview.util.DisplayUtil;
22 |
23 | import java.lang.annotation.Retention;
24 | import java.lang.annotation.RetentionPolicy;
25 |
26 | /**
27 | * Created by sunfusheng on 2017/6/12.
28 | */
29 | @SuppressWarnings("deprecation")
30 | public class ShapeImageView extends ImageView {
31 |
32 | // 定义Bitmap的默认配置
33 | private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
34 | private static final int COLOR_DRAWABLE_DIMENSION = 1;
35 |
36 | // 图片的宽高
37 | private int width;
38 | private int height;
39 |
40 | private int borderColor = 0x1A000000; // 边框颜色
41 | private int borderWidth = 0; // 边框宽度
42 | private int radius = 0; // 圆角弧度
43 | private int shapeType = ShapeType.RECTANGLE; // 图片类型(圆形, 矩形)
44 |
45 | private Paint pressedPaint; // 按下的画笔
46 | private float pressedAlpha = 0.1f; // 按下的透明度
47 | private int pressedColor = 0x1A000000; // 按下的颜色
48 |
49 | @IntDef({ShapeType.RECTANGLE, ShapeType.CIRCLE})
50 | @Retention(RetentionPolicy.SOURCE)
51 | public @interface ShapeType {
52 | int RECTANGLE = 0;
53 | int CIRCLE = 1;
54 | }
55 |
56 | public ShapeImageView(Context context) {
57 | this(context, null);
58 | }
59 |
60 | public ShapeImageView(Context context, AttributeSet attrs) {
61 | this(context, attrs, 0);
62 | }
63 |
64 | public ShapeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
65 | super(context, attrs, defStyleAttr);
66 | init(context, attrs);
67 | }
68 |
69 | private void init(Context context, AttributeSet attrs) {
70 | if (attrs != null) {
71 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ShapeImageViewStyle);
72 | borderWidth = array.getDimensionPixelOffset(R.styleable.ShapeImageViewStyle_siv_border_width, borderWidth);
73 | borderColor = array.getColor(R.styleable.ShapeImageViewStyle_siv_border_color, borderColor);
74 | radius = array.getDimensionPixelOffset(R.styleable.ShapeImageViewStyle_siv_radius, radius);
75 | pressedAlpha = array.getFloat(R.styleable.ShapeImageViewStyle_siv_pressed_alpha, pressedAlpha);
76 | if (pressedAlpha > 1) pressedAlpha = 1;
77 | pressedColor = array.getColor(R.styleable.ShapeImageViewStyle_siv_pressed_color, pressedColor);
78 | shapeType = array.getInteger(R.styleable.ShapeImageViewStyle_siv_shape_type, shapeType);
79 | array.recycle();
80 | }
81 |
82 | initPressedPaint();
83 | setClickable(true);
84 | setDrawingCacheEnabled(true);
85 | setWillNotDraw(false);
86 | }
87 |
88 | // 初始化按下的画笔
89 | private void initPressedPaint() {
90 | pressedPaint = new Paint();
91 | pressedPaint.setAntiAlias(true);
92 | pressedPaint.setStyle(Paint.Style.FILL);
93 | pressedPaint.setColor(pressedColor);
94 | pressedPaint.setAlpha(0);
95 | pressedPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
96 | }
97 |
98 | @Override
99 | protected void onDraw(Canvas canvas) {
100 | Drawable drawable = getDrawable();
101 | if (drawable == null) {
102 | return;
103 | }
104 |
105 | if (getWidth() == 0 || getHeight() == 0) {
106 | return;
107 | }
108 |
109 | drawDrawable(canvas, getBitmapFromDrawable(drawable));
110 | drawBorder(canvas);
111 | drawPressed(canvas);
112 | }
113 |
114 | @Override
115 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
116 | super.onSizeChanged(w, h, oldw, oldh);
117 | width = w;
118 | height = h;
119 | }
120 |
121 | // 绘制圆角
122 | private void drawDrawable(Canvas canvas, Bitmap bitmap) {
123 | Paint paint = new Paint();
124 | paint.setColor(0xffffffff);
125 | paint.setAntiAlias(true);
126 |
127 | int saveFlags = Canvas.MATRIX_SAVE_FLAG
128 | | Canvas.CLIP_SAVE_FLAG
129 | | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
130 | | Canvas.FULL_COLOR_LAYER_SAVE_FLAG
131 | | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
132 |
133 | canvas.saveLayer(0, 0, width, height, null, saveFlags);
134 |
135 | if (shapeType == ShapeType.RECTANGLE) {
136 | RectF rectf = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, getHeight() - borderWidth / 2);
137 | canvas.drawRoundRect(rectf, radius, radius, paint);
138 | } else {
139 | canvas.drawCircle(width / 2, height / 2, width / 2 - borderWidth, paint);
140 | }
141 |
142 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); // SRC_IN 只显示两层图像交集部分的上层图像
143 |
144 | //Bitmap缩放
145 | float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
146 | float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
147 | Matrix matrix = new Matrix();
148 | matrix.postScale(scaleWidth, scaleHeight);
149 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
150 | canvas.drawBitmap(bitmap, 0, 0, paint);
151 | canvas.restore();
152 | }
153 |
154 | // 绘制边框
155 | private void drawBorder(Canvas canvas) {
156 | if (borderWidth > 0) {
157 | Paint paint = new Paint();
158 | paint.setStrokeWidth(borderWidth);
159 | paint.setStyle(Paint.Style.STROKE);
160 | paint.setColor(borderColor);
161 | paint.setAntiAlias(true);
162 | if (shapeType == ShapeType.RECTANGLE) {
163 | RectF rectf = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, getHeight() - borderWidth / 2);
164 | canvas.drawRoundRect(rectf, radius, radius, paint);
165 | } else {
166 | canvas.drawCircle(width / 2, height / 2, (width - borderWidth) / 2, paint);
167 | }
168 | }
169 | }
170 |
171 | // 绘制按下效果
172 | private void drawPressed(Canvas canvas) {
173 | if (shapeType == ShapeType.RECTANGLE) {
174 | RectF rectf = new RectF(1, 1, width - 1, height - 1);
175 | canvas.drawRoundRect(rectf, radius, radius, pressedPaint);
176 | } else {
177 | canvas.drawCircle(width / 2, height / 2, width / 2, pressedPaint);
178 | }
179 | }
180 |
181 | @Override
182 | public boolean onTouchEvent(MotionEvent event) {
183 | switch (event.getAction()) {
184 | case MotionEvent.ACTION_DOWN:
185 | pressedPaint.setAlpha((int) (pressedAlpha * 255));
186 | invalidate();
187 | break;
188 | case MotionEvent.ACTION_UP:
189 | pressedPaint.setAlpha(0);
190 | invalidate();
191 | break;
192 | case MotionEvent.ACTION_MOVE:
193 | break;
194 | default:
195 | pressedPaint.setAlpha(0);
196 | invalidate();
197 | break;
198 | }
199 | return super.onTouchEvent(event);
200 | }
201 |
202 | // 获取Bitmap内容
203 | private Bitmap getBitmapFromDrawable(Drawable drawable) {
204 | try {
205 | Bitmap bitmap;
206 | if (drawable instanceof BitmapDrawable) {
207 | return ((BitmapDrawable) drawable).getBitmap();
208 | } else if (drawable instanceof ColorDrawable) {
209 | bitmap = Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG);
210 | } else {
211 | bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
212 | }
213 | Canvas canvas = new Canvas(bitmap);
214 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
215 | drawable.draw(canvas);
216 | return bitmap;
217 | } catch (OutOfMemoryError e) {
218 | e.printStackTrace();
219 | return null;
220 | }
221 | }
222 |
223 | // 设置边框颜色
224 | public void setBorderColor(@ColorRes int id) {
225 | this.borderColor = getResources().getColor(id);
226 | invalidate();
227 | }
228 |
229 | // 设置边框宽度
230 | public void setBorderWidth(int borderWidth) {
231 | this.borderWidth = DisplayUtil.dip2px(getContext(), borderWidth);
232 | invalidate();
233 | }
234 |
235 | // 设置图片按下颜色透明度
236 | public void setPressedAlpha(float pressAlpha) {
237 | this.pressedAlpha = pressAlpha;
238 | }
239 |
240 | // 设置图片按下的颜色
241 | public void setPressedColor(@ColorRes int id) {
242 | this.pressedColor = getResources().getColor(id);
243 | pressedPaint.setColor(pressedColor);
244 | pressedPaint.setAlpha(0);
245 | invalidate();
246 | }
247 |
248 | // 设置圆角半径
249 | public void setRadius(int radius) {
250 | this.radius = DisplayUtil.dip2px(getContext(), radius);
251 | invalidate();
252 | }
253 |
254 | // 设置形状类型
255 | public void setShapeType(@ShapeType int shapeType) {
256 | this.shapeType = shapeType;
257 | invalidate();
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview;
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.text.TextUtils;
8 | import android.util.Log;
9 | import android.view.Menu;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
16 | import com.bumptech.glide.load.engine.GlideException;
17 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
18 | import com.bumptech.glide.request.RequestOptions;
19 | import com.sunfusheng.glideimageview.GlideImageLoader;
20 | import com.sunfusheng.glideimageview.GlideImageView;
21 | import com.sunfusheng.glideimageview.ShapeImageView;
22 | import com.sunfusheng.glideimageview.progress.CircleProgressView;
23 | import com.sunfusheng.glideimageview.progress.OnGlideImageViewListener;
24 | import com.sunfusheng.glideimageview.progress.OnProgressListener;
25 |
26 | import java.util.Random;
27 |
28 | import cy.wcdb.yyh.com.myglidefactoryview.image.SingleImageActivity;
29 |
30 | import static cy.wcdb.yyh.com.myglidefactoryview.image.SingleImageActivity.KEY_IMAGE_URL;
31 | import static cy.wcdb.yyh.com.myglidefactoryview.image.SingleImageActivity.KEY_IMAGE_URL_THUMBNAIL;
32 |
33 |
34 | /**
35 | * Created by sunfusheng on 2017/6/3.
36 | */
37 | public class MainActivity extends BaseActivity {
38 |
39 | GlideImageView image11;
40 | GlideImageView image12;
41 | GlideImageView image13;
42 | GlideImageView image14;
43 |
44 | GlideImageView image21;
45 | GlideImageView image22;
46 | GlideImageView image23;
47 | GlideImageView image24;
48 |
49 | GlideImageView image31;
50 | GlideImageView image32;
51 | GlideImageView image33;
52 | GlideImageView image34;
53 |
54 | GlideImageView image41;
55 | CircleProgressView progressView1;
56 | GlideImageView image42;
57 | CircleProgressView progressView2;
58 |
59 | TextView draggableView;
60 |
61 | String url1 = "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";
62 | String url2 = "http://img1.imgtn.bdimg.com/it/u=4027212837,1228313366&fm=23&gp=0.jpg";
63 |
64 | public static boolean isLoadAgain = false; // Just for fun when loading images!
65 |
66 | public static final String cat = "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/screenshot/cat.jpg";
67 | public static final String cat_thumbnail = "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/screenshot/cat_thumbnail.jpg";
68 |
69 | public static final String girl = "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/screenshot/girl.jpg";
70 | public static final String girl_thumbnail = "https://raw.githubusercontent.com/sfsheng0322/GlideImageView/master/screenshot/girl_thumbnail.jpg";
71 |
72 | String gif1 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496754078616&di=cc68338a66a36de619fa11d0c1b2e6f3&imgtype=0&src=http%3A%2F%2Fapp.576tv.com%2FUploads%2Foltz%2F201609%2F25%2F1474813626468299.gif";
73 | String gif2 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1497276275707&di=57c8c7917e91afc1bc86b1b57e743425&imgtype=0&src=http%3A%2F%2Fimg.haatoo.com%2Fpics%2F2016%2F05%2F14%2F9%2F4faf3f52b8e8315af7a469731dc7dce5.jpg";
74 | String gif3 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1497276379533&di=71435f66d66221eb36dab266deb9d6d2&imgtype=0&src=http%3A%2F%2Fatt.bbs.duowan.com%2Fforum%2F201608%2F02%2F190418bmy9zqm94qxlmqf4.gif";
75 |
76 | @Override
77 | protected void onCreate(Bundle savedInstanceState) {
78 | super.onCreate(savedInstanceState);
79 | setContentView(R.layout.activity_main);
80 |
81 | image11 = (GlideImageView) findViewById(R.id.image11);
82 | image12 = (GlideImageView) findViewById(R.id.image12);
83 | image13 = (GlideImageView) findViewById(R.id.image13);
84 | image14 = (GlideImageView) findViewById(R.id.image14);
85 |
86 | image21 = (GlideImageView) findViewById(R.id.image21);
87 | image22 = (GlideImageView) findViewById(R.id.image22);
88 | image23 = (GlideImageView) findViewById(R.id.image23);
89 | image24 = (GlideImageView) findViewById(R.id.image24);
90 |
91 | image31 = (GlideImageView) findViewById(R.id.image31);
92 | image32 = (GlideImageView) findViewById(R.id.image32);
93 | image33 = (GlideImageView) findViewById(R.id.image33);
94 | image34 = (GlideImageView) findViewById(R.id.image34);
95 |
96 | image41 = (GlideImageView) findViewById(R.id.image41);
97 | progressView1 = (CircleProgressView) findViewById(R.id.progressView1);
98 | image42 = (GlideImageView) findViewById(R.id.image42);
99 | progressView2 = (CircleProgressView) findViewById(R.id.progressView2);
100 |
101 | draggableView = (TextView) findViewById(R.id.draggable_view);
102 | draggableView.setOnClickListener(new View.OnClickListener() {
103 | @Override
104 | public void onClick(View v) {
105 | startActivity(new Intent(mContext, RecycleViewActivity.class));
106 | }
107 | });
108 |
109 | isLoadAgain = new Random().nextInt(3) == 1;
110 |
111 | line1();
112 | line2();
113 | line3();
114 | line41();
115 | line42();
116 | }
117 |
118 | private void line1() {
119 | image11.loadImage(url1, R.color.placeholder_color).listener(new OnProgressListener() {
120 | @Override
121 | public void onProgress(String imageUrl, long bytesRead, long totalBytes, boolean isDone, GlideException exception) {
122 | Log.d("--->image11", "bytesRead: " + bytesRead + " totalBytes: " + totalBytes + " isDone: " + isDone);
123 | }
124 | });
125 |
126 | image12.setBorderWidth(3);
127 | image12.setBorderColor(R.color.transparent20);
128 | image12.loadCircleImage(url1, R.color.placeholder_color);
129 |
130 | image13.setRadius(15);
131 | image13.setBorderWidth(3);
132 | image13.setBorderColor(R.color.blue);
133 | image13.setPressedAlpha(0.3f);
134 | image13.setPressedColor(R.color.blue);
135 | image13.loadImage(url1, R.color.placeholder_color);
136 |
137 | image14.setShapeType(ShapeImageView.ShapeType.CIRCLE);
138 | image14.setBorderWidth(3);
139 | image14.setBorderColor(R.color.orange);
140 | image14.setPressedAlpha(0.2f);
141 | image14.setPressedColor(R.color.orange);
142 | image14.loadImage(url1, R.color.placeholder_color);
143 | }
144 |
145 | private void line2() {
146 | image21.loadImage(url2, R.color.placeholder_color);
147 | image22.loadImage(url2, R.color.placeholder_color);
148 | image23.loadImage(url2, R.color.placeholder_color);
149 | image24.loadImage(url2, R.color.placeholder_color);
150 | }
151 |
152 | private void line3() {
153 | image31.loadLocalImage(R.drawable.gif_robot_walk, R.mipmap.ic_launcher);
154 |
155 | image32.loadCircleImage(gif1, R.mipmap.ic_launcher).listener(new OnGlideImageViewListener() {
156 | @Override
157 | public void onProgress(int percent, boolean isDone, GlideException exception) {
158 | Log.d("--->image32", "percent: " + percent + " isDone: " + isDone);
159 | }
160 | });
161 |
162 | image33.loadImage(gif2, R.mipmap.ic_launcher);
163 | image34.loadImage(gif3, R.mipmap.ic_launcher);
164 | }
165 |
166 | private void line41() {
167 | image41.setOnClickListener(new View.OnClickListener() {
168 | @Override
169 | public void onClick(View v) {
170 | Intent intent = new Intent(MainActivity.this, SingleImageActivity.class);
171 | intent.putExtra(KEY_IMAGE_URL, cat);
172 | intent.putExtra(KEY_IMAGE_URL_THUMBNAIL, cat_thumbnail);
173 | ActivityOptionsCompat compat = ActivityOptionsCompat
174 | .makeSceneTransitionAnimation(MainActivity.this, image41, getString(R.string.transitional_image));
175 | ActivityCompat.startActivity(MainActivity.this, intent, compat.toBundle());
176 | }
177 | });
178 |
179 | RequestOptions requestOptions = image41.requestOptions(R.color.placeholder_color).centerCrop();
180 | if (isLoadAgain) {
181 | requestOptions.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true);
182 | }
183 |
184 | // 第一种方式加载
185 | image41.load(cat_thumbnail, requestOptions).listener(new OnGlideImageViewListener() {
186 | @Override
187 | public void onProgress(int percent, boolean isDone, GlideException exception) {
188 | if (exception != null && !TextUtils.isEmpty(exception.getMessage())) {
189 | Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
190 | }
191 | progressView1.setProgress(percent);
192 | progressView1.setVisibility(isDone ? View.GONE : View.VISIBLE);
193 | }
194 | });
195 | }
196 |
197 | private void line42() {
198 | image42.setOnClickListener(new View.OnClickListener() {
199 | @Override
200 | public void onClick(View view) {
201 | Intent intent = new Intent(MainActivity.this, SingleImageActivity.class);
202 | intent.putExtra(KEY_IMAGE_URL, girl);
203 | intent.putExtra(KEY_IMAGE_URL_THUMBNAIL, girl_thumbnail);
204 | ActivityOptionsCompat compat = ActivityOptionsCompat
205 | .makeSceneTransitionAnimation(MainActivity.this, image42, getString(R.string.transitional_image));
206 | ActivityCompat.startActivity(MainActivity.this, intent, compat.toBundle());
207 | }
208 | });
209 |
210 | RequestOptions requestOptions = image42.requestOptions(R.color.placeholder_color).centerCrop();
211 | if (isLoadAgain) {
212 | requestOptions.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true);
213 | }
214 |
215 | // 第二种方式加载:可以解锁更多功能
216 | GlideImageLoader imageLoader = image42.getImageLoader();
217 | imageLoader.setOnGlideImageViewListener(girl_thumbnail, new OnGlideImageViewListener() {
218 | @Override
219 | public void onProgress(int percent, boolean isDone, GlideException exception) {
220 |
221 | if (exception != null && !TextUtils.isEmpty(exception.getMessage())) {
222 | Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
223 | }
224 | progressView2.setProgress(percent);
225 | progressView2.setVisibility(isDone ? View.GONE : View.VISIBLE);
226 | }
227 | });
228 | imageLoader.requestBuilder(girl_thumbnail, requestOptions)
229 | .transition(DrawableTransitionOptions.withCrossFade())
230 | .into(image42);
231 | }
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/app/src/main/java/cy/wcdb/yyh/com/myglidefactoryview/widget/NineImageView/NineImageView.java:
--------------------------------------------------------------------------------
1 | package cy.wcdb.yyh.com.myglidefactoryview.widget.NineImageView;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.drawable.Drawable;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.text.TextUtils;
9 | import android.util.AttributeSet;
10 | import android.util.DisplayMetrics;
11 | import android.util.TypedValue;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.widget.ImageView;
15 |
16 | import com.bumptech.glide.load.DataSource;
17 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
18 | import com.bumptech.glide.load.engine.GlideException;
19 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
20 | import com.bumptech.glide.request.RequestListener;
21 | import com.bumptech.glide.request.RequestOptions;
22 | import com.bumptech.glide.request.target.Target;
23 | import com.sunfusheng.glideimageview.GlideImageLoader;
24 | import com.sunfusheng.glideimageview.util.DisplayUtil;
25 |
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | import cy.wcdb.yyh.com.myglidefactoryview.R;
30 |
31 | public class NineImageView extends ViewGroup {
32 |
33 | public static final int MODE_GRID = 0; //网格模式,4张图2X2布局
34 | public static final int MODE_FILL = 1; //填充模式,类似于微信
35 |
36 | private int singleImageWidth;
37 | private int singleImageHeight;
38 | private int singleImageMaxWidth;
39 | private int singleImageMinWidth;
40 |
41 | private int maxImageSize = 9; // 最大显示的图片数
42 | private int gridSpacing = 5; // 宫格间距,单位dp
43 | private int mode = MODE_GRID; // 默认使用GRID模式
44 |
45 | private int columnCount; // 列数
46 | private int rowCount; // 行数
47 | private int gridWidth; // 宫格宽度
48 | private int gridHeight; // 宫格高度
49 |
50 | private List imageViews;
51 | private List imageAttrs;
52 | private NineImageViewAdapter mAdapter;
53 |
54 | public NineImageView(Context context) {
55 | this(context, null);
56 | }
57 |
58 | public NineImageView(Context context, AttributeSet attrs) {
59 | this(context, attrs, 0);
60 | }
61 |
62 | public NineImageView(Context context, AttributeSet attrs, int defStyleAttr) {
63 | super(context, attrs, defStyleAttr);
64 | init(context, attrs);
65 | }
66 |
67 | private void init(Context context, AttributeSet attrs) {
68 | int WIDTH = DisplayUtil.getScreenWidth(context) - DisplayUtil.dip2px(context, 15 * 2);
69 | singleImageMaxWidth = WIDTH * 2 / 3;
70 | singleImageMinWidth = WIDTH / 3;
71 | singleImageWidth = singleImageMinWidth;
72 | singleImageHeight = singleImageMinWidth;
73 |
74 | imageViews = new ArrayList<>();
75 |
76 | DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
77 | gridSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gridSpacing, displayMetrics);
78 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NineGridView);
79 | gridSpacing = (int) typedArray.getDimension(R.styleable.NineGridView_ngv_gridSpacing, gridSpacing);
80 | maxImageSize = typedArray.getInt(R.styleable.NineGridView_ngv_maxSize, maxImageSize);
81 | mode = typedArray.getInt(R.styleable.NineGridView_ngv_mode, mode);
82 | typedArray.recycle();
83 | }
84 |
85 | @Override
86 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
87 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
88 | if (imageAttrs == null) return;
89 | int width = MeasureSpec.getSize(widthMeasureSpec);
90 | int height = 0;
91 | int totalWidth = width - getPaddingLeft() - getPaddingRight();
92 | if (imageAttrs.size() == 1) {
93 | gridWidth = singleImageWidth;
94 | gridHeight = singleImageHeight;
95 | } else {
96 | gridWidth = gridHeight = (totalWidth - gridSpacing * 2) / 3;
97 | }
98 | width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight();
99 | height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom();
100 | setMeasuredDimension(width, height);
101 | }
102 |
103 | @Override
104 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
105 | layoutChildrenView();
106 | }
107 |
108 | private void layoutChildrenView() {
109 | if (imageAttrs == null) return;
110 | int childrenCount = imageAttrs.size();
111 | for (int i = 0; i < childrenCount; i++) {
112 | ImageView imageView = (ImageView) getChildAt(i);
113 | ImageAttr imageAttr = imageAttrs.get(i);
114 | if (imageView == null) continue;
115 |
116 | int rowNum = i / columnCount;
117 | int columnNum = i % columnCount;
118 | int left = (gridWidth + gridSpacing) * columnNum + getPaddingLeft();
119 | int top = (gridHeight + gridSpacing) * rowNum + getPaddingTop();
120 | int right = left + gridWidth;
121 | int bottom = top + gridHeight;
122 | imageView.layout(left, top, right, bottom);
123 |
124 | loadImage(imageView, imageAttr, childrenCount);
125 | }
126 | }
127 |
128 | private void loadImage(ImageView imageView, ImageAttr attr, final int count) {
129 | String url = TextUtils.isEmpty(attr.thumbnailUrl) ? attr.url : attr.thumbnailUrl;
130 | GlideImageLoader imageLoader = GlideImageLoader.create(imageView);
131 |
132 | RequestOptions requestOptions = imageLoader.requestOptions(R.color.placeholder_color)
133 | .centerCrop()
134 | .skipMemoryCache(false)
135 | .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
136 | .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
137 |
138 | imageLoader.requestBuilder(url, requestOptions)
139 | .transition(DrawableTransitionOptions.withCrossFade())
140 | .listener(new RequestListener() {
141 | @Override
142 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
143 | return false;
144 | }
145 |
146 | @Override
147 | public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
148 | if (count == 1) {
149 | setSingleImageWidthHeight(resource);
150 | }
151 | return false;
152 | }
153 | }).into(imageView);
154 | }
155 |
156 | private void setSingleImageWidthHeight(Drawable drawable) {
157 | if (drawable == null) return;
158 | int width = drawable.getIntrinsicWidth();
159 | int height = drawable.getIntrinsicHeight();
160 | float ratio = width * 1.0f / height;
161 |
162 | if (width > singleImageMaxWidth || ratio > 2.1f) {
163 | singleImageWidth = singleImageMaxWidth;
164 | singleImageHeight = (int) (singleImageMaxWidth * height * 1.0f / width);
165 | } else if (width < singleImageMinWidth || ratio < 0.7f) {
166 | if (ratio < 0.3f) {
167 | singleImageWidth = singleImageMinWidth / 2;
168 | singleImageHeight = (int) (singleImageMinWidth / 2 * height * 1.0f / width);
169 | if (singleImageHeight > singleImageMaxWidth) {
170 | singleImageHeight = singleImageMaxWidth;
171 | }
172 | } else {
173 | singleImageWidth = singleImageMinWidth;
174 | singleImageHeight = (int) (singleImageMinWidth * height * 1.0f / width);
175 | }
176 | } else {
177 | singleImageWidth = width;
178 | singleImageHeight = height;
179 | }
180 | }
181 |
182 | public void setAdapter(@NonNull NineImageViewAdapter adapter) {
183 | this.mAdapter = adapter;
184 | List attrList = adapter.getImageAttrs();
185 | if (attrList == null || attrList.isEmpty()) {
186 | setVisibility(GONE);
187 | return;
188 | }
189 | setVisibility(VISIBLE);
190 |
191 | int imageCount = attrList.size();
192 | if (maxImageSize > 0 && imageCount > maxImageSize) {
193 | attrList = attrList.subList(0, maxImageSize);
194 | imageCount = attrList.size(); // 再次获取图片数量
195 | }
196 |
197 | // 默认是3列显示,行数根据图片的数量决定
198 | rowCount = imageCount / 3 + (imageCount % 3 == 0 ? 0 : 1);
199 | columnCount = 3;
200 | // Grid模式下,显示4张使用2X2模式
201 | if (mode == MODE_GRID) {
202 | if (imageCount == 4) {
203 | rowCount = 2;
204 | columnCount = 2;
205 | }
206 | }
207 |
208 | // 保证View的复用,避免重复创建
209 | if (imageAttrs == null) {
210 | for (int i = 0; i < imageCount; i++) {
211 | ImageView imageView = getImageView(i);
212 | addView(imageView, generateDefaultLayoutParams());
213 | }
214 | } else {
215 | int oldViewCount = imageAttrs.size();
216 | if (oldViewCount > imageCount) {
217 | removeViews(imageCount, oldViewCount - imageCount);
218 | } else if (oldViewCount < imageCount) {
219 | for (int i = oldViewCount; i < imageCount; i++) {
220 | ImageView imageView = getImageView(i);
221 | addView(imageView, generateDefaultLayoutParams());
222 | }
223 | }
224 | }
225 |
226 | // 修改最后一个条目,决定是否显示更多
227 | if (adapter.getImageAttrs().size() > maxImageSize) {
228 | View child = getChildAt(maxImageSize - 1);
229 | if (child instanceof ImageViewWrapper) {
230 | ImageViewWrapper imageView = (ImageViewWrapper) child;
231 | imageView.setMoreNum(adapter.getImageAttrs().size() - maxImageSize);
232 | }
233 | }
234 | imageAttrs = attrList;
235 | layoutChildrenView();
236 | }
237 |
238 | // 获得ImageView,并保证ImageView的重用
239 | private ImageView getImageView(final int position) {
240 | ImageView imageView = null;
241 | if (position < imageViews.size()) {
242 | imageView = imageViews.get(position);
243 | }
244 | if (imageView == null) {
245 | imageView = mAdapter.generateImageView(getContext());
246 | imageView.setOnClickListener(
247 | new OnClickListener() {
248 | @Override
249 | public void onClick(View view) {
250 | mAdapter.onImageItemClick(getContext(), NineImageView.this, position, mAdapter.getImageAttrs());
251 | }
252 | });
253 | imageViews.add(imageView);
254 | }
255 | return imageView;
256 | }
257 |
258 | public NineImageViewAdapter getAdapter() {
259 | return mAdapter;
260 | }
261 |
262 | public void setGridSpacing(int spacing) {
263 | gridSpacing = spacing;
264 | }
265 |
266 | public void setMaxSize(int maxSize) {
267 | maxImageSize = maxSize;
268 | }
269 |
270 | public int getMaxSize() {
271 | return maxImageSize;
272 | }
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
19 |
20 |
25 |
26 |
33 |
34 |
41 |
42 |
49 |
50 |
57 |
58 |
59 |
64 |
65 |
77 |
78 |
91 |
92 |
104 |
105 |
117 |
118 |
119 |
124 |
125 |
131 |
132 |
140 |
141 |
148 |
149 |
158 |
159 |
160 |
164 |
165 |
174 |
175 |
184 |
185 |
200 |
201 |
202 |
211 |
212 |
221 |
222 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
248 |
249 |
260 |
261 |
--------------------------------------------------------------------------------
/GlideImageView/src/main/java/com/sunfusheng/glideimageview/progress/CircleProgressView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.glideimageview.progress;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.os.Bundle;
11 | import android.os.Parcelable;
12 | import android.support.annotation.IntDef;
13 | import android.util.AttributeSet;
14 | import android.view.animation.AccelerateDecelerateInterpolator;
15 | import android.widget.ProgressBar;
16 |
17 | import com.sunfusheng.glideimageview.R;
18 | import com.sunfusheng.glideimageview.util.DisplayUtil;
19 |
20 | import java.lang.annotation.Retention;
21 | import java.lang.annotation.RetentionPolicy;
22 |
23 | public class CircleProgressView extends ProgressBar {
24 |
25 | private int mReachBarSize = DisplayUtil.dip2px(getContext(), 2); // 未完成进度条大小
26 | private int mNormalBarSize = DisplayUtil.dip2px(getContext(), 2); // 未完成进度条大小
27 | private int mReachBarColor = Color.parseColor("#108ee9"); // 已完成进度颜色
28 | private int mNormalBarColor = Color.parseColor("#FFD3D6DA"); // 未完成进度颜色
29 | private int mTextSize = DisplayUtil.sp2px(getContext(), 14); // 进度值字体大小
30 | private int mTextColor = Color.parseColor("#108ee9"); // 进度的值字体颜色
31 | private float mTextSkewX; // 进度值字体倾斜角度
32 | private String mTextSuffix = "%"; // 进度值前缀
33 | private String mTextPrefix = ""; // 进度值后缀
34 | private boolean mTextVisible = true; // 是否显示进度值
35 | private boolean mReachCapRound; // 画笔是否使用圆角边界,normalStyle下生效
36 | private int mRadius = DisplayUtil.dip2px(getContext(), 20); // 半径
37 | private int mStartArc; // 起始角度
38 | private int mInnerBackgroundColor; // 内部背景填充颜色
39 | private int mProgressStyle = ProgressStyle.NORMAL; // 进度风格
40 | private int mInnerPadding = DisplayUtil.dip2px(getContext(), 1); // 内部圆与外部圆间距
41 | private int mOuterColor; // 外部圆环颜色
42 | private boolean needDrawInnerBackground; // 是否需要绘制内部背景
43 | private RectF rectF; // 外部圆环绘制区域
44 | private RectF rectInner; // 内部圆环绘制区域
45 | private int mOuterSize = DisplayUtil.dip2px(getContext(), 1); // 外层圆环宽度
46 | private Paint mTextPaint; // 绘制进度值字体画笔
47 | private Paint mNormalPaint; // 绘制未完成进度画笔
48 | private Paint mReachPaint; // 绘制已完成进度画笔
49 | private Paint mInnerBackgroundPaint; // 内部背景画笔
50 | private Paint mOutPaint; // 外部圆环画笔
51 |
52 | private int mRealWidth;
53 | private int mRealHeight;
54 |
55 | @IntDef({ProgressStyle.NORMAL, ProgressStyle.FILL_IN, ProgressStyle.FILL_IN_ARC})
56 | @Retention(RetentionPolicy.SOURCE)
57 | public @interface ProgressStyle {
58 | int NORMAL = 0;
59 | int FILL_IN = 1;
60 | int FILL_IN_ARC = 2;
61 | }
62 |
63 | public CircleProgressView(Context context) {
64 | this(context, null);
65 | }
66 |
67 | public CircleProgressView(Context context, AttributeSet attrs) {
68 | this(context, attrs, 0);
69 | }
70 |
71 | public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
72 | super(context, attrs, defStyleAttr);
73 | obtainAttributes(attrs);
74 | initPaint();
75 | }
76 |
77 | private void initPaint() {
78 | mTextPaint = new Paint();
79 | mTextPaint.setColor(mTextColor);
80 | mTextPaint.setStyle(Paint.Style.FILL);
81 | mTextPaint.setTextSize(mTextSize);
82 | mTextPaint.setTextSkewX(mTextSkewX);
83 | mTextPaint.setAntiAlias(true);
84 |
85 | mNormalPaint = new Paint();
86 | mNormalPaint.setColor(mNormalBarColor);
87 | mNormalPaint.setStyle(mProgressStyle == ProgressStyle.FILL_IN_ARC ? Paint.Style.FILL : Paint.Style.STROKE);
88 | mNormalPaint.setAntiAlias(true);
89 | mNormalPaint.setStrokeWidth(mNormalBarSize);
90 |
91 | mReachPaint = new Paint();
92 | mReachPaint.setColor(mReachBarColor);
93 | mReachPaint.setStyle(mProgressStyle == ProgressStyle.FILL_IN_ARC ? Paint.Style.FILL : Paint.Style.STROKE);
94 | mReachPaint.setAntiAlias(true);
95 | mReachPaint.setStrokeCap(mReachCapRound ? Paint.Cap.ROUND : Paint.Cap.BUTT);
96 | mReachPaint.setStrokeWidth(mReachBarSize);
97 |
98 | if (needDrawInnerBackground) {
99 | mInnerBackgroundPaint = new Paint();
100 | mInnerBackgroundPaint.setStyle(Paint.Style.FILL);
101 | mInnerBackgroundPaint.setAntiAlias(true);
102 | mInnerBackgroundPaint.setColor(mInnerBackgroundColor);
103 | }
104 | if (mProgressStyle == ProgressStyle.FILL_IN_ARC) {
105 | mOutPaint = new Paint();
106 | mOutPaint.setStyle(Paint.Style.STROKE);
107 | mOutPaint.setColor(mOuterColor);
108 | mOutPaint.setStrokeWidth(mOuterSize);
109 | mOutPaint.setAntiAlias(true);
110 | }
111 | }
112 |
113 | private void obtainAttributes(AttributeSet attrs) {
114 | TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CircleProgressView);
115 | mProgressStyle = ta.getInt(R.styleable.CircleProgressView_cpv_progressStyle, ProgressStyle.NORMAL);
116 | // 获取三种风格通用的属性
117 | mNormalBarSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_progressNormalSize, mNormalBarSize);
118 | mNormalBarColor = ta.getColor(R.styleable.CircleProgressView_cpv_progressNormalColor, mNormalBarColor);
119 |
120 | mReachBarSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_progressReachSize, mReachBarSize);
121 | mReachBarColor = ta.getColor(R.styleable.CircleProgressView_cpv_progressReachColor, mReachBarColor);
122 |
123 | mTextSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_progressTextSize, mTextSize);
124 | mTextColor = ta.getColor(R.styleable.CircleProgressView_cpv_progressTextColor, mTextColor);
125 | mTextSkewX = ta.getDimension(R.styleable.CircleProgressView_cpv_progressTextSkewX, 0);
126 | if (ta.hasValue(R.styleable.CircleProgressView_cpv_progressTextSuffix)) {
127 | mTextSuffix = ta.getString(R.styleable.CircleProgressView_cpv_progressTextSuffix);
128 | }
129 | if (ta.hasValue(R.styleable.CircleProgressView_cpv_progressTextPrefix)) {
130 | mTextPrefix = ta.getString(R.styleable.CircleProgressView_cpv_progressTextPrefix);
131 | }
132 | mTextVisible = ta.getBoolean(R.styleable.CircleProgressView_cpv_progressTextVisible, mTextVisible);
133 |
134 | mRadius = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_radius, mRadius);
135 | rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
136 |
137 | switch (mProgressStyle) {
138 | case ProgressStyle.FILL_IN:
139 | mReachBarSize = 0;
140 | mNormalBarSize = 0;
141 | mOuterSize = 0;
142 | break;
143 | case ProgressStyle.FILL_IN_ARC:
144 | mStartArc = ta.getInt(R.styleable.CircleProgressView_cpv_progressStartArc, 0) + 270;
145 | mInnerPadding = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_innerPadding, mInnerPadding);
146 | mOuterColor = ta.getColor(R.styleable.CircleProgressView_cpv_outerColor, mReachBarColor);
147 | mOuterSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_outerSize, mOuterSize);
148 | mReachBarSize = 0;// 将画笔大小重置为0
149 | mNormalBarSize = 0;
150 | if (!ta.hasValue(R.styleable.CircleProgressView_cpv_progressNormalColor)) {
151 | mNormalBarColor = Color.TRANSPARENT;
152 | }
153 | int mInnerRadius = mRadius - mOuterSize / 2 - mInnerPadding;
154 | rectInner = new RectF(-mInnerRadius, -mInnerRadius, mInnerRadius, mInnerRadius);
155 |
156 | break;
157 | case ProgressStyle.NORMAL:
158 | mReachCapRound = ta.getBoolean(R.styleable.CircleProgressView_cpv_reachCapRound, true);
159 | mStartArc = ta.getInt(R.styleable.CircleProgressView_cpv_progressStartArc, 0) + 270;
160 | if (ta.hasValue(R.styleable.CircleProgressView_cpv_innerBackgroundColor)) {
161 | mInnerBackgroundColor = ta.getColor(R.styleable.CircleProgressView_cpv_innerBackgroundColor, Color.argb(0, 0, 0, 0));
162 | needDrawInnerBackground = true;
163 | }
164 | break;
165 | }
166 | ta.recycle();
167 | }
168 |
169 | @Override
170 | protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
171 | int maxBarPaintWidth = Math.max(mReachBarSize, mNormalBarSize);
172 | int maxPaintWidth = Math.max(maxBarPaintWidth, mOuterSize);
173 | int height = 0;
174 | int width = 0;
175 | switch (mProgressStyle) {
176 | case ProgressStyle.FILL_IN:
177 | height = getPaddingTop() + getPaddingBottom() // 边距
178 | + Math.abs(mRadius * 2); // 直径
179 | width = getPaddingLeft() + getPaddingRight() // 边距
180 | + Math.abs(mRadius * 2); // 直径
181 | break;
182 | case ProgressStyle.FILL_IN_ARC:
183 | height = getPaddingTop() + getPaddingBottom() // 边距
184 | + Math.abs(mRadius * 2) // 直径
185 | + maxPaintWidth;// 边框
186 | width = getPaddingLeft() + getPaddingRight() // 边距
187 | + Math.abs(mRadius * 2) // 直径
188 | + maxPaintWidth;// 边框
189 | break;
190 | case ProgressStyle.NORMAL:
191 | height = getPaddingTop() + getPaddingBottom() // 边距
192 | + Math.abs(mRadius * 2) // 直径
193 | + maxBarPaintWidth;// 边框
194 | width = getPaddingLeft() + getPaddingRight() // 边距
195 | + Math.abs(mRadius * 2) // 直径
196 | + maxBarPaintWidth;// 边框
197 | break;
198 | }
199 |
200 | mRealWidth = resolveSize(width, widthMeasureSpec);
201 | mRealHeight = resolveSize(height, heightMeasureSpec);
202 |
203 | setMeasuredDimension(mRealWidth, mRealHeight);
204 | }
205 |
206 | @Override
207 | protected synchronized void onDraw(Canvas canvas) {
208 | switch (mProgressStyle) {
209 | case ProgressStyle.NORMAL:
210 | drawNormalCircle(canvas);
211 | break;
212 | case ProgressStyle.FILL_IN:
213 | drawFillInCircle(canvas);
214 | break;
215 | case ProgressStyle.FILL_IN_ARC:
216 | drawFillInArcCircle(canvas);
217 | break;
218 | }
219 | }
220 |
221 | /**
222 | * 绘制PROGRESS_STYLE_FILL_IN_ARC圆形
223 | */
224 | private void drawFillInArcCircle(Canvas canvas) {
225 | canvas.save();
226 | canvas.translate(mRealWidth / 2, mRealHeight / 2);
227 | // 绘制外层圆环
228 | canvas.drawArc(rectF, 0, 360, false, mOutPaint);
229 | // 绘制内层进度实心圆弧
230 | // 内层圆弧半径
231 | float reachArc = getProgress() * 1.0f / getMax() * 360;
232 | canvas.drawArc(rectInner, mStartArc, reachArc, true, mReachPaint);
233 |
234 | // 绘制未到达进度
235 | if (reachArc != 360) {
236 | canvas.drawArc(rectInner, reachArc + mStartArc, 360 - reachArc, true, mNormalPaint);
237 | }
238 |
239 | canvas.restore();
240 | }
241 |
242 | /**
243 | * 绘制PROGRESS_STYLE_FILL_IN圆形
244 | */
245 | private void drawFillInCircle(Canvas canvas) {
246 | canvas.save();
247 | canvas.translate(mRealWidth / 2, mRealHeight / 2);
248 | float progressY = getProgress() * 1.0f / getMax() * (mRadius * 2);
249 | float angle = (float) (Math.acos((mRadius - progressY) / mRadius) * 180 / Math.PI);
250 | float startAngle = 90 + angle;
251 | float sweepAngle = 360 - angle * 2;
252 | // 绘制未到达区域
253 | rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
254 | mNormalPaint.setStyle(Paint.Style.FILL);
255 | canvas.drawArc(rectF, startAngle, sweepAngle, false, mNormalPaint);
256 | // 翻转180度绘制已到达区域
257 | canvas.rotate(180);
258 | mReachPaint.setStyle(Paint.Style.FILL);
259 | canvas.drawArc(rectF, 270 - angle, angle * 2, false, mReachPaint);
260 | // 文字显示在最上层最后绘制
261 | canvas.rotate(180);
262 | // 绘制文字
263 | if (mTextVisible) {
264 | String text = mTextPrefix + getProgress() + mTextSuffix;
265 | float textWidth = mTextPaint.measureText(text);
266 | float textHeight = (mTextPaint.descent() + mTextPaint.ascent());
267 | canvas.drawText(text, -textWidth / 2, -textHeight / 2, mTextPaint);
268 | }
269 | }
270 |
271 | /**
272 | * 绘制PROGRESS_STYLE_NORMAL圆形
273 | */
274 | private void drawNormalCircle(Canvas canvas) {
275 | canvas.save();
276 | canvas.translate(mRealWidth / 2, mRealHeight / 2);
277 | // 绘制内部圆形背景色
278 | if (needDrawInnerBackground) {
279 | canvas.drawCircle(0, 0, mRadius - Math.min(mReachBarSize, mNormalBarSize) / 2,
280 | mInnerBackgroundPaint);
281 | }
282 | // 绘制文字
283 | if (mTextVisible) {
284 | String text = mTextPrefix + getProgress() + mTextSuffix;
285 | float textWidth = mTextPaint.measureText(text);
286 | float textHeight = (mTextPaint.descent() + mTextPaint.ascent());
287 | canvas.drawText(text, -textWidth / 2, -textHeight / 2, mTextPaint);
288 | }
289 | // 计算进度值
290 | float reachArc = getProgress() * 1.0f / getMax() * 360;
291 | // 绘制未到达进度
292 | if (reachArc != 360) {
293 | canvas.drawArc(rectF, reachArc + mStartArc, 360 - reachArc, false, mNormalPaint);
294 | }
295 | // 绘制已到达进度
296 | canvas.drawArc(rectF, mStartArc, reachArc, false, mReachPaint);
297 | canvas.restore();
298 | }
299 |
300 | /**
301 | * 动画进度(0-当前进度)
302 | *
303 | * @param duration 动画时长
304 | */
305 | public void runProgressAnim(long duration) {
306 | setProgressInTime(0, duration);
307 | }
308 |
309 | /**
310 | * @param progress 进度值
311 | * @param duration 动画播放时间
312 | */
313 | public void setProgressInTime(final int progress, final long duration) {
314 | setProgressInTime(progress, getProgress(), duration);
315 | }
316 |
317 | /**
318 | * @param startProgress 起始进度
319 | * @param progress 进度值
320 | * @param duration 动画播放时间
321 | */
322 | public void setProgressInTime(int startProgress, final int progress, final long duration) {
323 | ValueAnimator valueAnimator = ValueAnimator.ofInt(startProgress, progress);
324 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
325 |
326 | @Override
327 | public void onAnimationUpdate(ValueAnimator animator) {
328 | //获得当前动画的进度值,整型,1-100之间
329 | int currentValue = (Integer) animator.getAnimatedValue();
330 | setProgress(currentValue);
331 | }
332 | });
333 | AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
334 | valueAnimator.setInterpolator(interpolator);
335 | valueAnimator.setDuration(duration);
336 | valueAnimator.start();
337 | }
338 |
339 | public int getReachBarSize() {
340 | return mReachBarSize;
341 | }
342 |
343 | public void setReachBarSize(int reachBarSize) {
344 | mReachBarSize = DisplayUtil.dip2px(getContext(), reachBarSize);
345 | invalidate();
346 | }
347 |
348 | public int getNormalBarSize() {
349 | return mNormalBarSize;
350 | }
351 |
352 | public void setNormalBarSize(int normalBarSize) {
353 | mNormalBarSize = DisplayUtil.dip2px(getContext(), normalBarSize);
354 | invalidate();
355 | }
356 |
357 | public int getReachBarColor() {
358 | return mReachBarColor;
359 | }
360 |
361 | public void setReachBarColor(int reachBarColor) {
362 | mReachBarColor = reachBarColor;
363 | invalidate();
364 | }
365 |
366 | public int getNormalBarColor() {
367 | return mNormalBarColor;
368 | }
369 |
370 | public void setNormalBarColor(int normalBarColor) {
371 | mNormalBarColor = normalBarColor;
372 | invalidate();
373 | }
374 |
375 | public int getTextSize() {
376 | return mTextSize;
377 | }
378 |
379 | public void setTextSize(int textSize) {
380 | mTextSize = DisplayUtil.sp2px(getContext(), textSize);
381 | invalidate();
382 | }
383 |
384 | public int getTextColor() {
385 | return mTextColor;
386 | }
387 |
388 | public void setTextColor(int textColor) {
389 | mTextColor = textColor;
390 | invalidate();
391 | }
392 |
393 | public float getTextSkewX() {
394 | return mTextSkewX;
395 | }
396 |
397 | public void setTextSkewX(float textSkewX) {
398 | mTextSkewX = textSkewX;
399 | invalidate();
400 | }
401 |
402 | public String getTextSuffix() {
403 | return mTextSuffix;
404 | }
405 |
406 | public void setTextSuffix(String textSuffix) {
407 | mTextSuffix = textSuffix;
408 | invalidate();
409 | }
410 |
411 | public String getTextPrefix() {
412 | return mTextPrefix;
413 | }
414 |
415 | public void setTextPrefix(String textPrefix) {
416 | mTextPrefix = textPrefix;
417 | invalidate();
418 | }
419 |
420 | public boolean isTextVisible() {
421 | return mTextVisible;
422 | }
423 |
424 | public void setTextVisible(boolean textVisible) {
425 | mTextVisible = textVisible;
426 | invalidate();
427 | }
428 |
429 | public boolean isReachCapRound() {
430 | return mReachCapRound;
431 | }
432 |
433 | public void setReachCapRound(boolean reachCapRound) {
434 | mReachCapRound = reachCapRound;
435 | invalidate();
436 | }
437 |
438 | public int getRadius() {
439 | return mRadius;
440 | }
441 |
442 | public void setRadius(int radius) {
443 | mRadius = DisplayUtil.dip2px(getContext(), radius);
444 | invalidate();
445 | }
446 |
447 | public int getStartArc() {
448 | return mStartArc;
449 | }
450 |
451 | public void setStartArc(int startArc) {
452 | mStartArc = startArc;
453 | invalidate();
454 | }
455 |
456 | public int getInnerBackgroundColor() {
457 | return mInnerBackgroundColor;
458 | }
459 |
460 | public void setInnerBackgroundColor(int innerBackgroundColor) {
461 | mInnerBackgroundColor = innerBackgroundColor;
462 | invalidate();
463 | }
464 |
465 | public int getProgressStyle() {
466 | return mProgressStyle;
467 | }
468 |
469 | public void setProgressStyle(int progressStyle) {
470 | mProgressStyle = progressStyle;
471 | invalidate();
472 | }
473 |
474 | public int getInnerPadding() {
475 | return mInnerPadding;
476 | }
477 |
478 | public void setInnerPadding(int innerPadding) {
479 | mInnerPadding = DisplayUtil.dip2px(getContext(), innerPadding);
480 | int mInnerRadius = mRadius - mOuterSize / 2 - mInnerPadding;
481 | rectInner = new RectF(-mInnerRadius, -mInnerRadius, mInnerRadius, mInnerRadius);
482 | invalidate();
483 | }
484 |
485 | public int getOuterColor() {
486 | return mOuterColor;
487 | }
488 |
489 | public void setOuterColor(int outerColor) {
490 | mOuterColor = outerColor;
491 | invalidate();
492 | }
493 |
494 | public int getOuterSize() {
495 | return mOuterSize;
496 | }
497 |
498 | public void setOuterSize(int outerSize) {
499 | mOuterSize = DisplayUtil.dip2px(getContext(), outerSize);
500 | invalidate();
501 | }
502 |
503 | private static final String STATE = "state";
504 | private static final String PROGRESS_STYLE = "progressStyle";
505 | private static final String TEXT_COLOR = "textColor";
506 | private static final String TEXT_SIZE = "textSize";
507 | private static final String TEXT_SKEW_X = "textSkewX";
508 | private static final String TEXT_VISIBLE = "textVisible";
509 | private static final String TEXT_SUFFIX = "textSuffix";
510 | private static final String TEXT_PREFIX = "textPrefix";
511 | private static final String REACH_BAR_COLOR = "reachBarColor";
512 | private static final String REACH_BAR_SIZE = "reachBarSize";
513 | private static final String NORMAL_BAR_COLOR = "normalBarColor";
514 | private static final String NORMAL_BAR_SIZE = "normalBarSize";
515 | private static final String IS_REACH_CAP_ROUND = "isReachCapRound";
516 | private static final String RADIUS = "radius";
517 | private static final String START_ARC = "startArc";
518 | private static final String INNER_BG_COLOR = "innerBgColor";
519 | private static final String INNER_PADDING = "innerPadding";
520 | private static final String OUTER_COLOR = "outerColor";
521 | private static final String OUTER_SIZE = "outerSize";
522 |
523 | @Override
524 | public Parcelable onSaveInstanceState() {
525 | final Bundle bundle = new Bundle();
526 | bundle.putParcelable(STATE, super.onSaveInstanceState());
527 | // 保存当前样式
528 | bundle.putInt(PROGRESS_STYLE, getProgressStyle());
529 | bundle.putInt(RADIUS, getRadius());
530 | bundle.putBoolean(IS_REACH_CAP_ROUND, isReachCapRound());
531 | bundle.putInt(START_ARC, getStartArc());
532 | bundle.putInt(INNER_BG_COLOR, getInnerBackgroundColor());
533 | bundle.putInt(INNER_PADDING, getInnerPadding());
534 | bundle.putInt(OUTER_COLOR, getOuterColor());
535 | bundle.putInt(OUTER_SIZE, getOuterSize());
536 | // 保存text信息
537 | bundle.putInt(TEXT_COLOR, getTextColor());
538 | bundle.putInt(TEXT_SIZE, getTextSize());
539 | bundle.putFloat(TEXT_SKEW_X, getTextSkewX());
540 | bundle.putBoolean(TEXT_VISIBLE, isTextVisible());
541 | bundle.putString(TEXT_SUFFIX, getTextSuffix());
542 | bundle.putString(TEXT_PREFIX, getTextPrefix());
543 | // 保存已到达进度信息
544 | bundle.putInt(REACH_BAR_COLOR, getReachBarColor());
545 | bundle.putInt(REACH_BAR_SIZE, getReachBarSize());
546 |
547 | // 保存未到达进度信息
548 | bundle.putInt(NORMAL_BAR_COLOR, getNormalBarColor());
549 | bundle.putInt(NORMAL_BAR_SIZE, getNormalBarSize());
550 | return bundle;
551 | }
552 |
553 | @Override
554 | public void onRestoreInstanceState(Parcelable state) {
555 | if (state instanceof Bundle) {
556 | final Bundle bundle = (Bundle) state;
557 |
558 | mProgressStyle = bundle.getInt(PROGRESS_STYLE);
559 | mRadius = bundle.getInt(RADIUS);
560 | mReachCapRound = bundle.getBoolean(IS_REACH_CAP_ROUND);
561 | mStartArc = bundle.getInt(START_ARC);
562 | mInnerBackgroundColor = bundle.getInt(INNER_BG_COLOR);
563 | mInnerPadding = bundle.getInt(INNER_PADDING);
564 | mOuterColor = bundle.getInt(OUTER_COLOR);
565 | mOuterSize = bundle.getInt(OUTER_SIZE);
566 |
567 | mTextColor = bundle.getInt(TEXT_COLOR);
568 | mTextSize = bundle.getInt(TEXT_SIZE);
569 | mTextSkewX = bundle.getFloat(TEXT_SKEW_X);
570 | mTextVisible = bundle.getBoolean(TEXT_VISIBLE);
571 | mTextSuffix = bundle.getString(TEXT_SUFFIX);
572 | mTextPrefix = bundle.getString(TEXT_PREFIX);
573 |
574 | mReachBarColor = bundle.getInt(REACH_BAR_COLOR);
575 | mReachBarSize = bundle.getInt(REACH_BAR_SIZE);
576 | mNormalBarColor = bundle.getInt(NORMAL_BAR_COLOR);
577 | mNormalBarSize = bundle.getInt(NORMAL_BAR_SIZE);
578 |
579 | initPaint();
580 | super.onRestoreInstanceState(bundle.getParcelable(STATE));
581 | return;
582 | }
583 | super.onRestoreInstanceState(state);
584 | }
585 |
586 | @Override
587 | public void invalidate() {
588 | initPaint();
589 | super.invalidate();
590 | }
591 | }
592 |
--------------------------------------------------------------------------------