├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── fonts
│ │ └── dincond_boldalternate.ttf
│ ├── java
│ └── com
│ │ └── fphoenixcorneae
│ │ └── smartprogressbar
│ │ └── MainActivity.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── font
│ └── arial.ttf
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── preview
└── smart_progress_bar.png
├── settings.gradle
└── smartProgressBar
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── fphoenixcorneae
│ └── progressbar
│ ├── ProgressBarLayout.kt
│ └── SmartProgressBar.kt
└── res
└── values
└── attrs.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | /.idea
15 | /.gradle
16 | /gradle
17 | /gradlew
18 | /gradlew.bat
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SmartProgressBar
2 | 漂亮的进度条,如丝般顺滑,样式风格有水平、竖直、圆环、扇形......
3 | ------------------------------------------------------------
4 |
5 |
6 |

7 |
8 |
9 | -----------------------------
10 |
11 | How to include it in your project:
12 | --------------
13 | **Step 1.** Add the JitPack repository to your build file
14 | ```groovy
15 | allprojects {
16 | repositories {
17 | ...
18 | maven { url 'https://jitpack.io' }
19 | }
20 | }
21 | ```
22 |
23 | **Step 2.** Add the dependency
24 | ```groovy
25 | dependencies {
26 | implementation 'com.github.FPhoenixCorneaE:SmartProgressBar:1.0.3'
27 | }
28 | ```
29 |
30 | xml中使用
31 | --------------
32 | `水平样式进度条`
33 | ```xml
34 |
59 | ```
60 |
61 | `竖直样式进度条`
62 | ```xml
63 |
88 | ```
89 |
90 | `圆环样式进度条`
91 | ```xml
92 |
113 | ```
114 |
115 | `扇形样式进度条`
116 | ```xml
117 |
137 | ```
138 |
139 | --------------------
140 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 | android {
6 | compileSdkVersion 30
7 | defaultConfig {
8 | applicationId "com.wkz.smartprogressbar"
9 | minSdkVersion 19
10 | targetSdkVersion 30
11 | versionCode 1
12 | versionName "1.0"
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | compileOptions {
22 | targetCompatibility JavaVersion.VERSION_1_8
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
30 | implementation 'androidx.core:core-ktx:1.3.2'
31 | implementation 'androidx.appcompat:appcompat:1.2.0'
32 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
33 | testImplementation 'junit:junit:4.13.2'
34 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
35 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
36 |
37 | // implementation 'com.github.FPhoenixCorneaE:SmartProgressBar:1.0.3'
38 | implementation project(path: ':smartProgressBar')
39 | }
40 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/dincond_boldalternate.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/assets/fonts/dincond_boldalternate.ttf
--------------------------------------------------------------------------------
/app/src/main/java/com/fphoenixcorneae/smartprogressbar/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.fphoenixcorneae.smartprogressbar
2 |
3 | import android.animation.Animator
4 | import android.animation.AnimatorListenerAdapter
5 | import android.os.Bundle
6 | import android.util.Log
7 | import androidx.appcompat.app.AppCompatActivity
8 | import kotlinx.android.synthetic.main.activity_main.*
9 |
10 | class MainActivity : AppCompatActivity() {
11 |
12 | private var isFullReduction = false
13 | private var isShowTime = false
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_main)
18 | initView()
19 | initListener()
20 | }
21 |
22 | private fun initView() {
23 | pblProgress.addProgressAnimatorUpdateListener {
24 |
25 | }
26 | pblProgress.addProgressAnimatorListener(object : AnimatorListenerAdapter() {
27 | override fun onAnimationEnd(animation: Animator?) {
28 | super.onAnimationEnd(animation)
29 | Log.i("onAnimationEnd", "onAnimationEnd")
30 | }
31 | })
32 | }
33 |
34 | private fun initListener() {
35 | btnShowTemperatureText.setOnClickListener {
36 | isShowTime = false
37 | var beginTemperature = when (isFullReduction) {
38 | true -> 100f
39 | else -> 80f
40 | }
41 | val endTemperature = when (isFullReduction) {
42 | true -> 80f
43 | else -> 100f
44 | }
45 | when {
46 | isFullReduction -> {
47 | pblProgress.mSmartProgressBar.setProgressWithNoAnimation(0f)
48 | pblProgress.mSmartProgressBar.setIsAnimated(true)
49 | it.postDelayed({
50 | beginTemperature = 99f
51 | pblProgress.setTemperatureText(beginTemperature, endTemperature)
52 | }, 3000)
53 | }
54 | else -> {
55 | pblProgress.mSmartProgressBar.setIsAnimated(false)
56 | }
57 | }
58 | pblProgress.setTemperatureText(beginTemperature, endTemperature)
59 | }
60 | btnShowTimeText.setOnClickListener {
61 | isShowTime = true
62 | pblProgress.setTimeText(60, isFullReduction)
63 | }
64 | btnTurnDirection.setOnClickListener {
65 | isFullReduction = !isFullReduction
66 | when (isShowTime) {
67 | true -> {
68 | btnShowTimeText.performClick()
69 | }
70 | else -> {
71 | btnShowTemperatureText.performClick()
72 | }
73 | }
74 | }
75 | btnPause.setOnClickListener {
76 | pblProgress.pauseProgressAnimation()
77 | }
78 | btnResume.setOnClickListener {
79 | pblProgress.resumeProgressAnimation()
80 | }
81 | btnCancel.setOnClickListener {
82 | pblProgress.cancelProgressAnimation()
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/font/arial.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/font/arial.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
37 |
38 |
44 |
45 |
66 |
67 |
92 |
93 |
115 |
116 |
117 |
123 |
124 |
144 |
145 |
167 |
168 |
169 |
172 |
173 |
213 |
214 |
228 |
229 |
243 |
244 |
258 |
259 |
273 |
274 |
288 |
289 |
303 |
304 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - #ff0000
5 | - #ff0000
6 | - #ffff00
7 | - #00aa00
8 | - #00ffff
9 | - #0000ff
10 | - #0000ff
11 |
12 |
13 | - 0
14 | - 10
15 | - 30
16 | - 45
17 | - 65
18 | - 85
19 | - 100
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 | #000000
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SmartProgressBar
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.4.32'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:4.1.3'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | maven {
24 | url "https://jitpack.io"
25 | }
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | org.gradle.jvmargs=-Xmx1536m
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 |
17 | #systemProp.http.proxyHost=127.0.0.1
18 | #systemProp.http.proxyPort=8580
19 | #systemProp.https.proxyHost=127.0.0.1
20 | #systemProp.https.proxyPort=8580
21 |
22 |
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat May 01 08:41:23 CST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/preview/smart_progress_bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/preview/smart_progress_bar.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':smartProgressBar'
3 |
--------------------------------------------------------------------------------
/smartProgressBar/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/smartProgressBar/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'com.github.dcendents.android-maven'
4 | group = 'com.github.FPhoenixCorneaE'
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.3"
9 |
10 | defaultConfig {
11 | minSdkVersion 19
12 | targetSdkVersion 30
13 | versionCode 103
14 | versionName "1.0.3"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles 'consumer-rules.pro'
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 |
27 | compileOptions {
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | }
31 |
32 | kotlinOptions {
33 | jvmTarget = JavaVersion.VERSION_1_8.toString()
34 | }
35 |
36 | lintOptions {
37 | checkReleaseBuilds false
38 | abortOnError false
39 | }
40 | }
41 |
42 | dependencies {
43 | compileOnly fileTree(dir: 'libs', include: ['*.jar'])
44 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
45 | compileOnly 'androidx.appcompat:appcompat:1.2.0'
46 | compileOnly 'androidx.core:core-ktx:1.3.2'
47 | }
48 |
49 | //添加以下配置,否则上传后的jar包看不到注释-------------------------------------------------------------
50 |
51 | // 指定编码
52 | tasks.withType(JavaCompile) {
53 | options.encoding = "UTF-8"
54 | }
55 | // 打包源码
56 | task sourcesJar(type: Jar) {
57 | from android.sourceSets.main.java.srcDirs
58 | classifier = 'sources'
59 | }
60 | task javadoc(type: Javadoc) {
61 | failOnError false
62 | source = android.sourceSets.main.java.sourceFiles
63 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
64 | classpath += configurations.compile
65 | }
66 | // 制作文档(Javadoc)
67 | task javadocJar(type: Jar, dependsOn: javadoc) {
68 | classifier = 'javadoc'
69 | from javadoc.destinationDir
70 | }
71 | artifacts {
72 | archives sourcesJar
73 | archives javadocJar
74 | }
75 |
--------------------------------------------------------------------------------
/smartProgressBar/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FPhoenixCorneaE/SmartProgressBar/357c47cd95d17ba5ec1e162cd410406f2eb1043a/smartProgressBar/consumer-rules.pro
--------------------------------------------------------------------------------
/smartProgressBar/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/smartProgressBar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/smartProgressBar/src/main/java/com/fphoenixcorneae/progressbar/ProgressBarLayout.kt:
--------------------------------------------------------------------------------
1 | package com.fphoenixcorneae.progressbar
2 |
3 | import android.animation.Animator
4 | import android.animation.ValueAnimator
5 | import android.annotation.SuppressLint
6 | import android.content.Context
7 | import android.util.AttributeSet
8 | import android.util.Log
9 | import android.view.Gravity
10 | import android.view.View
11 | import android.widget.FrameLayout
12 | import android.widget.RelativeLayout
13 | import android.widget.TextView
14 | import androidx.core.content.res.ResourcesCompat
15 | import com.fphoenixcorneae.progressbar.SmartProgressBar.ShapeStyle
16 | import java.text.SimpleDateFormat
17 | import java.util.*
18 |
19 | /**
20 | * 进度条布局
21 | *
22 | * @author wkz
23 | * @date 2019-12-09 09:20
24 | */
25 | class ProgressBarLayout @JvmOverloads constructor(
26 | context: Context,
27 | attrs: AttributeSet? = null
28 | ) : FrameLayout(context, attrs) {
29 | lateinit var mSmartProgressBar: SmartProgressBar
30 | private var mRlTemperatureParent: RelativeLayout? = null
31 | private var mTvTemperature: TextView? = null
32 | private var mTvTemperatureUnit: TextView? = null
33 | private var mTvTime: TextView? = null
34 | private var mProgressBarBgColor = 0
35 | private var mProgressBarBgGradient = false
36 | private var mProgressBarBgAlpha = 0f
37 | private var mProgressStartColor = 0
38 | private var mProgressCenterColor = 0
39 | private var mProgressEndColor = 0
40 | private var mProgressColorsResId = 0
41 | private var mProgressPositionsResId = 0
42 | private var mClockwise = false
43 | private var mRadius = 0f
44 | private var mProgressMax = 100f
45 | private var mProgress = 0f
46 | private var mTemperature = 0
47 | private var mTemperatureTextSize = 0f
48 | private var mTemperatureTextColor = 0
49 | private var mTemperatureTextBold = false
50 | private var mTemperatureTextFontFamily = 0
51 | private var mTemperatureUnitTextSize = 0f
52 | private var mTemperatureUnitTextColor = 0
53 | private var mTemperatureUnitTextBold = false
54 | private var mTemperatureUnitResId = 0
55 | private var mTemperatureUnitHeight = 0f
56 | private var mTemperatureUnitLeftMargin = 0f
57 | private var mTemperatureUnitTopMargin = 0f
58 | private var mTime = 0
59 | private var mTimeHhmmssTextSize = 0f
60 | private var mTimeMmssTextSize = 0f
61 | private var mTimeTextColor = 0
62 | private var mTimeTextBold = false
63 | private var mTimeTextFontFamily = 0
64 | private var mProgressBarWidth = 0f
65 | private var mProgressBarHeight = 0f
66 | private var mShowTemperatureText = false
67 | private var mShowTimeText = false
68 | private var mShowShadow = true
69 |
70 | private fun initAttributes(
71 | context: Context,
72 | attrs: AttributeSet?
73 | ) {
74 | if (attrs != null) {
75 | val attributes =
76 | context.theme.obtainStyledAttributes(
77 | attrs,
78 | R.styleable.ProgressBarLayout,
79 | 0,
80 | 0
81 | )
82 | try {
83 | mProgressBarWidth = attributes.getDimension(
84 | R.styleable.ProgressBarLayout_pbl_progress_bar_width,
85 | 580f
86 | )
87 | mProgressBarHeight = attributes.getDimension(
88 | R.styleable.ProgressBarLayout_pbl_progress_bar_height,
89 | 580f
90 | )
91 | mProgressBarBgColor = attributes.getColor(
92 | R.styleable.ProgressBarLayout_pbl_progress_bar_bg_color,
93 | 0
94 | )
95 | mProgressBarBgGradient = attributes.getBoolean(
96 | R.styleable.ProgressBarLayout_pbl_progress_bar_bg_gradient,
97 | false
98 | )
99 | mProgressBarBgAlpha = attributes.getFloat(
100 | R.styleable.ProgressBarLayout_pbl_progress_bar_bg_alpha,
101 | 1f
102 | )
103 | mProgressStartColor = attributes.getColor(
104 | R.styleable.ProgressBarLayout_pbl_progress_start_color,
105 | 0
106 | )
107 | mProgressCenterColor = attributes.getColor(
108 | R.styleable.ProgressBarLayout_pbl_progress_center_color,
109 | 0
110 | )
111 | mProgressEndColor = attributes.getColor(
112 | R.styleable.ProgressBarLayout_pbl_progress_end_color,
113 | 0
114 | )
115 | mProgressColorsResId = attributes.getResourceId(
116 | R.styleable.ProgressBarLayout_pbl_progress_colors,
117 | 0
118 | )
119 | mProgressPositionsResId = attributes.getResourceId(
120 | R.styleable.ProgressBarLayout_pbl_progress_positions,
121 | 0
122 | )
123 | mClockwise = attributes.getBoolean(
124 | R.styleable.ProgressBarLayout_pbl_clockwise,
125 | true
126 | )
127 | mRadius = attributes.getDimension(
128 | R.styleable.ProgressBarLayout_pbl_radius,
129 | 0f
130 | )
131 | mProgressMax = attributes.getFloat(
132 | R.styleable.ProgressBarLayout_pbl_progress_max,
133 | 100f
134 | )
135 | mProgress = attributes.getFloat(
136 | R.styleable.ProgressBarLayout_pbl_progress,
137 | 0f
138 | )
139 | mShowTemperatureText = attributes.getBoolean(
140 | R.styleable.ProgressBarLayout_pbl_show_temperature_text,
141 | false
142 | )
143 | mTemperature = attributes.getInteger(
144 | R.styleable.ProgressBarLayout_pbl_temperature_text,
145 | 0
146 | )
147 | mTemperatureTextSize = attributes.getFloat(
148 | R.styleable.ProgressBarLayout_pbl_temperature_text_size,
149 | 60f
150 | )
151 | mTemperatureTextColor = attributes.getColor(
152 | R.styleable.ProgressBarLayout_pbl_temperature_text_color,
153 | 0
154 | )
155 | mTemperatureTextBold = attributes.getBoolean(
156 | R.styleable.ProgressBarLayout_pbl_temperature_text_bold,
157 | false
158 | )
159 | mTemperatureTextFontFamily = attributes.getResourceId(
160 | R.styleable.ProgressBarLayout_pbl_temperature_text_fontfamily,
161 | 0
162 | )
163 | mTemperatureUnitTextSize = attributes.getFloat(
164 | R.styleable.ProgressBarLayout_pbl_temperature_unit_text_size,
165 | 30f
166 | )
167 | mTemperatureUnitTextColor = attributes.getColor(
168 | R.styleable.ProgressBarLayout_pbl_temperature_unit_text_color,
169 | 0
170 | )
171 | mTemperatureUnitTextBold = attributes.getBoolean(
172 | R.styleable.ProgressBarLayout_pbl_temperature_unit_text_bold,
173 | false
174 | )
175 | mTemperatureUnitResId = attributes.getResourceId(
176 | R.styleable.ProgressBarLayout_pbl_temperature_unit_res_id,
177 | 0
178 | )
179 | mTemperatureUnitHeight = attributes.getDimension(
180 | R.styleable.ProgressBarLayout_pbl_temperature_unit_height,
181 | -2f
182 | )
183 | mTemperatureUnitLeftMargin = attributes.getDimension(
184 | R.styleable.ProgressBarLayout_pbl_temperature_unit_left_margin,
185 | 0f
186 | )
187 | mTemperatureUnitTopMargin = attributes.getDimension(
188 | R.styleable.ProgressBarLayout_pbl_temperature_unit_top_margin,
189 | 0f
190 | )
191 | mShowTimeText = attributes.getBoolean(
192 | R.styleable.ProgressBarLayout_pbl_show_time_text,
193 | false
194 | )
195 | mShowShadow = attributes.getBoolean(
196 | R.styleable.ProgressBarLayout_pbl_show_shadow,
197 | true
198 | )
199 | mTime = attributes.getInteger(
200 | R.styleable.ProgressBarLayout_pbl_time_text,
201 | 0
202 | )
203 | mTimeHhmmssTextSize = attributes.getFloat(
204 | R.styleable.ProgressBarLayout_pbl_time_hhmmss_text_size,
205 | 50f
206 | )
207 | mTimeMmssTextSize = attributes.getFloat(
208 | R.styleable.ProgressBarLayout_pbl_time_mmss_text_size,
209 | 60f
210 | )
211 | mTimeTextColor = attributes.getColor(
212 | R.styleable.ProgressBarLayout_pbl_time_text_color,
213 | 0
214 | )
215 | mTimeTextBold = attributes.getBoolean(
216 | R.styleable.ProgressBarLayout_pbl_time_text_bold,
217 | false
218 | )
219 | mTimeTextFontFamily = attributes.getResourceId(
220 | R.styleable.ProgressBarLayout_pbl_temperature_text_fontfamily,
221 | 0
222 | )
223 | } finally {
224 | attributes.recycle()
225 | }
226 | }
227 | }
228 |
229 | private fun initLayout(context: Context) {
230 | addProgressBar(context)
231 | if (mShowTemperatureText) {
232 | addTemperature(context, 0f, mProgressMax)
233 | }
234 | if (mShowTimeText) {
235 | addTime(context, mTime.toLong())
236 | }
237 | }
238 |
239 | private fun addProgressBar(context: Context) {
240 | val progressLp = LayoutParams(mProgressBarWidth.toInt(), mProgressBarHeight.toInt())
241 | progressLp.gravity = Gravity.CENTER
242 | mSmartProgressBar = SmartProgressBar(context)
243 | mSmartProgressBar.setShapeStyle(ShapeStyle.RING)
244 | mSmartProgressBar.setIsAnimated(false)
245 | mSmartProgressBar.setProgressBarBgGradient(mProgressBarBgGradient)
246 | mSmartProgressBar.setProgressBarBgAlpha(mProgressBarBgAlpha)
247 | mSmartProgressBar.setProgressColorsResId(mProgressColorsResId)
248 | mSmartProgressBar.setProgressPositionsResId(mProgressPositionsResId)
249 | setProgressBarBgColor(mProgressBarBgColor)
250 | setProgressStartColor(mProgressStartColor)
251 | setProgressCenterColor(mProgressCenterColor)
252 | setProgressEndColor(mProgressEndColor)
253 | setClockwise(mClockwise)
254 | setRadius(mRadius)
255 | mSmartProgressBar.setShowShadow(mShowShadow)
256 | addView(mSmartProgressBar, progressLp)
257 | }
258 |
259 | @SuppressLint("ResourceType")
260 | private fun addTemperature(context: Context, beginTemperature: Float, endTemperature: Float) {
261 | mRlTemperatureParent = RelativeLayout(context)
262 | mRlTemperatureParent!!.id = View.generateViewId()
263 | val temperatureLp =
264 | RelativeLayout.LayoutParams(-2, -2)
265 | temperatureLp.addRule(
266 | RelativeLayout.CENTER_IN_PARENT,
267 | mRlTemperatureParent!!.id
268 | )
269 | mTvTemperature = TextView(context)
270 | mTvTemperature!!.id = View.generateViewId()
271 | mTvTemperature!!.paint.isFakeBoldText = mTemperatureTextBold
272 | mTvTemperature!!.textSize = mTemperatureTextSize
273 | mTvTemperature!!.setTextColor(mTemperatureTextColor)
274 | if (!isInEditMode && mTemperatureTextFontFamily != 0) {
275 | mTvTemperature!!.typeface = ResourcesCompat.getFont(
276 | getContext(),
277 | mTemperatureTextFontFamily
278 | )
279 | }
280 | val temperatureUnitLp =
281 | RelativeLayout.LayoutParams(-2, mTemperatureUnitHeight.toInt())
282 | temperatureUnitLp.addRule(RelativeLayout.RIGHT_OF, mTvTemperature!!.id)
283 | temperatureUnitLp.topMargin = mTemperatureUnitTopMargin.toInt()
284 | temperatureUnitLp.leftMargin = mTemperatureUnitLeftMargin.toInt()
285 | mTvTemperatureUnit = TextView(context)
286 | mTvTemperatureUnit!!.paint.isFakeBoldText = mTemperatureUnitTextBold
287 | mTvTemperatureUnit!!.textSize = mTemperatureUnitTextSize
288 | mTvTemperatureUnit!!.setTextColor(mTemperatureUnitTextColor)
289 | if (mTemperatureUnitResId != 0) {
290 | temperatureUnitLp.addRule(
291 | RelativeLayout.ALIGN_TOP,
292 | mTvTemperature!!.id
293 | )
294 | mTvTemperatureUnit!!.setBackgroundResource(mTemperatureUnitResId)
295 | } else {
296 | if (!isInEditMode && mTemperatureTextFontFamily != 0) {
297 | mTvTemperatureUnit!!.typeface = ResourcesCompat.getFont(
298 | getContext(),
299 | mTemperatureTextFontFamily
300 | )
301 | }
302 | mTvTemperatureUnit!!.text = "℃"
303 | }
304 | mRlTemperatureParent!!.addView(mTvTemperature, temperatureLp)
305 | mRlTemperatureParent!!.addView(mTvTemperatureUnit, temperatureUnitLp)
306 | val parentLp =
307 | LayoutParams(-2, -2)
308 | parentLp.gravity = Gravity.CENTER
309 | addView(mRlTemperatureParent, parentLp)
310 |
311 | setTemperatureText(beginTemperature, endTemperature)
312 | }
313 |
314 | private fun addTime(context: Context, secondTotalTime: Long) {
315 | val timeLp =
316 | LayoutParams(-2, -2)
317 | timeLp.gravity = Gravity.CENTER
318 | mTvTime = TextView(context)
319 | addView(mTvTime, timeLp)
320 | mTvTime!!.paint.isFakeBoldText = mTimeTextBold
321 | mTvTime!!.setTextColor(mTimeTextColor)
322 | if (!isInEditMode && mTimeTextFontFamily != 0) {
323 | mTvTime!!.typeface = ResourcesCompat.getFont(
324 | getContext(),
325 | mTimeTextFontFamily
326 | )
327 | }
328 |
329 | setTimeText(secondTotalTime)
330 | }
331 |
332 | fun setProgressBarBgColor(progressBarBgColor: Int) {
333 | mSmartProgressBar.setProgressBarBgColor(progressBarBgColor)
334 | }
335 |
336 | fun setProgressStartColor(progressStartColor: Int) {
337 | mSmartProgressBar.setProgressStartColor(progressStartColor)
338 | }
339 |
340 | fun setProgressCenterColor(progressCenterColor: Int) {
341 | mSmartProgressBar.setProgressCenterColor(progressCenterColor)
342 | }
343 |
344 | fun setProgressEndColor(progressEndColor: Int) {
345 | mSmartProgressBar.setProgressEndColor(progressEndColor)
346 | }
347 |
348 | fun setClockwise(clockwise: Boolean) {
349 | mSmartProgressBar.setClockwise(clockwise)
350 | }
351 |
352 | fun setRadius(radius: Float) {
353 | mSmartProgressBar.setRadius(radius)
354 | }
355 |
356 | fun setProgressWithNoAnimation(progress: Float) {
357 | mSmartProgressBar.setProgressWithNoAnimation(progress)
358 | }
359 |
360 | fun setProgress(progress: Float, duration: Long = 0) {
361 | mSmartProgressBar.setProgress(progress, duration)
362 | }
363 |
364 | fun addProgressAnimatorUpdateListener(progressAnimatorUpdateListener: ValueAnimator.AnimatorUpdateListener) {
365 | mSmartProgressBar.addProgressAnimatorUpdateListener(progressAnimatorUpdateListener)
366 | }
367 |
368 | fun addProgressAnimatorListener(mProgressAnimatorListener: Animator.AnimatorListener) {
369 | mSmartProgressBar.addProgressAnimatorListener(mProgressAnimatorListener)
370 | }
371 |
372 | var max: Float
373 | get() = mSmartProgressBar.getMax()
374 | set(max) {
375 | mSmartProgressBar.setMax(max)
376 | }
377 |
378 | /**
379 | * 暂停进度动画
380 | */
381 | fun pauseProgressAnimation() {
382 | mSmartProgressBar.pauseProgressAnimation()
383 | }
384 |
385 | /**
386 | * 恢复进度动画
387 | */
388 | fun resumeProgressAnimation() {
389 | mSmartProgressBar.resumeProgressAnimation()
390 | }
391 |
392 | /**
393 | * 取消进度动画
394 | */
395 | fun cancelProgressAnimation() {
396 | mSmartProgressBar.cancelProgressAnimation()
397 | }
398 |
399 | /**
400 | * 设置温度
401 | * @param beginTemperature 开始温度
402 | * @param endTemperature 结束温度
403 | */
404 | fun setTemperatureText(beginTemperature: Float, endTemperature: Float) {
405 | this.mShowTemperatureText = true
406 | this.mShowTimeText = false
407 | val isClockwise = endTemperature > beginTemperature
408 | this.max = when (isClockwise) {
409 | true -> endTemperature - beginTemperature
410 | else -> endTemperature
411 | }
412 |
413 | if (mTvTime != null) {
414 | mTvTime!!.visibility = View.GONE
415 | }
416 | if (mRlTemperatureParent != null) {
417 | mRlTemperatureParent!!.visibility = View.VISIBLE
418 |
419 | // 更新温度
420 | addProgressAnimatorUpdateListener {
421 | val animatedValue = it.animatedValue as Float
422 | Log.i("animatedValue", "setTemperatureText---${animatedValue}")
423 | when (isClockwise) {
424 | true -> {
425 | mTvTemperature!!.text = (beginTemperature + animatedValue).toInt().toString()
426 | }
427 | else -> {
428 | mTvTemperature!!.text = beginTemperature.toInt().toString()
429 | }
430 | }
431 | }
432 |
433 | // 更新圆环进度
434 | val progress = max
435 | when (isClockwise) {
436 | true -> {
437 | setProgressWithNoAnimation(0f)
438 | setProgress(progress, max.toLong() * 1000)
439 | }
440 | else -> {
441 | setProgress(progress, 1000)
442 | }
443 | }
444 | } else {
445 | addTemperature(context, beginTemperature, endTemperature)
446 | }
447 | }
448 |
449 | /**
450 | * 设置时间,单位"秒"
451 | * @param secondTotalTime 总时长
452 | */
453 | fun setTimeText(secondTotalTime: Long, isFullReduction: Boolean = true) {
454 | this.mShowTemperatureText = false
455 | this.mShowTimeText = true
456 |
457 | if (mRlTemperatureParent != null) {
458 | mRlTemperatureParent!!.visibility = View.GONE
459 | }
460 | if (mTvTime != null) {
461 | mTvTime!!.visibility = View.VISIBLE
462 | // 更新时间
463 | addProgressAnimatorUpdateListener {
464 | val animatedValue = it.animatedValue as Float
465 | val time = animatedValue.toLong()
466 | try {
467 | when {
468 | time >= 10 * 60 * 60 -> {
469 | // 大于十个小时
470 | mTvTime!!.text = formatSecondValueTime("HH:mm:ss", time)
471 | mTvTime!!.textSize = mTimeHhmmssTextSize
472 | }
473 | time >= 1 * 60 * 60 -> {
474 | // 大于1个小时,小于十个小时
475 | mTvTime!!.text = formatSecondValueTime("H:mm:ss", time)
476 | mTvTime!!.textSize = mTimeHhmmssTextSize
477 | }
478 | time >= 10 * 60 -> {
479 | // 大于十分钟,小于1个小时
480 | mTvTime!!.text = formatSecondValueTime("mm:ss", time)
481 | mTvTime!!.textSize = mTimeMmssTextSize
482 | }
483 | else -> {
484 | // 小于十分钟
485 | mTvTime!!.text = formatSecondValueTime("m:ss", time)
486 | mTvTime!!.textSize = mTimeMmssTextSize
487 | }
488 | }
489 | } catch (e: NumberFormatException) {
490 | e.printStackTrace()
491 | }
492 | }
493 |
494 | // 更新圆环进度
495 | this.max = secondTotalTime.toFloat()
496 | val progress = run {
497 | when {
498 | isFullReduction -> {
499 | setProgressWithNoAnimation(max)
500 | 0f
501 | }
502 | else -> {
503 | setProgressWithNoAnimation(0f)
504 | max
505 | }
506 | }
507 | }
508 | mSmartProgressBar.setIsAnimated(false)
509 | setProgress(progress, max.toLong() * 1000)
510 | } else {
511 | addTime(context, secondTotalTime)
512 | }
513 | }
514 |
515 | init {
516 | initAttributes(context, attrs)
517 | initLayout(context)
518 | }
519 |
520 | companion object {
521 | /**
522 | * @param pattern 时间格式
523 | * @param secondValue 秒值
524 | */
525 | private fun formatSecondValueTime(pattern: String, secondValue: Long): String {
526 | return formatMillisecondValueTime(pattern, secondValue * 1000)
527 | }
528 |
529 | /**
530 | * @param pattern 时间格式
531 | * @param millisecondValue 毫秒值
532 | */
533 | private fun formatMillisecondValueTime(pattern: String, millisecondValue: Long): String {
534 | val dateFormat = SimpleDateFormat(pattern, Locale.getDefault())
535 | //设置时区,否则会有时差
536 | dateFormat.timeZone = TimeZone.getTimeZone("UT+08:00")
537 | return dateFormat.format(millisecondValue)
538 | }
539 | }
540 | }
--------------------------------------------------------------------------------
/smartProgressBar/src/main/java/com/fphoenixcorneae/progressbar/SmartProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.fphoenixcorneae.progressbar
2 |
3 | import android.animation.Animator
4 | import android.animation.ValueAnimator
5 | import android.content.Context
6 | import android.graphics.*
7 | import android.os.Parcel
8 | import android.os.Parcelable
9 | import android.util.AttributeSet
10 | import android.view.View
11 | import android.view.animation.LinearInterpolator
12 | import java.util.*
13 |
14 | /**
15 | * @desc:自定义的进度条,样式风格有:水平、竖直、圆环、扇形......
16 | * @date 2019/05/05 21:23
17 | */
18 | class SmartProgressBar @JvmOverloads constructor(
19 | context: Context,
20 | attrs: AttributeSet? = null,
21 | defStyleAttr: Int = 0
22 | ) : View(context, attrs, defStyleAttr), ValueAnimator.AnimatorUpdateListener {
23 |
24 | /**
25 | * 形状样式:默认样式为水平样式
26 | * [ShapeStyle.HORIZONTAL] 水平样式
27 | * [ShapeStyle.VERTICAL] 竖直样式
28 | * [ShapeStyle.RING] 圆环样式
29 | * [ShapeStyle.SECTOR] 扇形样式
30 | */
31 | @Target(AnnotationTarget.FIELD)
32 | @kotlin.annotation.Retention(AnnotationRetention.BINARY)
33 | annotation class ShapeStyle {
34 | companion object {
35 | const val HORIZONTAL = 0
36 | const val VERTICAL = 1
37 | const val RING = 2
38 | const val SECTOR = 3
39 | }
40 | }
41 |
42 | /**
43 | * 进度条背景颜色
44 | */
45 | private var mProgressBarBgColor = DEFAULT_PROGRESS_BAR_BG_COLOR
46 |
47 | /**
48 | * 进度条背景渐变
49 | */
50 | private var mProgressBarBgGradient = false
51 |
52 | /**
53 | * 进度条背景透明度
54 | */
55 | private var mProgressBarBgAlpha = 0f
56 |
57 | /**
58 | * 进度颜色
59 | */
60 | private var mProgressStartColor = DEFAULT_PROGRESS_COLOR
61 | private var mProgressCenterColor = DEFAULT_PROGRESS_COLOR
62 | private var mProgressEndColor = DEFAULT_PROGRESS_COLOR
63 | private var mProgressColorsResId = 0
64 | private var mProgressPositionsResId = 0
65 | private var mProgressColors: IntArray? = null
66 | private var mProgressPositions: FloatArray? = null
67 |
68 | /**
69 | * 边框颜色
70 | */
71 | private var mBorderColor = DEFAULT_BORDER_COLOR
72 |
73 | /**
74 | * 边框宽度
75 | */
76 | private var mBorderWidth = 0f
77 |
78 | /**
79 | * 进度提示文字大小
80 | */
81 | private var mPercentTextSize =
82 | DEFAULT_PERCENT_TEXT_SIZE
83 |
84 | /**
85 | * 进度提示文字颜色
86 | */
87 | private var mPercentTextColor = DEFAULT_PERCENT_TEXT_COLOR
88 |
89 | /**
90 | * 进度条中心X坐标
91 | */
92 | private var mCenterX = 0f
93 |
94 | /**
95 | * 进度条中心Y坐标
96 | */
97 | private var mCenterY = 0f
98 |
99 | /**
100 | * 进度条样式
101 | */
102 | private var mShapeStyle = ShapeStyle.HORIZONTAL
103 |
104 | /**
105 | * 水平、竖直进度条圆角半径;圆环/扇形内圆半径
106 | */
107 | private var mRadius = 0f
108 |
109 | /**
110 | * 圆环/扇形是否顺时针方向绘制
111 | */
112 | private var mClockwise = true
113 |
114 | /**
115 | * 水平、竖直进度条圆角半径
116 | */
117 | private var mTopLeftRadius = 0f
118 | private var mTopRightRadius = 0f
119 | private var mBottomLeftRadius = 0f
120 | private var mBottomRightRadius = 0f
121 | private lateinit var mRadii: FloatArray
122 |
123 | /**
124 | * 进度最大值
125 | */
126 | private var mMaxProgress = DEFAULT_MAX
127 |
128 | /**
129 | * 进度值
130 | */
131 | private var mProgress = 0f
132 |
133 | /**
134 | * 进度文字是否显示百分号
135 | */
136 | private var mIsShowPercentSign = false
137 |
138 | /**
139 | * 进度文字是否显示
140 | */
141 | private var mIsShowPercentText = false
142 |
143 | /**
144 | * 进度画笔
145 | */
146 | private var mProgressPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
147 | private var mStartProgressPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
148 | private var mEndProgressPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
149 |
150 | /**
151 | * 进度条背景画笔
152 | */
153 | private var mProgressBarBgPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
154 |
155 | /**
156 | * 进度百分比字体画笔
157 | */
158 | private var mPercentTextPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
159 |
160 | /**
161 | * 边框画笔
162 | */
163 | private var mBorderPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
164 |
165 | /**
166 | * 绘制路径
167 | */
168 | private val mProgressPath = Path()
169 | private val mStartProgressPath = Path()
170 | private val mEndProgressPath = Path()
171 | private val mBorderPath = Path()
172 | private val mProgressBarBgPath = Path()
173 | private val mShadowPath = Path()
174 |
175 | /**
176 | * 是否执行动画
177 | */
178 | private var mIsAnimated = true
179 | private var mAnimator = ValueAnimator()
180 | private var mDuration = DEFAULT_ANIMATION_DURATION
181 | private var mAnimatorUpdateListener: ValueAnimator.AnimatorUpdateListener? = null
182 | private var mProgressAnimator = ValueAnimator()
183 | private var mProgressAnimatorListener = ArrayList()
184 | private var mProgressAnimatorUpdateListener = ArrayList()
185 |
186 | /**
187 | * 进度阴影
188 | */
189 | private var mShadowPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
190 | private val mShadowColor = Color.parseColor("#2b1a14")
191 | private val mShadowColor2 = Color.parseColor("#102b1a14")
192 | private var mShowShadow = true
193 |
194 | /**
195 | * 矩形
196 | */
197 | private val mHorizontalRectF = RectF()
198 | private val mVerticalRectF = RectF()
199 | private val mRingRectF = RectF()
200 | private val mSectorRectF = RectF()
201 |
202 | /**
203 | * 初始化自定义属性
204 | */
205 | private fun initAttrs(
206 | context: Context,
207 | attrs: AttributeSet?,
208 | defStyleAttr: Int
209 | ) {
210 | val attributes = context.theme.obtainStyledAttributes(
211 | attrs,
212 | R.styleable.SmartProgressBar,
213 | defStyleAttr,
214 | 0
215 | )
216 | try {
217 | mMaxProgress = attributes.getFloat(
218 | R.styleable.SmartProgressBar_spb_max,
219 | DEFAULT_MAX
220 | )
221 | mProgress = attributes.getFloat(
222 | R.styleable.SmartProgressBar_spb_progress,
223 | 0f
224 | )
225 | mProgressStartColor = attributes.getColor(
226 | R.styleable.SmartProgressBar_spb_progress_start_color,
227 | DEFAULT_PROGRESS_COLOR
228 | )
229 | mProgressCenterColor = attributes.getColor(
230 | R.styleable.SmartProgressBar_spb_progress_center_color,
231 | DEFAULT_PROGRESS_COLOR
232 | )
233 | mProgressEndColor = attributes.getColor(
234 | R.styleable.SmartProgressBar_spb_progress_end_color,
235 | DEFAULT_PROGRESS_COLOR
236 | )
237 | mProgressColorsResId = attributes.getResourceId(
238 | R.styleable.SmartProgressBar_spb_progress_colors,
239 | 0
240 | )
241 | mProgressPositionsResId = attributes.getResourceId(
242 | R.styleable.SmartProgressBar_spb_progress_positions,
243 | 0
244 | )
245 | mProgressBarBgColor = attributes.getColor(
246 | R.styleable.SmartProgressBar_spb_progress_bar_bg_color,
247 | DEFAULT_PROGRESS_BAR_BG_COLOR
248 | )
249 | mProgressBarBgGradient = attributes.getBoolean(
250 | R.styleable.SmartProgressBar_spb_progress_bar_bg_gradient,
251 | false
252 | )
253 | mProgressBarBgAlpha = attributes.getFloat(
254 | R.styleable.SmartProgressBar_spb_progress_bar_bg_alpha,
255 | 1f
256 | )
257 | mIsShowPercentText = attributes.getBoolean(
258 | R.styleable.SmartProgressBar_spb_show_percent_text,
259 | false
260 | )
261 | mIsShowPercentSign = attributes.getBoolean(
262 | R.styleable.SmartProgressBar_spb_show_percent_sign,
263 | false
264 | )
265 | mPercentTextColor = attributes.getColor(
266 | R.styleable.SmartProgressBar_spb_percent_text_color,
267 | DEFAULT_PERCENT_TEXT_COLOR
268 | )
269 | mPercentTextSize = attributes.getDimension(
270 | R.styleable.SmartProgressBar_spb_percent_text_size,
271 | DEFAULT_PERCENT_TEXT_SIZE
272 | )
273 | mBorderColor = attributes.getColor(
274 | R.styleable.SmartProgressBar_spb_border_color,
275 | DEFAULT_BORDER_COLOR
276 | )
277 | mBorderWidth = attributes.getDimension(
278 | R.styleable.SmartProgressBar_spb_border_width,
279 | 0f
280 | )
281 | mRadius = attributes.getDimension(
282 | R.styleable.SmartProgressBar_spb_radius,
283 | 0f
284 | )
285 | mClockwise = attributes.getBoolean(
286 | R.styleable.SmartProgressBar_spb_clockwise,
287 | true
288 | )
289 | mTopLeftRadius = attributes.getDimension(
290 | R.styleable.SmartProgressBar_spb_top_left_radius,
291 | 0f
292 | )
293 | mTopRightRadius = attributes.getDimension(
294 | R.styleable.SmartProgressBar_spb_top_right_radius,
295 | 0f
296 | )
297 | mBottomLeftRadius = attributes.getDimension(
298 | R.styleable.SmartProgressBar_spb_bottom_left_radius,
299 | 0f
300 | )
301 | mBottomRightRadius = attributes.getDimension(
302 | R.styleable.SmartProgressBar_spb_bottom_right_radius,
303 | 0f
304 | )
305 | mShapeStyle = attributes.getInt(
306 | R.styleable.SmartProgressBar_spb_shape_style,
307 | 0
308 | )
309 | mIsAnimated = attributes.getBoolean(
310 | R.styleable.SmartProgressBar_spb_animated,
311 | true
312 | )
313 | mDuration = attributes.getInt(
314 | R.styleable.SmartProgressBar_spb_animated_duration,
315 | DEFAULT_ANIMATION_DURATION.toInt()
316 | ).toLong()
317 | mShowShadow = attributes.getBoolean(
318 | R.styleable.SmartProgressBar_spb_show_shadow,
319 | false
320 | )
321 | if (mMaxProgress <= 0) {
322 | mMaxProgress = DEFAULT_MAX
323 | }
324 | if (mProgress > mMaxProgress) {
325 | mProgress = mMaxProgress
326 | } else if (mProgress < 0) {
327 | mProgress = 0f
328 | }
329 | } finally {
330 | attributes.recycle()
331 | }
332 | }
333 |
334 | /**
335 | * 初始化
336 | */
337 | private fun init() {
338 | // 硬件加速
339 | setLayerType(LAYER_TYPE_HARDWARE, null)
340 |
341 | /*进度画笔*/
342 | mProgressPaint.style = Paint.Style.FILL
343 |
344 | /*进度条背景画笔*/
345 | mProgressBarBgPaint.color = mProgressBarBgColor
346 |
347 | /*边框画笔*/
348 | mBorderPaint.color = mBorderColor
349 | mBorderPaint.style = Paint.Style.STROKE
350 | mBorderPaint.strokeWidth = mBorderWidth
351 |
352 | /*进度百分比字体画笔*/
353 | mPercentTextPaint.color = mPercentTextColor
354 | mPercentTextPaint.style = Paint.Style.FILL
355 | mPercentTextPaint.textSize = mPercentTextSize
356 |
357 | /*若是设置了radius属性,四个圆角属性值以radius属性值为准*/
358 | if (mRadius > 0) {
359 | mBottomRightRadius = mRadius
360 | mBottomLeftRadius = mRadius
361 | mTopRightRadius = mRadius
362 | mTopLeftRadius = mRadius
363 | }
364 |
365 | /*圆角的半径,依次为左上角xy半径,右上角,右下角,左下角*/
366 | mRadii = floatArrayOf(
367 | mTopLeftRadius, mTopLeftRadius,
368 | mTopRightRadius, mTopRightRadius,
369 | mBottomRightRadius, mBottomRightRadius,
370 | mBottomLeftRadius, mBottomLeftRadius
371 | )
372 | }
373 |
374 | override fun onAttachedToWindow() {
375 | super.onAttachedToWindow()
376 | // 是否执行动画
377 | if (mIsAnimated) {
378 | // 开始动画
379 | startAnimating()
380 | }
381 | }
382 |
383 | override fun onDetachedFromWindow() {
384 | super.onDetachedFromWindow()
385 | // 取消动画
386 | cancelAnimating()
387 | cancelProgressAnimation()
388 | }
389 |
390 | /**
391 | * 开始动画
392 | */
393 | private fun startAnimating() {
394 | mAnimator.apply {
395 | setFloatValues(0f, mProgress)
396 | repeatCount = 0
397 | repeatMode = ValueAnimator.RESTART
398 | interpolator = LinearInterpolator()
399 | duration = mDuration
400 | // 设置动画的回调
401 | mAnimatorUpdateListener = ValueAnimator.AnimatorUpdateListener { animation ->
402 | mProgress = animation.animatedValue as Float
403 | post { postInvalidate() }
404 | }
405 | addUpdateListener(mAnimatorUpdateListener)
406 | start()
407 | }
408 | }
409 |
410 | /**
411 | * 停止动画
412 | */
413 | private fun pauseAnimating() {
414 | mAnimator.pause()
415 | }
416 |
417 | /**
418 | * 取消动画
419 | */
420 | private fun cancelAnimating() {
421 | mAnimator.cancel()
422 | }
423 |
424 | private fun isAnimatorRunning(): Boolean {
425 | return mAnimator.isRunning
426 | }
427 |
428 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
429 | val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec)
430 | val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)
431 | val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec)
432 | val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec)
433 | val (width, height) = when (widthSpecMode) {
434 | MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED -> {
435 | dp2px(DEFAULT_WIDTH)
436 | }
437 | else -> {
438 | widthSpecSize
439 | }
440 | } to when (heightSpecMode) {
441 | MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED -> {
442 | dp2px(DEFAULT_HEIGHT)
443 | }
444 | else -> {
445 | heightSpecSize
446 | }
447 | }
448 | setMeasuredDimension(width, height)
449 | }
450 |
451 | override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
452 | super.onSizeChanged(w, h, oldw, oldh)
453 | mCenterX = width.toFloat() / 2
454 | mCenterY = height.toFloat() / 2
455 | setProgressColorsResId(mProgressColorsResId)
456 | setProgressPositionsResId(mProgressPositionsResId)
457 | when (mProgressColors) {
458 | null -> {
459 | mProgressColors = IntArray(5)
460 | mProgressColors!![0] = mProgressStartColor
461 | mProgressColors!![1] = mProgressStartColor
462 | mProgressColors!![2] = mProgressCenterColor
463 | mProgressColors!![3] = mProgressEndColor
464 | mProgressColors!![4] = mProgressEndColor
465 | mProgressPositions = FloatArray(5)
466 | mProgressPositions!![0] = 0.0f
467 | mProgressPositions!![1] = 0.1f
468 | mProgressPositions!![2] = 0.5f
469 | mProgressPositions!![3] = 0.9f
470 | mProgressPositions!![4] = 1.0f
471 | }
472 | }
473 | when (mShapeStyle) {
474 | ShapeStyle.HORIZONTAL -> {
475 | /*创建线性颜色渐变器*/
476 | val linearGradient: Shader = LinearGradient(
477 | mBorderWidth,
478 | (height - mBorderWidth * 2) / 2,
479 | mBorderWidth + mProgress / mMaxProgress * (width - mBorderWidth * 2),
480 | (height - mBorderWidth * 2) / 2,
481 | mProgressColors!!,
482 | mProgressPositions, Shader.TileMode.MIRROR
483 | )
484 | mProgressPaint.shader = linearGradient
485 | }
486 | ShapeStyle.VERTICAL -> {
487 | /*创建线性颜色渐变器*/
488 | val linearGradient: Shader = LinearGradient(
489 | (width - mBorderWidth * 2) / 2,
490 | height - mBorderWidth,
491 | (width - mBorderWidth * 2) / 2,
492 | height - mProgress / mMaxProgress * (height - mBorderWidth * 2) - mBorderWidth,
493 | mProgressColors!!,
494 | mProgressPositions, Shader.TileMode.MIRROR
495 | )
496 | mProgressPaint.shader = linearGradient
497 | }
498 | ShapeStyle.RING -> {
499 | /*创建扫描式渐变器*/
500 | when {
501 | !mClockwise -> {
502 | reverseProgressColors()
503 | }
504 | }
505 | val sweepGradient = SweepGradient(
506 | 0f,
507 | 0f,
508 | mProgressColors!!,
509 | mProgressPositions
510 | )
511 | mProgressPaint.shader = sweepGradient
512 | when {
513 | mProgressBarBgGradient -> {
514 | mProgressBarBgPaint.shader = sweepGradient
515 | mProgressBarBgPaint.alpha = (mProgressBarBgAlpha * 255).toInt()
516 | }
517 | }
518 | val gradientMatrix = Matrix()
519 | gradientMatrix.setTranslate(mCenterX, mCenterY)
520 | sweepGradient.setLocalMatrix(gradientMatrix)
521 | }
522 | ShapeStyle.SECTOR -> {
523 | /*创建扫描式渐变器*/
524 | when {
525 | !mClockwise -> {
526 | reverseProgressColors()
527 | }
528 | }
529 | val sweepGradient: Shader = SweepGradient(
530 | 0f,
531 | 0f,
532 | mProgressColors!!,
533 | null
534 | )
535 | mProgressPaint.shader = sweepGradient
536 | val gradientMatrix = Matrix()
537 | gradientMatrix.setTranslate(mCenterX, mCenterY)
538 | sweepGradient.setLocalMatrix(gradientMatrix)
539 | }
540 | }
541 | }
542 |
543 | override fun onDraw(canvas: Canvas) {
544 | canvas.save()
545 | when (mShapeStyle) {
546 | ShapeStyle.HORIZONTAL -> {
547 | drawHorizontalProgressBar(canvas)
548 | }
549 | ShapeStyle.VERTICAL -> {
550 | drawVerticalProgressBar(canvas)
551 | }
552 | ShapeStyle.RING -> {
553 | drawRingProgressBar(canvas)
554 | }
555 | ShapeStyle.SECTOR -> {
556 | drawSectorProgressBar(canvas)
557 | }
558 | }
559 | canvas.restore()
560 | super.onDraw(canvas)
561 | }
562 |
563 | /**
564 | * 避免View占用额外的GPU内存空间
565 | */
566 | override fun hasOverlappingRendering(): Boolean {
567 | return false
568 | }
569 |
570 | /**
571 | * 绘制水平进度条
572 | *
573 | * @param canvas 画布
574 | */
575 | private fun drawHorizontalProgressBar(canvas: Canvas) {
576 | // 绘制进度条背景
577 | mProgressBarBgPath.rewind()
578 | mHorizontalRectF.left = mBorderWidth / 2
579 | mHorizontalRectF.top = mBorderWidth / 2
580 | mHorizontalRectF.right = width - mBorderWidth / 2
581 | mHorizontalRectF.bottom = height - mBorderWidth / 2
582 | mProgressBarBgPath.addRoundRect(
583 | mHorizontalRectF,
584 | mRadii,
585 | Path.Direction.CW
586 | )
587 | canvas.drawPath(mProgressBarBgPath, mProgressBarBgPaint)
588 |
589 | // 绘制边框
590 | when {
591 | mBorderWidth > 0 -> {
592 | mBorderPath.rewind()
593 | mBorderPath.addRoundRect(mHorizontalRectF, mRadii, Path.Direction.CW)
594 | canvas.drawPath(mBorderPath, mBorderPaint)
595 | }
596 | }
597 |
598 | // 绘制进度
599 | mProgressPath.rewind()
600 | mHorizontalRectF.left = mBorderWidth
601 | mHorizontalRectF.top = mBorderWidth
602 | mHorizontalRectF.right = mBorderWidth + mProgress / mMaxProgress * (width - mBorderWidth * 2)
603 | mHorizontalRectF.bottom = height - mBorderWidth
604 | mProgressPath.addRoundRect(mHorizontalRectF, mRadii, Path.Direction.CW)
605 | canvas.drawPath(mProgressPath, mProgressPaint)
606 | when {
607 | mIsShowPercentText -> {
608 | // 绘制进度文字和进度百分比符号
609 | drawPercentText(canvas)
610 | }
611 | }
612 | }
613 |
614 | /**
615 | * 绘制竖直进度条
616 | *
617 | * @param canvas 画布
618 | */
619 | private fun drawVerticalProgressBar(canvas: Canvas) {
620 | // 绘制进度条背景
621 | mProgressBarBgPath.rewind()
622 | mVerticalRectF.left = mBorderWidth / 2
623 | mVerticalRectF.top = mBorderWidth / 2
624 | mVerticalRectF.right = width - mBorderWidth / 2
625 | mVerticalRectF.bottom = height - mBorderWidth / 2
626 | mProgressBarBgPath.addRoundRect(mVerticalRectF, mRadii, Path.Direction.CW)
627 | canvas.drawPath(mProgressBarBgPath, mProgressBarBgPaint)
628 |
629 | // 绘制边框
630 | when {
631 | mBorderWidth > 0 -> {
632 | mBorderPath.rewind()
633 | mBorderPath.addRoundRect(mVerticalRectF, mRadii, Path.Direction.CW)
634 | canvas.drawPath(mBorderPath, mBorderPaint)
635 | }
636 | }
637 |
638 | // 绘制进度
639 | mProgressPath.rewind()
640 | mVerticalRectF.left = mBorderWidth
641 | mVerticalRectF.top =
642 | height - mProgress / mMaxProgress * (height - mBorderWidth * 2) - mBorderWidth
643 | mVerticalRectF.right = width - mBorderWidth
644 | mVerticalRectF.bottom = height - mBorderWidth
645 | mProgressPath.addRoundRect(mVerticalRectF, mRadii, Path.Direction.CW)
646 | canvas.drawPath(mProgressPath, mProgressPaint)
647 | when {
648 | mIsShowPercentText -> {
649 | // 绘制进度文字和进度百分比符号
650 | drawPercentText(canvas)
651 | }
652 | }
653 | }
654 |
655 | /**
656 | * 绘制圆环进度条
657 | *
658 | * @param canvas 画布
659 | */
660 | private fun drawRingProgressBar(canvas: Canvas) {
661 | val strokeWidth = mCenterX - mRadius - mBorderWidth
662 | // 绘制边框
663 | when {
664 | mBorderWidth > 0 -> {
665 | mBorderPath.rewind()
666 | mBorderPath.addCircle(
667 | mCenterX,
668 | mCenterY,
669 | mCenterX - mBorderWidth / 2,
670 | Path.Direction.CW
671 | )
672 | canvas.drawPath(mBorderPath, mBorderPaint)
673 | }
674 | }
675 |
676 | // 逆时针旋转画布90度
677 | canvas.rotate(-90f, mCenterX, mCenterY)
678 | mRingRectF.left = mBorderWidth + strokeWidth / 2
679 | mRingRectF.top = mBorderWidth + strokeWidth / 2
680 | mRingRectF.right = width - mBorderWidth - strokeWidth / 2
681 | mRingRectF.bottom = height - mBorderWidth - strokeWidth / 2
682 |
683 | // 绘制进度条背景
684 | mProgressBarBgPaint.style = Paint.Style.STROKE
685 | mProgressBarBgPaint.strokeCap = Paint.Cap.ROUND
686 | mProgressBarBgPaint.strokeJoin = Paint.Join.ROUND
687 | mProgressBarBgPaint.strokeWidth = strokeWidth
688 | mProgressBarBgPath.rewind()
689 | when {
690 | mClockwise -> {
691 | mProgressBarBgPath.addArc(mRingRectF, 0f, 360f)
692 | }
693 | else -> {
694 | mProgressBarBgPath.addArc(mRingRectF, 0f, -360f)
695 | }
696 | }
697 | canvas.drawPath(mProgressBarBgPath, mProgressBarBgPaint)
698 |
699 | // 添加阴影效果
700 | when {
701 | mShowShadow -> {
702 | mShadowPaint.style = Paint.Style.STROKE
703 | mShadowPaint.strokeCap = Paint.Cap.ROUND
704 | mShadowPaint.strokeJoin = Paint.Join.ROUND
705 | mShadowPaint.strokeWidth = strokeWidth
706 | mShadowPaint.color = mShadowColor
707 | mShadowPath.rewind()
708 | when {
709 | mProgress / mMaxProgress <= 0.92f -> {
710 | when {
711 | mClockwise -> {
712 | mShadowPath.addArc(mRingRectF, 0f, 360 * mProgress / mMaxProgress)
713 | }
714 | else -> {
715 | mShadowPath.addArc(mRingRectF, 0f, -360 * mProgress / mMaxProgress)
716 | }
717 | }
718 | }
719 | else -> {
720 | mShadowPath.addArc(mRingRectF, 0f, 1f)
721 | }
722 | }
723 | mShadowPaint.setShadowLayer(20f, 0f, 0f, mShadowColor)
724 | canvas.drawPath(mShadowPath, mShadowPaint)
725 | mShadowPaint.setShadowLayer(30f, 0f, 0f, mShadowColor2)
726 | canvas.drawPath(mShadowPath, mShadowPaint)
727 | }
728 | }
729 |
730 | // 绘制进度
731 | mProgressPaint.style = Paint.Style.STROKE
732 | mProgressPaint.strokeCap = Paint.Cap.ROUND
733 | mProgressPaint.strokeJoin = Paint.Join.ROUND
734 | mProgressPaint.strokeWidth = strokeWidth
735 | mProgressPath.rewind()
736 | when {
737 | mClockwise -> {
738 | mProgressPath.addArc(mRingRectF, 0f, 360 * mProgress / mMaxProgress)
739 | }
740 | else -> {
741 | mProgressPath.addArc(mRingRectF, 0f, -360 * mProgress / mMaxProgress)
742 | }
743 | }
744 | canvas.drawPath(mProgressPath, mProgressPaint)
745 |
746 | // 绘制开始状态时的圆
747 | mStartProgressPaint.style = Paint.Style.STROKE
748 | mStartProgressPaint.strokeCap = Paint.Cap.ROUND
749 | mStartProgressPaint.strokeJoin = Paint.Join.ROUND
750 | mStartProgressPaint.strokeWidth = strokeWidth
751 | when {
752 | mClockwise -> {
753 | mStartProgressPaint.color = mProgressColors!![0]
754 | }
755 | else -> {
756 | mStartProgressPaint.color = mProgressColors!![mProgressColors!!.size - 1]
757 | }
758 | }
759 | mStartProgressPath.rewind()
760 | mStartProgressPath.addArc(mRingRectF, 0f, 1f)
761 | canvas.drawPath(mStartProgressPath, mStartProgressPaint)
762 |
763 | // 结束阶段进度
764 | mEndProgressPaint.style = Paint.Style.STROKE
765 | mEndProgressPaint.strokeCap = Paint.Cap.ROUND
766 | mEndProgressPaint.strokeJoin = Paint.Join.ROUND
767 | mEndProgressPaint.strokeWidth = strokeWidth
768 | when {
769 | mClockwise -> {
770 | mEndProgressPaint.color = mProgressColors!![mProgressColors!!.size - 1]
771 | }
772 | else -> {
773 | mEndProgressPaint.color = mProgressColors!![0]
774 | }
775 | }
776 | when {
777 | mProgress / mMaxProgress > 0.9f -> {
778 | // 添加阴影效果
779 | when {
780 | mShowShadow && mProgress / mMaxProgress > 0.92f -> {
781 | mShadowPath.rewind()
782 | when {
783 | mClockwise -> {
784 | mShadowPath.addArc(mRingRectF, 360 * (mProgress / mMaxProgress) - 1, 1f)
785 | }
786 | else -> {
787 | mShadowPath.addArc(mRingRectF, -360 * (mProgress / mMaxProgress) + 1, -1f)
788 | }
789 | }
790 | mShadowPaint.setShadowLayer(20f, 0f, 0f, mShadowColor)
791 | canvas.drawPath(mShadowPath, mShadowPaint)
792 | mShadowPaint.setShadowLayer(30f, 0f, 0f, mShadowColor2)
793 | canvas.drawPath(mShadowPath, mShadowPaint)
794 | }
795 | }
796 |
797 | mEndProgressPath.rewind()
798 | when {
799 | mClockwise -> {
800 | mEndProgressPath.addArc(mRingRectF, 360 * 0.9f, 360 * (mProgress / mMaxProgress - 0.9f))
801 | }
802 | else -> {
803 | mEndProgressPath.addArc(
804 | mRingRectF,
805 | -360 * 0.9f,
806 | -360 * (mProgress / mMaxProgress - 0.9f)
807 | )
808 | }
809 | }
810 | canvas.drawPath(mEndProgressPath, mEndProgressPaint)
811 | }
812 | }
813 | when {
814 | mIsShowPercentText -> {
815 | // 顺时针旋转画布90度
816 | canvas.rotate(90f, mCenterX, mCenterY)
817 | // 绘制进度文字和进度百分比符号
818 | drawPercentText(canvas)
819 | }
820 | }
821 | }
822 |
823 | /**
824 | * 绘制扇形扫描式进度
825 | *
826 | * @param canvas 画布
827 | */
828 | private fun drawSectorProgressBar(canvas: Canvas) {
829 | // 绘制进度条背景
830 | canvas.drawCircle(mCenterX, mCenterY, mCenterX - mBorderWidth, mProgressBarBgPaint)
831 |
832 | // 绘制边框
833 | when {
834 | mBorderWidth > 0 -> {
835 | mBorderPath.rewind()
836 | mBorderPath.addCircle(
837 | mCenterX,
838 | mCenterY,
839 | mCenterX - mBorderWidth / 2,
840 | Path.Direction.CW
841 | )
842 | canvas.drawPath(mBorderPath, mBorderPaint)
843 | }
844 | }
845 |
846 | // 逆时针旋转画布90度
847 | canvas.rotate(-90f, mCenterX, mCenterY)
848 | // 绘制进度
849 | mSectorRectF.left = mBorderWidth
850 | mSectorRectF.top = mBorderWidth
851 | mSectorRectF.right = width - mBorderWidth
852 | mSectorRectF.bottom = height - mBorderWidth
853 | when {
854 | mClockwise -> {
855 | canvas.drawArc(mSectorRectF, 0f, 360 * mProgress / mMaxProgress, true, mProgressPaint)
856 | }
857 | else -> {
858 | canvas.drawArc(mSectorRectF, 0f, -360 * mProgress / mMaxProgress, true, mProgressPaint)
859 | }
860 | }
861 | when {
862 | mIsShowPercentText -> {
863 | // 顺时针旋转画布90度
864 | canvas.rotate(90f, mCenterX, mCenterY)
865 | // 绘制进度文字和进度百分比符号
866 | drawPercentText(canvas)
867 | }
868 | }
869 | }
870 |
871 | /**
872 | * 绘制进度文字和进度百分比符号
873 | *
874 | * @param canvas 画布
875 | */
876 | private fun drawPercentText(canvas: Canvas) {
877 | var percent = (mProgress * 100 / mMaxProgress).toInt().toString()
878 | if (mIsShowPercentSign) {
879 | percent = "$percent%"
880 | }
881 | val rect = Rect()
882 | // 获取字符串的宽高值
883 | mPercentTextPaint.getTextBounds(percent, 0, percent.length, rect)
884 | var textWidth = rect.width().toFloat()
885 | var textHeight = rect.height().toFloat()
886 | when {
887 | textWidth >= width -> {
888 | textWidth = width.toFloat()
889 | }
890 | }
891 | when {
892 | textHeight >= height -> {
893 | textHeight = height.toFloat()
894 | }
895 | }
896 | canvas.drawText(
897 | percent,
898 | mCenterX - textWidth / 2,
899 | mCenterY + textHeight / 2,
900 | mPercentTextPaint
901 | )
902 | }
903 |
904 | internal class SavedState : BaseSavedState {
905 | internal var progress = 0F
906 |
907 | internal constructor(superState: Parcelable) : super(superState) {}
908 |
909 | private constructor(`in`: Parcel) : super(`in`) {
910 | progress = `in`.readFloat()
911 | }
912 |
913 | override fun writeToParcel(out: Parcel, flags: Int) {
914 | super.writeToParcel(out, flags)
915 | out.writeFloat(progress)
916 | }
917 |
918 | companion object CREATOR : Parcelable.Creator {
919 | override fun createFromParcel(parcel: Parcel): SavedState {
920 | return SavedState(parcel)
921 | }
922 |
923 | override fun newArray(size: Int): Array {
924 | return arrayOfNulls(size)
925 | }
926 | }
927 | }
928 |
929 | public override fun onSaveInstanceState(): Parcelable? {
930 | // Force our ancestor class to save its state
931 | val superState = super.onSaveInstanceState()
932 | val ss = superState?.let { SavedState(it) }
933 | ss?.progress = getProgress()
934 | return ss
935 | }
936 |
937 | public override fun onRestoreInstanceState(state: Parcelable) {
938 | val ss = state as SavedState
939 | super.onRestoreInstanceState(ss.superState)
940 | setProgress(ss.progress)
941 | }
942 |
943 | fun setProgressBarBgColor(mProgressBarBgColor: Int): SmartProgressBar {
944 | this.mProgressBarBgColor = mProgressBarBgColor
945 | mProgressBarBgPaint.color = mProgressBarBgColor
946 | return this
947 | }
948 |
949 | fun setProgressBarBgGradient(mProgressBarBgGradient: Boolean): SmartProgressBar {
950 | this.mProgressBarBgGradient = mProgressBarBgGradient
951 | return this
952 | }
953 |
954 | fun setProgressBarBgAlpha(mProgressBarBgAlpha: Float): SmartProgressBar {
955 | this.mProgressBarBgAlpha = mProgressBarBgAlpha
956 | mProgressBarBgPaint.alpha = (mProgressBarBgAlpha * 255).toInt()
957 | return this
958 | }
959 |
960 | fun setProgressStartColor(mProgressStartColor: Int): SmartProgressBar {
961 | this.mProgressStartColor = mProgressStartColor
962 | return this
963 | }
964 |
965 | fun setProgressCenterColor(mProgressCenterColor: Int): SmartProgressBar {
966 | this.mProgressCenterColor = mProgressCenterColor
967 | return this
968 | }
969 |
970 | fun setProgressEndColor(mProgressEndColor: Int): SmartProgressBar {
971 | this.mProgressEndColor = mProgressEndColor
972 | return this
973 | }
974 |
975 | fun setProgressColorsResId(mProgressColorsResId: Int): SmartProgressBar {
976 | this.mProgressColorsResId = mProgressColorsResId
977 | if (mProgressColorsResId != 0) {
978 | try {
979 | val colors = context.resources.getStringArray(mProgressColorsResId)
980 | mProgressColors = IntArray(colors.size)
981 | for (i in colors.indices) {
982 | mProgressColors!![i] = Color.parseColor(colors[i])
983 | }
984 | } catch (e: Exception) {
985 | e.printStackTrace()
986 | }
987 | }
988 | return this
989 | }
990 |
991 | fun reverseProgressColors(): SmartProgressBar {
992 | if (mProgressColors != null) {
993 | val tempProgressColors = IntArray(mProgressColors!!.size)
994 | for (i in mProgressColors!!.indices) {
995 | tempProgressColors[mProgressColors!!.size - 1 - i] = mProgressColors!![i]
996 | }
997 | mProgressColors = tempProgressColors
998 | }
999 | return this
1000 | }
1001 |
1002 | fun setProgressPositionsResId(mProgressPositionsResId: Int): SmartProgressBar {
1003 | this.mProgressPositionsResId = mProgressPositionsResId
1004 | if (mProgressPositionsResId != 0) {
1005 | try {
1006 | val positions = context.resources.getIntArray(mProgressPositionsResId)
1007 | mProgressPositions = FloatArray(positions.size)
1008 | for (i in positions.indices) {
1009 | mProgressPositions!![i] = positions[i] / 100f
1010 | }
1011 | } catch (e: Exception) {
1012 | e.printStackTrace()
1013 | }
1014 | }
1015 | return this
1016 | }
1017 |
1018 | fun setBorderColor(mBorderColor: Int): SmartProgressBar {
1019 | this.mBorderColor = mBorderColor
1020 | mBorderPaint.color = mBorderColor
1021 | return this
1022 | }
1023 |
1024 | fun setBorderWidth(mBorderWidth: Float): SmartProgressBar {
1025 | this.mBorderWidth = mBorderWidth
1026 | mBorderPaint.strokeWidth = mBorderWidth
1027 | return this
1028 | }
1029 |
1030 | fun setPercentTextSize(mPercentTextSize: Float): SmartProgressBar {
1031 | this.mPercentTextSize = mPercentTextSize
1032 | mPercentTextPaint.textSize = mPercentTextSize
1033 | return this
1034 | }
1035 |
1036 | fun setPercentTextColor(mPercentTextColor: Int): SmartProgressBar {
1037 | this.mPercentTextColor = mPercentTextColor
1038 | mPercentTextPaint.color = mPercentTextColor
1039 | return this
1040 | }
1041 |
1042 | fun setShapeStyle(mShapeStyle: Int): SmartProgressBar {
1043 | this.mShapeStyle = mShapeStyle
1044 | return this
1045 | }
1046 |
1047 | fun setRadius(mRadius: Float): SmartProgressBar {
1048 | this.mRadius = mRadius
1049 | setRadius(mRadius, mRadius, mRadius, mRadius)
1050 | return this
1051 | }
1052 |
1053 | fun setClockwise(mClockwise: Boolean): SmartProgressBar {
1054 | this.mClockwise = mClockwise
1055 | return this
1056 | }
1057 |
1058 | fun setRadius(
1059 | mTopLeftRadius: Float,
1060 | mTopRightRadius: Float,
1061 | mBottomRightRadius: Float,
1062 | mBottomLeftRadius: Float
1063 | ): SmartProgressBar {
1064 | this.mTopLeftRadius = mTopLeftRadius
1065 | this.mTopRightRadius = mTopRightRadius
1066 | this.mBottomRightRadius = mBottomRightRadius
1067 | this.mBottomLeftRadius = mBottomLeftRadius
1068 | return this
1069 | }
1070 |
1071 | fun setRadii(mRadii: FloatArray): SmartProgressBar {
1072 | this.mRadii = mRadii
1073 | return this
1074 | }
1075 |
1076 | fun setIsShowPercentSign(mIsShowPercentSign: Boolean): SmartProgressBar {
1077 | this.mIsShowPercentSign = mIsShowPercentSign
1078 | return this
1079 | }
1080 |
1081 | fun setIsShowPercentText(mIsShowPercentText: Boolean): SmartProgressBar {
1082 | this.mIsShowPercentText = mIsShowPercentText
1083 | return this
1084 | }
1085 |
1086 | fun setIsAnimated(mIsAnimated: Boolean): SmartProgressBar {
1087 | this.mIsAnimated = mIsAnimated
1088 | return this
1089 | }
1090 |
1091 | fun setDuration(mDuration: Long): SmartProgressBar {
1092 | this.mDuration = mDuration
1093 | return this
1094 | }
1095 |
1096 | fun setAnimatorUpdateListener(mAnimatorUpdateListener: ValueAnimator.AnimatorUpdateListener?): SmartProgressBar {
1097 | this.mAnimatorUpdateListener = mAnimatorUpdateListener
1098 | return this
1099 | }
1100 |
1101 | fun setShowShadow(showShadow: Boolean): SmartProgressBar {
1102 | this.mShowShadow = showShadow
1103 | return this
1104 | }
1105 |
1106 | fun setMax(max: Float): SmartProgressBar {
1107 | this.mMaxProgress = max
1108 | return this
1109 | }
1110 |
1111 | /**
1112 | * 设置进度,没有动画
1113 | */
1114 | fun setProgressWithNoAnimation(progress: Float): SmartProgressBar {
1115 | post {
1116 | cancelProgressAnimation()
1117 | val lastProgress = this.mProgress
1118 | startProgressAnimation(lastProgress, progress, 0)
1119 | }
1120 | return this
1121 | }
1122 |
1123 | /**
1124 | * 设置进度,利用动画更新进度
1125 | */
1126 | fun setProgress(progress: Float, duration: Long = 0): SmartProgressBar {
1127 | val delay = when {
1128 | mIsAnimated -> mDuration + 1000
1129 | else -> 1000
1130 | }
1131 | postDelayed({
1132 | cancelProgressAnimation()
1133 | val lastProgress = this.mProgress
1134 | when {
1135 | progress > mMaxProgress -> {
1136 | this.mProgress = mMaxProgress
1137 | }
1138 | progress < 0 -> {
1139 | this.mProgress = 0f
1140 | }
1141 | }
1142 | startProgressAnimation(lastProgress, progress, duration)
1143 | }, delay)
1144 | return this
1145 | }
1146 |
1147 | fun getMax(): Float {
1148 | return mMaxProgress
1149 | }
1150 |
1151 | fun getProgress(): Float {
1152 | return mProgress
1153 | }
1154 |
1155 | fun addProgressAnimatorUpdateListener(progressAnimatorUpdateListener: ValueAnimator.AnimatorUpdateListener): SmartProgressBar {
1156 | this.mProgressAnimatorUpdateListener.add(progressAnimatorUpdateListener)
1157 | return this
1158 | }
1159 |
1160 | fun addProgressAnimatorListener(progressAnimatorListener: Animator.AnimatorListener): SmartProgressBar {
1161 | this.mProgressAnimatorListener.add(progressAnimatorListener)
1162 | return this
1163 | }
1164 |
1165 | /**
1166 | * 开始进度动画
1167 | */
1168 | private fun startProgressAnimation(lastProgress: Float, progress: Float, duration: Long) {
1169 | mProgressAnimator.apply {
1170 | setFloatValues(lastProgress, progress)
1171 | interpolator = LinearInterpolator()
1172 | this.duration = duration
1173 | removeAllUpdateListeners()
1174 | removeAllListeners()
1175 | addUpdateListener(this@SmartProgressBar)
1176 | mProgressAnimatorUpdateListener.forEach {
1177 | addUpdateListener(it)
1178 | }
1179 | mProgressAnimatorListener.forEach {
1180 | addListener(it)
1181 | }
1182 | start()
1183 | }
1184 | }
1185 |
1186 | /**
1187 | * 暂停进度动画
1188 | */
1189 | fun pauseProgressAnimation() {
1190 | mProgressAnimator.pause()
1191 | }
1192 |
1193 | /**
1194 | * 恢复进度动画
1195 | */
1196 | fun resumeProgressAnimation() {
1197 | mProgressAnimator.resume()
1198 | }
1199 |
1200 | /**
1201 | * 取消进度动画
1202 | */
1203 | fun cancelProgressAnimation() {
1204 | mProgressAnimator.apply {
1205 | removeAllUpdateListeners()
1206 | removeAllListeners()
1207 | cancel()
1208 | }
1209 | }
1210 |
1211 | override fun onAnimationUpdate(animation: ValueAnimator) {
1212 | val animatedValue = animation.animatedValue as Float
1213 | mProgress = when {
1214 | animatedValue >= mMaxProgress -> {
1215 | mMaxProgress
1216 | }
1217 | animatedValue <= 0 -> {
1218 | 0f
1219 | }
1220 | else -> {
1221 | animatedValue
1222 | }
1223 | }
1224 | post {
1225 | postInvalidate()
1226 | }
1227 | }
1228 |
1229 | /**
1230 | * dp转px
1231 | *
1232 | * @param dpValue dp值
1233 | * @return px值
1234 | */
1235 | private fun dp2px(dpValue: Float): Int {
1236 | val scale = context.resources.displayMetrics.density
1237 | return (dpValue * scale + 0.5f).toInt()
1238 | }
1239 |
1240 | companion object {
1241 | private const val DEFAULT_WIDTH = 100f
1242 | private const val DEFAULT_HEIGHT = 100f
1243 | private const val DEFAULT_PROGRESS_COLOR = Color.BLUE
1244 | private const val DEFAULT_PROGRESS_BAR_BG_COLOR = Color.WHITE
1245 | private const val DEFAULT_PERCENT_TEXT_COLOR = Color.BLACK
1246 | private const val DEFAULT_PERCENT_TEXT_SIZE = 15f
1247 | private const val DEFAULT_BORDER_COLOR = Color.RED
1248 | private const val DEFAULT_MAX = 100f
1249 | private const val DEFAULT_ANIMATION_DURATION = 1000L
1250 | }
1251 |
1252 | init {
1253 | initAttrs(context, attrs, defStyleAttr)
1254 | init()
1255 | }
1256 | }
--------------------------------------------------------------------------------
/smartProgressBar/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------