├── .github
└── workflows
│ └── android.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE.txt
├── MIGRATION.md
├── README.md
├── app
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── com
│ │ └── akexorcist
│ │ └── roundcornerprogressbar
│ │ └── example
│ │ ├── MainActivity.kt
│ │ ├── ViewPagerAdapter.kt
│ │ └── fragment
│ │ ├── CenteredDemoFragment.kt
│ │ ├── IconDemoFragment.kt
│ │ ├── IndeterminateDemoFragment.kt
│ │ ├── SimpleDemoFragment.kt
│ │ └── TextDemoFragment.kt
│ └── res
│ ├── drawable-hdpi
│ ├── ic_android.png
│ ├── ic_clock.png
│ ├── ic_download.png
│ └── ic_television.png
│ ├── drawable-mdpi
│ ├── ic_android.png
│ ├── ic_clock.png
│ ├── ic_download.png
│ └── ic_television.png
│ ├── drawable-night
│ └── shape_sample_card_background.xml
│ ├── drawable-xhdpi
│ ├── ic_android.png
│ ├── ic_clock.png
│ ├── ic_download.png
│ └── ic_television.png
│ ├── drawable-xxhdpi
│ ├── ic_android.png
│ ├── ic_clock.png
│ ├── ic_download.png
│ └── ic_television.png
│ ├── drawable
│ └── shape_sample_card_background.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── fragment_centered_demo.xml
│ ├── fragment_icon_demo.xml
│ ├── fragment_indeterminate_demo.xml
│ ├── fragment_simple_demo.xml
│ └── fragment_text_demo.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── values-night
│ └── colors.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── image
├── animation_comparison.gif
├── google_play.jpg
├── header.jpg
├── overview_centered.jpg
├── overview_icon.jpg
├── overview_indeterminate.gif
├── overview_simple.jpg
├── overview_text.jpg
├── sample_centered.jpg
├── sample_gradient.jpg
├── sample_icon.jpg
├── sample_indeterminate.gif
├── sample_indeterminate_centered.gif
├── sample_simple.jpg
└── sample_text.jpg
├── publish
└── mavencentral.gradle
├── round-corner-progress-bar
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── akexorcist
│ │ └── roundcornerprogressbar
│ │ ├── CenteredRoundCornerProgressBar.kt
│ │ ├── IconRoundCornerProgressBar.kt
│ │ ├── RoundCornerProgressBar.kt
│ │ ├── TextRoundCornerProgressBar.kt
│ │ ├── common
│ │ ├── AnimatedRoundCornerProgressBar.kt
│ │ └── BaseRoundCornerProgressBar.kt
│ │ └── indeterminate
│ │ ├── IndeterminateCenteredRoundCornerProgressBar.kt
│ │ └── IndeterminateRoundCornerProgressBar.kt
│ └── res
│ ├── layout
│ ├── layout_icon_round_corner_progress_bar.xml
│ ├── layout_round_corner_progress_bar.xml
│ └── layout_text_round_corner_progress_bar.xml
│ └── values
│ ├── attrs.xml
│ └── colors.xml
└── settings.gradle
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | test:
11 | name: Unit Test
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: set up JDK 1.8
17 | uses: actions/setup-java@v3
18 | with:
19 | distribution: 'adopt'
20 | java-version: '11'
21 | cache: 'gradle'
22 |
23 | - name: Grant execute permission for gradlew
24 | run: chmod +x gradlew
25 |
26 | - name: Run Clean
27 | run: ./gradlew clean
28 |
29 | - name: Run build compatibility test
30 | run: ./gradlew assembleDebug
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | #*.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
54 |
55 | # Freeline
56 | freeline.py
57 | freeline/
58 | freeline_project_description.json
59 |
60 | # fastlane
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots
64 | fastlane/test_output
65 | fastlane/readme.md
66 | .idea
67 | .DS_Store
68 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Release Notes
2 | ====
3 |
4 | 2.2.1
5 | --
6 | * Gradle 8.0
7 | * Android Gradle Plugin 8.1.0
8 | * Using Java 17 for Compile & Kotlin options
9 |
10 | 2.2.0
11 | --
12 | * Convert all Java classes to Kotlin
13 | * Gradle 7.5
14 | * Android Gradle Plugin 7.4.2
15 | * Kotlin 1.8.20
16 | * Compile & Target SDK version 33
17 | * Minimum SDK version 17
18 | * Update dependencies
19 | * AndroidX Annotation 1.6.0
20 |
21 | 2.1.2
22 | --
23 | * Fix unspecified module error
24 |
25 | 2.1.1
26 | --
27 | * Fix bug in ([#57](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/57)) ([#77](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/77))
28 |
29 | 2.1.0
30 | ----
31 | * `CenteredRoundCornerProgressBar` added ([#42](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/42))
32 | * `IndeterminateRoundCornerProgressBar` and `IndeterminateCenteredRoundCornerProgressBar` added
33 | * `IconRoundCornerProgressBar` now support for `Bitmap` and `Drawable` for icon
34 | * Animation for progress update (disable by default) added. This feature applied to all progress bars
35 | * Gradient progress color support (both primary and secondary progress) added. This feature applied to all progress bars (([#39](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/39)))
36 | * Text gravity when inside/outside and text position priority attribute in `TextRoundCornerProgressBar` added
37 | * Integer value support for progress setter (convert to float inside) added
38 | * Update to Gradle Plugin 3.6.3 and Gradle 5.6.4
39 | * Migrate from Android Support to AndroidX
40 | * Still in Java! (will be Kotlin in next version)
41 | * Fix bug in ([#43](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/43)) ([#20](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/20)) ([#74](https://github.com/akexorcist/Android-RoundCornerProgressBar/issues/74))
42 | * Moved from MavenCentral to JCenter. Please see "Installation" section for new artifact ID
43 | * All new sample code. You should try it!
44 | * Add useful annotations for Kotlin
45 |
46 | 2.0.X
47 | ----
48 | * New code structure for further development
49 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2023 Akexorcist
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/MIGRATION.md:
--------------------------------------------------------------------------------
1 | # Migration
2 |
3 | ## Migrate from 2.0 to 2.1+
4 |
5 | ### BaseRoundCornerProgressBar.OnProgressChangedListener
6 |
7 | Change the view ID parameter in `onProgressChanged` to View class
8 |
9 | ```kotlin
10 | // Old
11 | fun onProgressChanged(
12 | viewId: Int,
13 | progress: Float,
14 | isPrimaryProgress: Boolean,
15 | isSecondaryProgress: Boolean
16 | )
17 |
18 | // New
19 | fun onProgressChanged(
20 | view: View,
21 | progress: Float,
22 | isPrimaryProgress: Boolean,
23 | isSecondaryProgress: Boolean
24 | )
25 | ```
26 |
27 | ### Custom your own progress bar by extends BaseRoundCornerProgressBar
28 |
29 | Use AnimatedRoundCornerProgressBar instead of BaseRoundCornerProgressBar for progress change animation support.
30 |
31 | ```Kotlin
32 | class CustomRoundCornerProgressBar: AnimatedRoundCornerProgressBar() {
33 | /* ... */
34 | }
35 | ```
36 |
37 | And you do not have to create the `GradientDrawable` by yourself anymore. `drawProgress` will send it as parameter.
38 |
39 | ```kotlin
40 | // Old
41 | fun drawProgress(
42 | layoutProgress: LinearLayout,
43 | max: Float,
44 | progress: Float,
45 | totalWidth: Float,
46 | radius: Int,
47 | padding: Int,
48 | progressColor: Int,
49 | isReverse: Boolean
50 | )
51 |
52 | // New
53 | fun drawProgress(
54 | layoutProgress: LinearLayout,
55 | progressDrawable: GradientDrawable,
56 | max: Float,
57 | progress: Float,
58 | totalWidth: Float,
59 | radius: Int,
60 | padding: Int,
61 | isReverse: Boolean
62 | )
63 | ```
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-parcelize'
5 | }
6 |
7 | android {
8 | namespace 'com.akexorcist.roundcornerprogressbar.example'
9 | compileSdk project.compileSdkVersion
10 |
11 | defaultConfig {
12 | applicationId "com.akexorcist.roundcornerprogressbar"
13 | minSdkVersion project.minSdkVersion
14 | targetSdkVersion project.targetSdkVersion
15 | versionCode project.versionCode
16 | versionName project.versionName
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled true
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_17
28 | targetCompatibility JavaVersion.VERSION_17
29 | }
30 |
31 | kotlinOptions {
32 | jvmTarget = '17'
33 | }
34 |
35 | buildFeatures {
36 | viewBinding = true
37 | }
38 | }
39 |
40 | dependencies {
41 | implementation 'androidx.appcompat:appcompat:1.6.1'
42 | implementation 'com.google.android.material:material:1.10.0'
43 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
44 | testImplementation 'junit:junit:4.13.2'
45 | implementation project(':round-corner-progress-bar')
46 | // implementation "com.akexorcist:round-corner-progress-bar:${project.versionName}"
47 | }
48 |
--------------------------------------------------------------------------------
/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 /Applications/ADT/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/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.akexorcist.roundcornerprogressbar.example.databinding.ActivityMainBinding
6 | import com.google.android.material.tabs.TabLayoutMediator
7 |
8 | class MainActivity : AppCompatActivity() {
9 | private val binding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(binding.root)
14 |
15 | val adapter = ViewPagerAdapter(this)
16 | binding.viewPager.adapter = adapter
17 | TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
18 | tab.text = getString(
19 | when (position) {
20 | 0 -> R.string.tab_round_corner_progress_bar
21 | 1 -> R.string.tab_centered_round_corner_progress_bar
22 | 2 -> R.string.tab_icon_round_corner_progress_bar
23 | 3 -> R.string.tab_text_round_corner_progress_bar
24 | 4 -> R.string.tab_indeterminate_round_corner_progress_bar
25 | else -> R.string.blank
26 | }
27 | )
28 | }.attach()
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/ViewPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentActivity
5 | import androidx.viewpager2.adapter.FragmentStateAdapter
6 | import com.akexorcist.roundcornerprogressbar.example.fragment.*
7 |
8 | class ViewPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
9 | override fun getItemCount(): Int = 5
10 |
11 | override fun createFragment(position: Int): Fragment = when (position) {
12 | 0 -> SimpleDemoFragment.newInstance()
13 | 1 -> CenteredDemoFragment.newInstance()
14 | 2 -> IconDemoFragment.newInstance()
15 | 3 -> TextDemoFragment.newInstance()
16 | 4 -> IndeterminateDemoFragment.newInstance()
17 | else -> SimpleDemoFragment.newInstance()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/fragment/CenteredDemoFragment.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example.fragment
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import com.akexorcist.roundcornerprogressbar.example.R
9 | import com.akexorcist.roundcornerprogressbar.example.databinding.FragmentCenteredDemoBinding
10 |
11 | class
12 | CenteredDemoFragment : Fragment() {
13 | private lateinit var binding: FragmentCenteredDemoBinding
14 |
15 | companion object {
16 | fun newInstance(): Fragment = CenteredDemoFragment()
17 | }
18 |
19 | override fun onCreateView(
20 | inflater: LayoutInflater,
21 | container: ViewGroup?,
22 | savedInstanceState: Bundle?
23 | ): View {
24 | binding = FragmentCenteredDemoBinding.inflate(layoutInflater, container, false)
25 | return binding.root
26 | }
27 |
28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29 | super.onViewCreated(view, savedInstanceState)
30 | with(binding) {
31 | textViewCentered1.text = getCentered1Description()
32 | textViewCentered2.text = getCentered2Description()
33 | textViewCentered3.text = getCentered3Description()
34 | textViewCentered4.text = getCentered4Description()
35 | textViewCentered5.text = getCentered5Description()
36 | buttonCenteredCustomIncrease.setOnClickListener { increaseCustomProgress() }
37 | buttonCenteredCustomExtraIncrease.setOnClickListener { extraIncreaseCustomProgress() }
38 | buttonCenteredCustomDecrease.setOnClickListener { decreaseCustomProgress() }
39 | buttonCenteredCustomExtraDecrease.setOnClickListener { extraDecreaseCustomProgress() }
40 | checkBoxAnimationEnable.setOnCheckedChangeListener { _, isChecked ->
41 | onAnimationEnableCheckedChange(
42 | isChecked
43 | )
44 | }
45 | checkBoxGradientProgressColor.setOnCheckedChangeListener { _, isChecked ->
46 | onApplyGradientProgressColorCheckedChange(
47 | isChecked
48 | )
49 | }
50 | progressBarCenteredCustom.setOnProgressChangedListener { _, _, isPrimaryProgress, _ ->
51 | if (isPrimaryProgress) {
52 | updateCustomProgressText()
53 | }
54 | }
55 | }
56 | updateCustomProgressText()
57 | }
58 |
59 | private fun onAnimationEnableCheckedChange(isChecked: Boolean) {
60 | with(binding) {
61 | if (isChecked) {
62 | progressBarCenteredCustom.enableAnimation()
63 | } else {
64 | progressBarCenteredCustom.disableAnimation()
65 | }
66 | }
67 | }
68 |
69 | private fun onApplyGradientProgressColorCheckedChange(isChecked: Boolean) {
70 | with(binding) {
71 | if (isChecked) {
72 | progressBarCenteredCustom.setProgressColors(resources.getIntArray(R.array.sample_progress_gradient))
73 | } else {
74 | @Suppress("DEPRECATION")
75 | progressBarCenteredCustom.setProgress(resources.getColor(R.color.sample_progress_primary))
76 | }
77 | }
78 | }
79 |
80 | private fun increaseCustomProgress() {
81 | with(binding) {
82 | progressBarCenteredCustom.setProgress(progressBarCenteredCustom.getProgress() + 2)
83 | }
84 | updateCustomSecondaryProgress()
85 | }
86 |
87 | private fun extraIncreaseCustomProgress() {
88 | with(binding) {
89 | progressBarCenteredCustom.setProgress(progressBarCenteredCustom.getProgress() + 20)
90 | }
91 | updateCustomSecondaryProgress()
92 | }
93 |
94 | private fun decreaseCustomProgress() {
95 | with(binding) {
96 | progressBarCenteredCustom.setProgress(progressBarCenteredCustom.getProgress() - 2)
97 | }
98 | updateCustomSecondaryProgress()
99 | }
100 |
101 | private fun extraDecreaseCustomProgress() {
102 | with(binding) {
103 | progressBarCenteredCustom.setProgress(progressBarCenteredCustom.getProgress() - 20)
104 | }
105 | updateCustomSecondaryProgress()
106 | }
107 |
108 | private fun updateCustomSecondaryProgress() {
109 | with(binding) {
110 | progressBarCenteredCustom.setSecondaryProgress(progressBarCenteredCustom.getProgress() + 10)
111 | }
112 | }
113 |
114 | private fun updateCustomProgressText() {
115 | with(binding) {
116 | textViewCenteredCustom.text = "${progressBarCenteredCustom.getProgress()}"
117 | }
118 | }
119 |
120 | private fun getCentered1Description() = """
121 | |Max : 100
122 | |Progress : 50
123 | |Radius : 0dp
124 | |Padding : 4dp
125 | |Width : 260dp
126 | |Height : 30dp
127 | """.trimMargin()
128 |
129 | private fun getCentered2Description() = """
130 | |Max : 100
131 | |Progress : 40
132 | |SecondaryProgress : 60
133 | |Radius : 10dp
134 | |Radius : 10dp
135 | |Padding : 2dp
136 | |Width : 260dp
137 | |Height : 30dp
138 | """.trimMargin()
139 |
140 | private fun getCentered3Description() = """
141 | |Max : 100
142 | |Progress : 20
143 | |SecondaryProgress : 75
144 | |Radius : 80dp
145 | |Padding : 2dp
146 | |Reverse : True
147 | |Width : 260dp
148 | |Height : 30dp
149 | """.trimMargin()
150 |
151 | private fun getCentered4Description() = """
152 | |Max : 100
153 | |Progress : 80
154 | |Radius : 20dp
155 | |Padding : 2dp
156 | |Width : 260dp
157 | |Height : 20dp
158 | """.trimMargin()
159 |
160 | private fun getCentered5Description() = """
161 | |Max : 200
162 | |Progress : 20
163 | |Radius : 20dp
164 | |Padding : 10dp
165 | |Width : 260dp
166 | |Height : 50dp
167 | """.trimMargin()
168 | }
169 |
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/fragment/IconDemoFragment.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example.fragment
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import com.akexorcist.roundcornerprogressbar.example.R
9 | import com.akexorcist.roundcornerprogressbar.example.databinding.FragmentIconDemoBinding
10 |
11 | class IconDemoFragment : Fragment() {
12 | private lateinit var binding: FragmentIconDemoBinding
13 |
14 | companion object {
15 | fun newInstance(): Fragment = IconDemoFragment()
16 | }
17 |
18 | override fun onCreateView(
19 | inflater: LayoutInflater,
20 | container: ViewGroup?,
21 | savedInstanceState: Bundle?
22 | ): View {
23 | binding = FragmentIconDemoBinding.inflate(layoutInflater, container, false)
24 | return binding.root
25 | }
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 | with(binding) {
30 | textViewIcon1.text = getIcon1Description()
31 | textViewIcon2.text = getIcon2Description()
32 | textViewIcon3.text = getIcon3Description()
33 | textViewIcon4.text = getIcon4Description()
34 | textViewIcon5.text = getIcon5Description()
35 | textViewIcon6.text = getIcon6Description()
36 | textViewIcon7.text = getIcon7Description()
37 | buttonIconCustomIncrease.setOnClickListener { increaseCustomProgress() }
38 | buttonIconCustomExtraIncrease.setOnClickListener { extraIncreaseCustomProgress() }
39 | buttonIconCustomDecrease.setOnClickListener { decreaseCustomProgress() }
40 | buttonIconCustomExtraDecrease.setOnClickListener { extraDecreaseCustomProgress() }
41 | checkBoxAnimationEnable.setOnCheckedChangeListener { _, isChecked ->
42 | onAnimationEnableCheckdChange(
43 | isChecked
44 | )
45 | }
46 | checkBoxGradientProgressColor.setOnCheckedChangeListener { _, isChecked ->
47 | onApplyGradientProgressColorCheckedChange(
48 | isChecked
49 | )
50 | }
51 | progressBarIconCustom.setOnProgressChangedListener { _, _, isPrimaryProgress, _ ->
52 | if (isPrimaryProgress) {
53 | updateCustomProgressText()
54 | }
55 | }
56 | }
57 | updateCustomProgressText()
58 | }
59 |
60 | private fun onAnimationEnableCheckdChange(isChecked: Boolean) {
61 | with(binding) {
62 | if (isChecked) {
63 | progressBarIconCustom.enableAnimation()
64 | } else {
65 | progressBarIconCustom.disableAnimation()
66 | }
67 | }
68 | }
69 |
70 | private fun onApplyGradientProgressColorCheckedChange(isChecked: Boolean) {
71 | with(binding) {
72 | if (isChecked) {
73 | progressBarIconCustom.setProgressColors(resources.getIntArray(R.array.sample_progress_gradient))
74 | } else {
75 | @Suppress("DEPRECATION")
76 | progressBarIconCustom.setProgressColor(resources.getColor(R.color.sample_progress_primary))
77 | }
78 | }
79 | }
80 |
81 | private fun increaseCustomProgress() {
82 | with(binding) {
83 | progressBarIconCustom.setProgress(progressBarIconCustom.getProgress() + 2)
84 | }
85 | updateCustomSecondaryProgress()
86 | }
87 |
88 | private fun extraIncreaseCustomProgress() {
89 | with(binding) {
90 | progressBarIconCustom.setProgress(progressBarIconCustom.getProgress() + 20)
91 | }
92 | updateCustomSecondaryProgress()
93 | }
94 |
95 | private fun decreaseCustomProgress() {
96 | with(binding) {
97 | progressBarIconCustom.setProgress(progressBarIconCustom.getProgress() - 2)
98 | }
99 | updateCustomSecondaryProgress()
100 | }
101 |
102 | private fun extraDecreaseCustomProgress() {
103 | with(binding) {
104 | progressBarIconCustom.setProgress(progressBarIconCustom.getProgress() - 20)
105 | }
106 | updateCustomSecondaryProgress()
107 | }
108 |
109 | private fun updateCustomSecondaryProgress() {
110 | with(binding) {
111 | progressBarIconCustom.setSecondaryProgress(progressBarIconCustom.getProgress() + 30)
112 | }
113 | }
114 |
115 | private fun updateCustomProgressText() {
116 | with(binding) {
117 | textViewIconCustom.text = "${progressBarIconCustom.getProgress()}"
118 | }
119 | }
120 |
121 | private fun getIcon1Description() = """
122 | |Max : 150
123 | |Progress : 90
124 | |Icon Size : 40dp
125 | |Icon Padding : 5dp
126 | |Radius : 5dp
127 | |Background Padding : 2dp
128 | |Width : 260dp
129 | |Height : Wrap Content
130 | """.trimMargin()
131 |
132 | private fun getIcon2Description() = """
133 | |Max : 150
134 | |Progress : 90
135 | |Icon Size : 40dp
136 | |Icon Padding : 5dp
137 | |Radius : 5dp
138 | |Background Padding : 2dp
139 | |Reverse : True
140 | |Width : 260dp
141 | |Height : Wrap Content
142 | """.trimMargin()
143 |
144 | private fun getIcon3Description() = """
145 | |Max : 150
146 | |Progress : 50
147 | |Secondary Progress : 80
148 | |Icon Size : 25dp
149 | |Icon Padding : 5dp
150 | |Radius : 5dp
151 | |Background Padding : 5dp
152 | |Reverse : True
153 | |Width : 260dp
154 | |Height : Wrap Content
155 | """.trimMargin()
156 |
157 | private fun getIcon4Description() = """
158 | |Max : 150
159 | |Progress : 40
160 | |Icon Size : 70dp
161 | |Icon Padding : 5dp
162 | |Radius : 5dp
163 | |Background Padding : 10dp
164 | |Width : 260dp
165 | |Height : Wrap Content
166 | """.trimMargin()
167 |
168 | private fun getIcon5Description() = """
169 | |Max : 150
170 | |Progress : 150
171 | |Icon Size : 30dp
172 | |Icon Padding : 3dp
173 | |Radius : 5dp
174 | |Background Padding : 5dp
175 | |Width : 260dp
176 | |Height : Wrap Content
177 | """.trimMargin()
178 |
179 | private fun getIcon6Description() = """
180 | |Max : 150
181 | |Progress : 5
182 | |Icon Size : 50dp
183 | |Icon Padding : 3dp
184 | |Radius : 20dp
185 | |Background Padding : 10dp
186 | |Width : 260dp
187 | |Height : Wrap Content
188 | """.trimMargin()
189 |
190 | private fun getIcon7Description() = """
191 | |No Icon Image
192 | |Max : 150
193 | |Progress : 100
194 | |Icon Size : 20dp
195 | |Icon Padding : 10dp
196 | |Radius : 30dp
197 | |Background Padding : 5dp
198 | |Width : 260dp
199 | |Height : Wrap Content
200 | """.trimMargin()
201 | }
202 |
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/fragment/IndeterminateDemoFragment.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example.fragment
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import com.akexorcist.roundcornerprogressbar.example.databinding.FragmentIndeterminateDemoBinding
9 |
10 | class IndeterminateDemoFragment : Fragment() {
11 | private lateinit var binding: FragmentIndeterminateDemoBinding
12 |
13 | companion object {
14 | fun newInstance(): Fragment = IndeterminateDemoFragment()
15 | }
16 |
17 | override fun onCreateView(
18 | inflater: LayoutInflater,
19 | container: ViewGroup?,
20 | savedInstanceState: Bundle?
21 | ): View {
22 | binding = FragmentIndeterminateDemoBinding.inflate(layoutInflater, container, false)
23 | return binding.root
24 | }
25 |
26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
27 | super.onViewCreated(view, savedInstanceState)
28 | with(binding) {
29 | textViewIndeterminate1.text = getIndeterminate1Description()
30 | textViewIndeterminate2.text = getIndeterminate2Description()
31 | textViewIndeterminate3.text = getIndeterminate3Description()
32 | textViewIndeterminate4.text = getIndeterminate4Description()
33 | }
34 | }
35 |
36 | private fun getIndeterminate1Description() = """
37 | |Animation Speed Scale : x1
38 | """.trimMargin()
39 |
40 | private fun getIndeterminate2Description() = """
41 | |Animation Speed Scale : x3
42 | """.trimMargin()
43 |
44 | private fun getIndeterminate3Description() = """
45 | |Animation Speed Scale : x0.5
46 | """.trimMargin()
47 |
48 | private fun getIndeterminate4Description() = """
49 | |Animation Speed Scale : x1
50 | """.trimMargin()
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/fragment/SimpleDemoFragment.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example.fragment
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import com.akexorcist.roundcornerprogressbar.example.R
9 | import com.akexorcist.roundcornerprogressbar.example.databinding.FragmentSimpleDemoBinding
10 |
11 | class SimpleDemoFragment : Fragment() {
12 | private lateinit var binding: FragmentSimpleDemoBinding
13 |
14 | companion object {
15 | fun newInstance(): Fragment = SimpleDemoFragment()
16 | }
17 |
18 | override fun onCreateView(
19 | inflater: LayoutInflater,
20 | container: ViewGroup?,
21 | savedInstanceState: Bundle?
22 | ): View {
23 | binding = FragmentSimpleDemoBinding.inflate(layoutInflater, container, false)
24 | return binding.root
25 | }
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 | with(binding) {
30 | textViewSimple1.text = getSimple1Description()
31 | textViewSimple2.text = getSimple2Description()
32 | textViewSimple3.text = getSimple3Description()
33 | textViewSimple4.text = getSimple4Description()
34 | textViewSimple5.text = getSimple5Description()
35 | buttonSimpleCustomIncrease.setOnClickListener { increaseCustomProgress() }
36 | buttonSimpleCustomExtraIncrease.setOnClickListener { extraIncreaseCustomProgress() }
37 | buttonSimpleCustomDecrease.setOnClickListener { decreaseCustomProgress() }
38 | buttonSimpleCustomExtraDecrease.setOnClickListener { extraDecreaseCustomProgress() }
39 | checkBoxAnimationEnable.setOnCheckedChangeListener { _, isChecked ->
40 | onAnimationEnableCheckedChange(
41 | isChecked
42 | )
43 | }
44 | checkBoxGradientProgressColor.setOnCheckedChangeListener { _, isChecked ->
45 | onApplyGradientProgressColorCheckedChange(
46 | isChecked
47 | )
48 | }
49 | progressBarSimpleCustom.setOnProgressChangedListener { _, _, isPrimaryProgress, _ ->
50 | if (isPrimaryProgress) {
51 | updateCustomProgressText()
52 | }
53 | }
54 | }
55 | updateCustomProgressText()
56 | }
57 |
58 | private fun onAnimationEnableCheckedChange(isChecked: Boolean) {
59 | with(binding) {
60 | if (isChecked) {
61 | progressBarSimpleCustom.enableAnimation()
62 | } else {
63 | progressBarSimpleCustom.disableAnimation()
64 | }
65 | }
66 | }
67 |
68 | private fun onApplyGradientProgressColorCheckedChange(isChecked: Boolean) {
69 | with(binding) {
70 | if (isChecked) {
71 | progressBarSimpleCustom.setProgressColors(resources.getIntArray(R.array.sample_progress_gradient))
72 | } else {
73 | @Suppress("DEPRECATION")
74 | progressBarSimpleCustom.setProgressColor(resources.getColor(R.color.sample_progress_primary))
75 | }
76 | }
77 | }
78 |
79 | private fun increaseCustomProgress() {
80 | with(binding) {
81 | progressBarSimpleCustom.setProgress(progressBarSimpleCustom.getProgress() + 2)
82 | }
83 | updateCustomSecondaryProgress()
84 | }
85 |
86 | private fun extraIncreaseCustomProgress() {
87 | with(binding) {
88 | progressBarSimpleCustom.setProgress(progressBarSimpleCustom.getProgress() + 20)
89 | }
90 | updateCustomSecondaryProgress()
91 | }
92 |
93 | private fun decreaseCustomProgress() {
94 | with(binding) {
95 | progressBarSimpleCustom.setProgress(progressBarSimpleCustom.getProgress() - 2)
96 | }
97 | updateCustomSecondaryProgress()
98 | }
99 |
100 | private fun extraDecreaseCustomProgress() {
101 | with(binding) {
102 | progressBarSimpleCustom.setProgress(progressBarSimpleCustom.getProgress() - 20)
103 | }
104 | updateCustomSecondaryProgress()
105 | }
106 |
107 | private fun updateCustomSecondaryProgress() {
108 | with(binding) {
109 | progressBarSimpleCustom.setSecondaryProgress(progressBarSimpleCustom.getProgress() + 10)
110 | }
111 | }
112 |
113 | private fun updateCustomProgressText() {
114 | with(binding) {
115 | textViewSimpleCustom.text = "${progressBarSimpleCustom.getProgress()}"
116 | }
117 | }
118 |
119 | private fun getSimple1Description() = """
120 | |Max : 100
121 | |Progress : 50
122 | |Radius : 0dp
123 | |Padding : 4dp
124 | |Width : 260dp
125 | |Height : 30dp
126 | """.trimMargin()
127 |
128 | private fun getSimple2Description() = """
129 | |Max : 100
130 | |Progress : 40
131 | |SecondaryProgress : 60
132 | |Radius : 10dp
133 | |Padding : 2dp
134 | |Width : 260dp
135 | |Height : 30dp
136 | """.trimMargin()
137 |
138 | private fun getSimple3Description() = """
139 | |Max : 100
140 | |Progress : 20
141 | |SecondaryProgress : 75
142 | |Radius : 80dp
143 | |Padding : 2dp
144 | |Reverse : True
145 | |Width : 260dp
146 | |Height : 30dp
147 | """.trimMargin()
148 |
149 | private fun getSimple4Description() = """
150 | |Max : 100
151 | |Progress : 80
152 | |Radius : 20dp
153 | |Padding : 2dp
154 | |Width : 260dp
155 | |Height : 20dp
156 | """.trimMargin()
157 |
158 | private fun getSimple5Description() = """
159 | |Max : 200
160 | |Progress : 20
161 | |Radius : 20dp
162 | |Padding : 10dp
163 | |Width : 260dp
164 | |Height : 50dp
165 | """.trimMargin()
166 | }
167 |
--------------------------------------------------------------------------------
/app/src/main/java/com/akexorcist/roundcornerprogressbar/example/fragment/TextDemoFragment.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.example.fragment
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import com.akexorcist.roundcornerprogressbar.TextRoundCornerProgressBar
9 | import com.akexorcist.roundcornerprogressbar.example.databinding.FragmentTextDemoBinding
10 |
11 | class TextDemoFragment : Fragment() {
12 | private lateinit var binding: FragmentTextDemoBinding
13 |
14 | companion object {
15 | fun newInstance(): Fragment = TextDemoFragment()
16 | }
17 |
18 | override fun onCreateView(
19 | inflater: LayoutInflater,
20 | container: ViewGroup?,
21 | savedInstanceState: Bundle?
22 | ): View {
23 | binding = FragmentTextDemoBinding.inflate(layoutInflater, container, false)
24 | return binding.root
25 | }
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 | with(binding) {
30 | textViewText1.text = getText1Description()
31 | textViewText2.text = getText2Description()
32 | textViewText3.text = getText3Description()
33 | textViewText4.text = getText4Description()
34 | textViewText5.text = getText5Description()
35 | buttonTextCustomIncrease.setOnClickListener { increaseCustomProgress() }
36 | buttonTextCustomExtraIncrease.setOnClickListener { extraIncreaseCustomProgress() }
37 | buttonTextCustomDecrease.setOnClickListener { decreaseCustomProgress() }
38 | buttonTextCustomExtraDecrease.setOnClickListener { extraDecreaseCustomProgress() }
39 | checkBoxAnimationEnable.setOnCheckedChangeListener { _, isChecked ->
40 | onAnimationEnableCheckdChange(
41 | isChecked
42 | )
43 | }
44 | progressBarTextCustom.setOnProgressChangedListener { _, _, isPrimaryProgress, _ ->
45 | if (isPrimaryProgress) {
46 | updateCustomProgressText()
47 | }
48 | }
49 | radioButtonInsideGravityStart.setOnCheckedChangeListener { _, isChecked ->
50 | if (isChecked) {
51 | updateInsideTextGravityCustomProgress(TextRoundCornerProgressBar.GRAVITY_START)
52 | }
53 | }
54 | radioButtonInsideGravityEnd.setOnCheckedChangeListener { _, isChecked ->
55 | if (isChecked) {
56 | updateInsideTextGravityCustomProgress(TextRoundCornerProgressBar.GRAVITY_END)
57 | }
58 | }
59 | radioButtonOutsideGravityStart.setOnCheckedChangeListener { _, isChecked ->
60 | if (isChecked) {
61 | updateOutsideTextGravityCustomProgress(TextRoundCornerProgressBar.GRAVITY_START)
62 | }
63 | }
64 | radioButtonOutsideGravityEnd.setOnCheckedChangeListener { _, isChecked ->
65 | if (isChecked) {
66 | updateOutsideTextGravityCustomProgress(TextRoundCornerProgressBar.GRAVITY_END)
67 | }
68 | }
69 | radioButtonTextPositionPriorityInside.setOnCheckedChangeListener { _, isChecked ->
70 | if (isChecked) {
71 | updateTextPositionPriorityCustomProgress(TextRoundCornerProgressBar.PRIORITY_INSIDE)
72 | }
73 | }
74 | radioButtonTextPositionPriorityOutside.setOnCheckedChangeListener { _, isChecked ->
75 | if (isChecked) {
76 | updateTextPositionPriorityCustomProgress(TextRoundCornerProgressBar.PRIORITY_OUTSIDE)
77 | }
78 | }
79 | }
80 | updateCustomProgressText()
81 | }
82 |
83 | private fun onAnimationEnableCheckdChange(isChecked: Boolean) {
84 | with(binding) {
85 | if (isChecked) {
86 | progressBarTextCustom.enableAnimation()
87 | } else {
88 | progressBarTextCustom.disableAnimation()
89 | }
90 | }
91 | }
92 |
93 | private fun increaseCustomProgress() {
94 | with(binding) {
95 | progressBarTextCustom.setProgress(progressBarTextCustom.getProgress() + 2)
96 | }
97 | }
98 |
99 | private fun extraIncreaseCustomProgress() {
100 | with(binding) {
101 | progressBarTextCustom.setProgress(progressBarTextCustom.getProgress() + 20)
102 | }
103 | }
104 |
105 | private fun decreaseCustomProgress() {
106 | with(binding) {
107 | progressBarTextCustom.setProgress(progressBarTextCustom.getProgress() - 2)
108 | }
109 | }
110 |
111 | private fun extraDecreaseCustomProgress() {
112 | with(binding) {
113 | progressBarTextCustom.setProgress(progressBarTextCustom.getProgress() - 20)
114 | }
115 | }
116 |
117 | private fun updateInsideTextGravityCustomProgress(gravity: Int) {
118 | with(binding) {
119 | progressBarTextCustom.setTextInsideGravity(gravity)
120 | }
121 | }
122 |
123 | private fun updateOutsideTextGravityCustomProgress(gravity: Int) {
124 | with(binding) {
125 | progressBarTextCustom.setTextOutsideGravity(gravity)
126 | }
127 | }
128 |
129 | private fun updateTextPositionPriorityCustomProgress(priority: Int) {
130 | with(binding) {
131 | progressBarTextCustom.setTextPositionPriority(priority)
132 | }
133 | }
134 |
135 | private fun updateCustomProgressText() {
136 | with(binding) {
137 | progressBarTextCustom.setProgressText("${progressBarTextCustom.getProgress()}")
138 | }
139 | }
140 |
141 | private fun getText1Description() = """
142 | |Max : 100
143 | |Progress : 50
144 | |Radius : 0dp
145 | |Padding : 4dp
146 | |Width : 260dp
147 | |Height : 30dp
148 | """.trimMargin()
149 |
150 | private fun getText2Description() = """
151 | |Max : 100
152 | |Progress : 40
153 | |SecondaryProgress : 60
154 | |Radius : 10dp
155 | |Padding : 2dp
156 | |Text Inside Gravity : End
157 | |Width : 260dp
158 | |Height : 30dp
159 | """.trimMargin()
160 |
161 | private fun getText3Description() = """
162 | |Max : 100
163 | |Progress : 20
164 | |SecondaryProgress : 75
165 | |Radius : 80dp
166 | |Padding : 2dp
167 | |Reverse : True
168 | |Text Position Priority : Outside
169 | |Width : 260dp
170 | |Height : 30dp
171 | """.trimMargin()
172 |
173 | private fun getText4Description() = """
174 | |Max : 100
175 | |Progress : 80
176 | |Radius : 20dp
177 | |Padding : 2dp
178 | |Text Size : 12sp
179 | |Width : 260dp
180 | |Height : 20dp
181 | """.trimMargin()
182 |
183 | private fun getText5Description() = """
184 | |Max : 200
185 | |Progress : 20
186 | |Radius : 20dp
187 | |Padding : 10dp
188 | |Width : 260dp
189 | |Height : 50dp
190 | """.trimMargin()
191 | }
192 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-hdpi/ic_android.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-hdpi/ic_clock.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-hdpi/ic_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_television.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-hdpi/ic_television.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-mdpi/ic_android.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-mdpi/ic_clock.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-mdpi/ic_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_television.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-mdpi/ic_television.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/shape_sample_card_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xhdpi/ic_android.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xhdpi/ic_clock.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xhdpi/ic_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_television.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xhdpi/ic_television.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xxhdpi/ic_android.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xxhdpi/ic_clock.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xxhdpi/ic_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_television.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/drawable-xxhdpi/ic_television.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_sample_card_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
21 |
22 |
25 |
26 |
29 |
30 |
33 |
34 |
37 |
38 |
39 |
40 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_centered_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
30 |
31 |
43 |
44 |
50 |
51 |
56 |
57 |
61 |
62 |
71 |
72 |
77 |
78 |
82 |
83 |
84 |
90 |
91 |
96 |
97 |
98 |
99 |
104 |
105 |
114 |
115 |
124 |
125 |
126 |
127 |
132 |
133 |
144 |
145 |
154 |
155 |
156 |
157 |
162 |
163 |
175 |
176 |
185 |
186 |
187 |
188 |
193 |
194 |
203 |
204 |
213 |
214 |
215 |
216 |
221 |
222 |
231 |
232 |
241 |
242 |
243 |
244 |
245 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_icon_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
30 |
31 |
47 |
48 |
54 |
55 |
60 |
61 |
65 |
66 |
75 |
76 |
81 |
82 |
86 |
87 |
88 |
94 |
95 |
100 |
101 |
102 |
103 |
108 |
109 |
122 |
123 |
132 |
133 |
134 |
135 |
140 |
141 |
155 |
156 |
165 |
166 |
167 |
168 |
173 |
174 |
190 |
191 |
200 |
201 |
202 |
203 |
208 |
209 |
222 |
223 |
232 |
233 |
234 |
235 |
240 |
241 |
254 |
255 |
264 |
265 |
266 |
267 |
272 |
273 |
286 |
287 |
296 |
297 |
298 |
299 |
304 |
305 |
318 |
319 |
328 |
329 |
330 |
331 |
332 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_indeterminate_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
30 |
31 |
36 |
37 |
46 |
47 |
48 |
53 |
54 |
60 |
61 |
70 |
71 |
72 |
80 |
81 |
86 |
87 |
93 |
94 |
103 |
104 |
105 |
110 |
111 |
116 |
117 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_simple_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
30 |
31 |
43 |
44 |
50 |
51 |
56 |
57 |
61 |
62 |
71 |
72 |
77 |
78 |
82 |
83 |
84 |
90 |
91 |
96 |
97 |
98 |
99 |
104 |
105 |
114 |
115 |
124 |
125 |
126 |
127 |
132 |
133 |
144 |
145 |
154 |
155 |
156 |
157 |
162 |
163 |
175 |
176 |
185 |
186 |
187 |
188 |
193 |
194 |
203 |
204 |
213 |
214 |
215 |
216 |
221 |
222 |
231 |
232 |
241 |
242 |
243 |
244 |
245 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_text_demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
30 |
31 |
46 |
47 |
53 |
54 |
59 |
60 |
64 |
65 |
69 |
70 |
75 |
76 |
80 |
81 |
82 |
87 |
88 |
94 |
95 |
100 |
101 |
107 |
108 |
113 |
114 |
115 |
121 |
122 |
127 |
128 |
134 |
135 |
140 |
141 |
142 |
148 |
149 |
154 |
155 |
161 |
162 |
167 |
168 |
169 |
170 |
171 |
176 |
177 |
188 |
189 |
198 |
199 |
200 |
201 |
206 |
207 |
221 |
222 |
231 |
232 |
233 |
234 |
239 |
240 |
255 |
256 |
265 |
266 |
267 |
268 |
273 |
274 |
286 |
287 |
296 |
297 |
298 |
299 |
304 |
305 |
316 |
317 |
326 |
327 |
328 |
329 |
330 |
--------------------------------------------------------------------------------
/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/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #6200EE
5 | #6200EE
6 | #E91E63
7 |
8 | #10FFFFFF
9 |
10 | #10FFFFFF
11 | #C62828
12 | #F44336
13 | #40F44336
14 | #C62828
15 | #E57373
16 | #FFFFFF
17 |
18 |
19 | - @color/sample_progress_gradient_start
20 | - @color/sample_progress_gradient_end
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #6200EE
5 | #6200EE
6 | #E91E63
7 |
8 | #FFFFFF
9 | #0A000000
10 |
11 | #0A000000
12 | #D32F2F
13 | #EF5350
14 | #40EF5350
15 | #D32F2F
16 | #E57373
17 | #222222
18 |
19 |
20 | - @color/sample_progress_gradient_start
21 | - @color/sample_progress_gradient_end
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 | 2dp
4 | 260dp
5 | 16sp
6 | 12sp
7 | 8dp
8 | 8dp
9 | 16dp
10 | 8dp
11 | 16dp
12 | 24dp
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RoundCornerProgressBar Demo
3 |
4 |
5 |
6 | Simple
7 | Centered
8 | Icon
9 | Text
10 | Indeterminate
11 |
12 | Round Corner Progress Bar
13 | Centered Round Corner Progress Bar
14 | Icon Round Corner Progress Bar
15 | Text Round Corner Progress Bar
16 | Indeterminate Round Corner Progress Bar
17 | Indeterminate Centered Round Corner Progress Bar
18 |
19 | -2
20 | -20
21 | +2
22 | +20
23 | Enable Animation
24 | Gradient Progress Color
25 | Start
26 | End
27 | Inside Text Gravity
28 | Outside Text Gravity
29 | Text Position Priority
30 | Inside
31 | Outside
32 | Loading...
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
16 |
17 |
22 |
23 |
31 |
32 |
36 |
37 |
41 |
42 |
46 |
47 |
51 |
52 |
56 |
57 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | project.ext {
3 | compileSdkVersion = 34
4 | targetSdkVersion = 34
5 | minSdkVersion = 17
6 |
7 | versionName = '2.2.1'
8 | versionCode = 20201
9 | }
10 | }
11 |
12 | plugins {
13 | id 'com.android.application' version '8.1.3' apply false
14 | id 'com.android.library' version '8.1.3' apply false
15 | id 'org.jetbrains.kotlin.android' version '1.9.20' apply false
16 | id 'org.jetbrains.dokka-android' version '0.9.18' apply false
17 | }
18 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 | android.defaults.buildfeatures.buildconfig=true
23 | android.nonTransitiveRClass=false
24 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 13 22:23:18 ICT 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-8.0-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/image/animation_comparison.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/animation_comparison.gif
--------------------------------------------------------------------------------
/image/google_play.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/google_play.jpg
--------------------------------------------------------------------------------
/image/header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/header.jpg
--------------------------------------------------------------------------------
/image/overview_centered.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/overview_centered.jpg
--------------------------------------------------------------------------------
/image/overview_icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/overview_icon.jpg
--------------------------------------------------------------------------------
/image/overview_indeterminate.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/overview_indeterminate.gif
--------------------------------------------------------------------------------
/image/overview_simple.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/overview_simple.jpg
--------------------------------------------------------------------------------
/image/overview_text.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/overview_text.jpg
--------------------------------------------------------------------------------
/image/sample_centered.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_centered.jpg
--------------------------------------------------------------------------------
/image/sample_gradient.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_gradient.jpg
--------------------------------------------------------------------------------
/image/sample_icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_icon.jpg
--------------------------------------------------------------------------------
/image/sample_indeterminate.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_indeterminate.gif
--------------------------------------------------------------------------------
/image/sample_indeterminate_centered.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_indeterminate_centered.gif
--------------------------------------------------------------------------------
/image/sample_simple.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_simple.jpg
--------------------------------------------------------------------------------
/image/sample_text.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akexorcist/RoundCornerProgressBar/1c5823c91fd9572a081b4e625cc73b0e3475955c/image/sample_text.jpg
--------------------------------------------------------------------------------
/publish/mavencentral.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'signing'
3 |
4 | task androidJavadocJar(type: Jar) {
5 | archiveClassifier.set('javadoc')
6 | from("$buildDir/javadoc")
7 | }
8 |
9 | task androidSourcesJar(type: Jar) {
10 | archiveClassifier.set('sources')
11 | if (project.plugins.findPlugin("com.android.library")) {
12 | from android.sourceSets.main.java.srcDirs
13 | from android.sourceSets.main.kotlin.srcDirs
14 | } else {
15 | from sourceSets.main.java.srcDirs
16 | from sourceSets.main.kotlin.srcDirs
17 | }
18 | }
19 |
20 | group = project.groupId
21 | version = project.versionName
22 |
23 | ext["signing.keyId"] = ''
24 | ext["signing.password"] = ''
25 | ext["signing.secretKeyRingFile"] = ''
26 | ext["ossrhUsername"] = ''
27 | ext["ossrhPassword"] = ''
28 | ext["sonatypeStagingProfileId"] = ''
29 |
30 | ext["signing.keyId"] = getEnvironmentOrPropertyValue('SIGNING_KEY_ID')
31 | ext["signing.password"] = getEnvironmentOrPropertyValue('SIGNING_PASSWORD')
32 | ext["signing.secretKeyRingFile"] = getEnvironmentOrPropertyValue('SIGNING_SECRET_KEY_RING_FILE')
33 | ext["ossrhUsername"] = getEnvironmentOrPropertyValue('OSSRH_USERNAME')
34 | ext["ossrhPassword"] = getEnvironmentOrPropertyValue('OSSRH_PASSWORD')
35 | ext["sonatypeStagingProfileId"] = getEnvironmentOrPropertyValue('SONATYPE_STAGING_PROFILE_ID')
36 |
37 | private def getEnvironmentOrPropertyValue(String key) {
38 | return System.getenv(key) ?: getProperty(key) ?: ""
39 | }
40 |
41 | publishing {
42 | publications {
43 | release(MavenPublication) {
44 | groupId project.groupId
45 | artifactId project.artifactId
46 | version project.versionName
47 |
48 | if (project.plugins.findPlugin("com.android.library")) {
49 | artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
50 | } else {
51 | artifact("$buildDir/libs/${project.getName()}-${version}.jar")
52 | }
53 |
54 | artifact androidJavadocJar
55 | artifact androidSourcesJar
56 |
57 | pom {
58 | name = project.libraryName
59 | description = project.libraryDescription
60 | url = project.siteUrl
61 | licenses {
62 | license {
63 | name = project.licenseName
64 | url = project.licenseUrl
65 | }
66 | }
67 | developers {
68 | developer {
69 | id = project.developerId
70 | name = project.developName
71 | email = project.developerEmail
72 | }
73 | }
74 | scm {
75 | connection = project.gitUrl
76 | developerConnection = project.gitUrl
77 | url = project.siteUrl
78 | }
79 | withXml {
80 | def dependenciesNode = asNode().appendNode('dependencies')
81 | project.configurations.implementation.allDependencies.each {
82 | if (it.name != 'unspecified') {
83 | def dependencyNode = dependenciesNode.appendNode('dependency')
84 | dependencyNode.appendNode('groupId', it.group)
85 | dependencyNode.appendNode('artifactId', it.name)
86 | dependencyNode.appendNode('version', it.version)
87 | }
88 | }
89 | }
90 | }
91 | }
92 | }
93 | repositories {
94 | maven {
95 | name = "sonatype"
96 | url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
97 | credentials {
98 | username ossrhUsername
99 | password ossrhPassword
100 | }
101 | }
102 | }
103 | }
104 |
105 | signing {
106 | sign publishing.publications
107 | }
108 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | project.ext {
3 | libraryName = 'RoundCornerProgressBar'
4 | libraryDescription = 'Round corner is cool. Let\'s make your progress bar with round corner'
5 |
6 | groupId = 'com.akexorcist'
7 | artifactId = 'round-corner-progress-bar'
8 |
9 | siteUrl = 'https://github.com/akexorcist/Android-RoundCornerProgressBar'
10 | gitUrl = 'https://github.com/akexorcist/Android-RoundCornerProgressBar.git'
11 |
12 | developerId = 'akexorcist'
13 | developName = 'Somkiat Khitwongwattana'
14 | developerEmail = 'akexorcist@gmail.com'
15 |
16 | licenseName = 'The Apache License, Version 2.0'
17 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
18 | }
19 | }
20 |
21 | plugins {
22 | id 'com.android.library'
23 | id 'org.jetbrains.kotlin.android'
24 | id 'org.jetbrains.dokka-android'
25 | }
26 |
27 | android {
28 | namespace 'com.akexorcist.roundcornerprogressbar'
29 | compileSdk project.compileSdkVersion
30 |
31 | defaultConfig {
32 | minSdkVersion project.minSdkVersion
33 | targetSdkVersion project.targetSdkVersion
34 | }
35 |
36 | buildTypes {
37 | release {
38 | minifyEnabled false
39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
40 | }
41 | }
42 |
43 | sourceSets {
44 | main {
45 | manifest.srcFile 'src/main/AndroidManifest.xml'
46 | java.srcDirs = ['src/main/java']
47 | res.srcDirs = ['src/main/res']
48 | }
49 | }
50 |
51 | compileOptions {
52 | sourceCompatibility JavaVersion.VERSION_17
53 | targetCompatibility JavaVersion.VERSION_17
54 | }
55 |
56 | kotlinOptions {
57 | jvmTarget = '17'
58 | }
59 | }
60 |
61 | task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
62 | outputFormat = 'javadoc'
63 | outputDirectory = "$buildDir/javadoc"
64 | }
65 |
66 | dependencies {
67 | implementation "androidx.annotation:annotation:1.7.0"
68 | implementation "androidx.customview:customview:1.1.0"
69 | testImplementation 'junit:junit:4.13.2'
70 | }
71 |
72 | //apply from: '../publish/mavencentral.gradle'
73 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/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 /Applications/ADT/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 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/CenteredRoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.GradientDrawable
5 | import android.os.Build
6 | import android.util.AttributeSet
7 | import android.widget.LinearLayout
8 | import androidx.annotation.Keep
9 | import androidx.annotation.RequiresApi
10 |
11 | @Keep
12 | open class CenteredRoundCornerProgressBar : RoundCornerProgressBar {
13 | constructor(context: Context) : super(context)
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
16 |
17 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
18 |
19 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
20 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
21 |
22 | override fun drawProgress(
23 | layoutProgress: LinearLayout,
24 | progressDrawable: GradientDrawable,
25 | max: Float,
26 | progress: Float,
27 | totalWidth: Float,
28 | radius: Int,
29 | padding: Int,
30 | isReverse: Boolean,
31 | ) {
32 | super.drawProgress(layoutProgress, progressDrawable, max, progress, totalWidth, radius, padding, isReverse)
33 | val params = layoutProgress.layoutParams as MarginLayoutParams
34 | val ratio = max / progress
35 | val progressWidth = (totalWidth - (padding * 2)) / ratio
36 | val deltaWidth = totalWidth - progressWidth
37 | params.setMargins(
38 | (deltaWidth / 2).toInt(),
39 | params.topMargin,
40 | (deltaWidth / 2).toInt(),
41 | params.bottomMargin,
42 | )
43 | layoutProgress.layoutParams = params
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/IconRoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.drawable.Drawable
6 | import android.graphics.drawable.GradientDrawable
7 | import android.os.Build
8 | import android.os.Parcel
9 | import android.os.Parcelable
10 | import android.util.AttributeSet
11 | import android.widget.ImageView
12 | import android.widget.LinearLayout
13 | import androidx.annotation.Keep
14 | import androidx.annotation.RequiresApi
15 | import androidx.core.content.ContextCompat
16 | import androidx.customview.view.AbsSavedState
17 | import com.akexorcist.roundcornerprogressbar.common.AnimatedRoundCornerProgressBar
18 |
19 | @Suppress("unused")
20 | @Keep
21 | open class IconRoundCornerProgressBar : AnimatedRoundCornerProgressBar {
22 | companion object {
23 | protected const val DEFAULT_ICON_SIZE = 20
24 | protected const val DEFAULT_ICON_PADDING_LEFT = 0
25 | protected const val DEFAULT_ICON_PADDING_RIGHT = 0
26 | protected const val DEFAULT_ICON_PADDING_TOP = 0
27 | protected const val DEFAULT_ICON_PADDING_BOTTOM = 0
28 | }
29 |
30 | private var iconResource = 0
31 | private var iconSize = 0
32 | private var iconWidth = 0
33 | private var iconHeight = 0
34 | private var iconPadding = 0
35 | private var iconPaddingLeft = 0
36 | private var iconPaddingRight = 0
37 | private var iconPaddingTop = 0
38 | private var iconPaddingBottom = 0
39 | private var colorIconBackground = 0
40 |
41 | private var iconBitmap: Bitmap? = null
42 | private var iconDrawable: Drawable? = null
43 |
44 | private lateinit var ivProgressIcon: ImageView
45 |
46 | private var onIconClick: (() -> Unit)? = null
47 |
48 | constructor(context: Context) : super(context)
49 |
50 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
51 |
52 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
53 | context,
54 | attrs,
55 | defStyleAttr
56 | )
57 |
58 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
59 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
60 | context,
61 | attrs,
62 | defStyleAttr,
63 | defStyleRes
64 | )
65 |
66 | override fun initLayout(): Int = R.layout.layout_icon_round_corner_progress_bar
67 |
68 | override fun initStyleable(context: Context, attrs: AttributeSet?) {
69 | if (attrs == null) return
70 | val typedArray = context.obtainStyledAttributes(
71 | attrs, R.styleable.IconRoundCornerProgressBar
72 | )
73 |
74 | with(typedArray) {
75 | iconResource = getResourceId(R.styleable.IconRoundCornerProgressBar_rcIconSrc, -1)
76 | iconSize = getDimension(R.styleable.IconRoundCornerProgressBar_rcIconSize, -1f).toInt()
77 | iconWidth = getDimension(
78 | R.styleable.IconRoundCornerProgressBar_rcIconWidth,
79 | dp2px(DEFAULT_ICON_SIZE.toFloat())
80 | ).toInt()
81 | iconHeight = getDimension(
82 | R.styleable.IconRoundCornerProgressBar_rcIconHeight,
83 | dp2px(DEFAULT_ICON_SIZE.toFloat())
84 | ).toInt()
85 | iconPadding =
86 | getDimension(R.styleable.IconRoundCornerProgressBar_rcIconPadding, -1f).toInt()
87 | iconPaddingLeft = getDimension(
88 | R.styleable.IconRoundCornerProgressBar_rcIconPaddingLeft,
89 | dp2px(DEFAULT_ICON_PADDING_LEFT.toFloat())
90 | ).toInt()
91 | iconPaddingRight = getDimension(
92 | R.styleable.IconRoundCornerProgressBar_rcIconPaddingRight,
93 | dp2px(DEFAULT_ICON_PADDING_RIGHT.toFloat())
94 | ).toInt()
95 | iconPaddingTop = getDimension(
96 | R.styleable.IconRoundCornerProgressBar_rcIconPaddingTop,
97 | dp2px(DEFAULT_ICON_PADDING_TOP.toFloat())
98 | ).toInt()
99 | iconPaddingBottom = getDimension(
100 | R.styleable.IconRoundCornerProgressBar_rcIconPaddingBottom,
101 | dp2px(DEFAULT_ICON_PADDING_BOTTOM.toFloat())
102 | ).toInt()
103 |
104 | val defaultIconBackgroundColor = ContextCompat.getColor(
105 | context,
106 | R.color.round_corner_progress_bar_background_default
107 | )
108 | colorIconBackground = getColor(
109 | R.styleable.IconRoundCornerProgressBar_rcIconBackgroundColor,
110 | defaultIconBackgroundColor
111 | )
112 | recycle()
113 | }
114 | }
115 |
116 | override fun initView() {
117 | ivProgressIcon = findViewById(R.id.iv_progress_icon)
118 | ivProgressIcon.setOnClickListener {
119 | onIconClick?.invoke()
120 | }
121 | }
122 |
123 | fun setOnIconClickListener(onIconClick: (() -> Unit)? = null) {
124 | this.onIconClick = onIconClick
125 | }
126 |
127 | override fun drawProgress(
128 | layoutProgress: LinearLayout,
129 | progressDrawable: GradientDrawable,
130 | max: Float,
131 | progress: Float,
132 | totalWidth: Float,
133 | radius: Int,
134 | padding: Int,
135 | isReverse: Boolean,
136 | ) {
137 | val newRadius = radius - (padding / 2f)
138 | if (isReverse && progress != max) {
139 | progressDrawable.cornerRadii = floatArrayOf(
140 | newRadius,
141 | newRadius,
142 | newRadius,
143 | newRadius,
144 | newRadius,
145 | newRadius,
146 | newRadius,
147 | newRadius,
148 | )
149 | } else {
150 | progressDrawable.cornerRadii = floatArrayOf(
151 | 0f,
152 | 0f,
153 | newRadius,
154 | newRadius,
155 | newRadius,
156 | newRadius,
157 | 0f,
158 | 0f
159 | )
160 | }
161 | layoutProgress.background = progressDrawable
162 |
163 | val ratio = max / progress
164 | val progressWidth = ((totalWidth - ((padding * 2) + ivProgressIcon.width)) / ratio).toInt()
165 | val progressParams = layoutProgress.layoutParams as MarginLayoutParams
166 | if (isReverse) {
167 | if (padding + (progressWidth / 2) < radius) {
168 | val margin = (radius - padding).coerceAtLeast(0) - (progressWidth / 2)
169 | progressParams.topMargin = margin
170 | progressParams.bottomMargin = margin
171 | } else {
172 | progressParams.topMargin = 0
173 | progressParams.bottomMargin = 0
174 | }
175 | }
176 | progressParams.width = progressWidth
177 | layoutProgress.layoutParams = progressParams
178 | }
179 |
180 | override fun onViewDraw() {
181 | drawImageIcon()
182 | drawImageIconSize()
183 | drawImageIconPadding()
184 | drawIconBackgroundColor()
185 | }
186 |
187 | private fun drawImageIcon() {
188 | when {
189 | iconResource != -1 -> ivProgressIcon.setImageResource(iconResource)
190 | iconBitmap != null -> ivProgressIcon.setImageBitmap(iconBitmap)
191 | iconDrawable != null -> ivProgressIcon.setImageDrawable(iconDrawable)
192 | else -> ivProgressIcon.setImageResource(0)
193 | }
194 | }
195 |
196 | private fun drawImageIconSize() {
197 | @Suppress("IntroduceWhenSubject")
198 | val layoutParams = when {
199 | iconSize == -1 -> LayoutParams(iconWidth, iconHeight)
200 | else -> LayoutParams(iconSize, iconSize)
201 | }
202 | ivProgressIcon.layoutParams = layoutParams
203 | }
204 |
205 | private fun drawImageIconPadding() {
206 | @Suppress("IntroduceWhenSubject")
207 | when {
208 | iconPadding == -1 || iconPadding == 0 -> ivProgressIcon.setPadding(
209 | iconPaddingLeft,
210 | iconPaddingTop,
211 | iconPaddingRight,
212 | iconPaddingBottom
213 | )
214 |
215 | else -> ivProgressIcon.setPadding(
216 | iconPadding, iconPadding, iconPadding, iconPadding
217 | )
218 | }
219 | ivProgressIcon.invalidate()
220 | }
221 |
222 | private fun drawIconBackgroundColor() {
223 | val iconBackgroundDrawable = createGradientDrawable(colorIconBackground)
224 | val radius = getRadius() - (getPadding() / 2)
225 | iconBackgroundDrawable.cornerRadii = floatArrayOf(
226 | radius.toFloat(),
227 | radius.toFloat(),
228 | 0f,
229 | 0f,
230 | 0f,
231 | 0f,
232 | radius.toFloat(),
233 | radius.toFloat(),
234 | )
235 | ivProgressIcon.background = iconBackgroundDrawable
236 | }
237 |
238 | fun getIconImageResource(): Int = iconResource
239 |
240 | fun setIconImageResource(resId: Int) {
241 | iconResource = resId
242 | iconBitmap = null
243 | iconDrawable = null
244 | drawImageIcon()
245 | }
246 |
247 | fun getIconImageBitmap(): Bitmap? = iconBitmap
248 |
249 | fun setIconImageBitmap(bitmap: Bitmap?) {
250 | iconResource = -1
251 | iconBitmap = bitmap
252 | iconDrawable = null
253 | drawImageIcon()
254 | }
255 |
256 | fun getIconImageDrawable(): Drawable? = iconDrawable
257 |
258 | fun setIconImageDrawable(drawable: Drawable?) {
259 | iconResource = -1
260 | iconBitmap = null
261 | iconDrawable = drawable
262 | drawImageIcon()
263 | }
264 |
265 | fun getIconSize(): Int = iconSize
266 |
267 | fun setIconSize(size: Int) {
268 | if (size >= 0) {
269 | iconSize = size
270 | }
271 | drawImageIconSize()
272 | }
273 |
274 | fun getIconPadding(): Int = iconPadding
275 |
276 | fun setIconPadding(padding: Int) {
277 | if (padding >= 0) {
278 | iconPadding = padding
279 | }
280 | drawImageIconPadding()
281 | }
282 |
283 | fun getIconPaddingLeft(): Int = iconPaddingLeft
284 |
285 | fun setIconPaddingLeft(padding: Int) {
286 | if (padding > 0) {
287 | iconPaddingLeft = padding
288 | }
289 | drawImageIconPadding()
290 | }
291 |
292 | fun getIconPaddingRight(): Int = iconPaddingRight
293 |
294 | fun setIconPaddingRight(padding: Int) {
295 | if (padding > 0) {
296 | iconPaddingRight = padding
297 | }
298 | drawImageIconPadding()
299 | }
300 |
301 | fun getIconPaddingTop(): Int = iconPaddingTop
302 |
303 | fun setIconPaddingTop(padding: Int) {
304 | if (padding > 0) {
305 | iconPaddingTop = padding
306 | }
307 | drawImageIconPadding()
308 | }
309 |
310 | fun getIconPaddingBottom(): Int = iconPaddingBottom
311 |
312 | fun setIconPaddingBottom(padding: Int) {
313 | if (padding > 0) {
314 | iconPaddingBottom = padding
315 | }
316 | drawImageIconPadding()
317 | }
318 |
319 | fun getColorIconBackground(): Int = colorIconBackground
320 |
321 | fun setIconBackgroundColor(color: Int) {
322 | colorIconBackground = color
323 | drawIconBackgroundColor()
324 | }
325 |
326 | override fun onSaveInstanceState(): Parcelable? {
327 | val superState = super.onSaveInstanceState() ?: return null
328 | val state = SavedState(superState)
329 |
330 | state.iconResource = this.iconResource
331 | state.iconSize = this.iconSize
332 | state.iconWidth = this.iconWidth
333 | state.iconHeight = this.iconHeight
334 | state.iconPadding = this.iconPadding
335 | state.iconPaddingLeft = this.iconPaddingLeft
336 | state.iconPaddingRight = this.iconPaddingRight
337 | state.iconPaddingTop = this.iconPaddingTop
338 | state.iconPaddingBottom = this.iconPaddingBottom
339 | state.colorIconBackground = this.colorIconBackground
340 | return state
341 | }
342 |
343 | override fun onRestoreInstanceState(state: Parcelable?) {
344 | if (state !is SavedState) {
345 | super.onRestoreInstanceState(state)
346 | return
347 | }
348 | super.onRestoreInstanceState(state.superState)
349 |
350 | this.iconResource = state.iconResource
351 | this.iconSize = state.iconSize
352 | this.iconWidth = state.iconWidth
353 | this.iconHeight = state.iconHeight
354 | this.iconPadding = state.iconPadding
355 | this.iconPaddingLeft = state.iconPaddingLeft
356 | this.iconPaddingRight = state.iconPaddingRight
357 | this.iconPaddingTop = state.iconPaddingTop
358 | this.iconPaddingBottom = state.iconPaddingBottom
359 | this.colorIconBackground = state.colorIconBackground
360 | }
361 |
362 | protected class SavedState : AbsSavedState {
363 | var iconResource = 0
364 | var iconSize = 0
365 | var iconWidth = 0
366 | var iconHeight = 0
367 | var iconPadding = 0
368 | var iconPaddingLeft = 0
369 | var iconPaddingRight = 0
370 | var iconPaddingTop = 0
371 | var iconPaddingBottom = 0
372 | var colorIconBackground = 0
373 |
374 | constructor(superState: Parcelable) : super(superState)
375 |
376 | constructor(source: Parcel) : super(source, null)
377 |
378 | constructor(source: Parcel, loader: ClassLoader? = null) : super(source, loader) {
379 | this.iconResource = source.readInt()
380 | this.iconSize = source.readInt()
381 | this.iconWidth = source.readInt()
382 | this.iconHeight = source.readInt()
383 | this.iconPadding = source.readInt()
384 | this.iconPaddingLeft = source.readInt()
385 | this.iconPaddingRight = source.readInt()
386 | this.iconPaddingTop = source.readInt()
387 | this.iconPaddingBottom = source.readInt()
388 | this.colorIconBackground = source.readInt()
389 | }
390 |
391 | override fun writeToParcel(dest: Parcel, flags: Int) {
392 | super.writeToParcel(dest, flags)
393 | with(dest) {
394 | writeInt(iconResource)
395 | writeInt(iconSize)
396 | writeInt(iconWidth)
397 | writeInt(iconHeight)
398 | writeInt(iconPadding)
399 | writeInt(iconPaddingLeft)
400 | writeInt(iconPaddingRight)
401 | writeInt(iconPaddingTop)
402 | writeInt(iconPaddingBottom)
403 | writeInt(colorIconBackground)
404 | }
405 | }
406 |
407 | companion object {
408 | @JvmField
409 | val CREATOR: Parcelable.ClassLoaderCreator =
410 | object : Parcelable.ClassLoaderCreator {
411 | override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState =
412 | SavedState(source, loader)
413 |
414 | override fun createFromParcel(source: Parcel): SavedState = SavedState(source)
415 |
416 | override fun newArray(size: Int): Array = newArray(size)
417 | }
418 | }
419 | }
420 | }
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/RoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.GradientDrawable
5 | import android.os.Build
6 | import android.util.AttributeSet
7 | import android.widget.LinearLayout
8 | import androidx.annotation.Keep
9 | import androidx.annotation.RequiresApi
10 | import com.akexorcist.roundcornerprogressbar.common.AnimatedRoundCornerProgressBar
11 |
12 | @Keep
13 | open class RoundCornerProgressBar : AnimatedRoundCornerProgressBar {
14 | constructor(context: Context) : super(context)
15 |
16 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
17 |
18 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
19 |
20 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
21 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
22 |
23 | override fun initLayout(): Int = R.layout.layout_round_corner_progress_bar
24 |
25 | override fun initStyleable(context: Context, attrs: AttributeSet?) {}
26 |
27 | override fun initView() {}
28 |
29 | override fun drawProgress(
30 | layoutProgress: LinearLayout,
31 | progressDrawable: GradientDrawable,
32 | max: Float,
33 | progress: Float,
34 | totalWidth: Float,
35 | radius: Int,
36 | padding: Int,
37 | isReverse: Boolean,
38 | ) {
39 | val newRadius = radius - (padding / 2f)
40 | progressDrawable.cornerRadii = floatArrayOf(
41 | newRadius,
42 | newRadius,
43 | newRadius,
44 | newRadius,
45 | newRadius,
46 | newRadius,
47 | newRadius,
48 | newRadius,
49 | )
50 | layoutProgress.background = progressDrawable
51 | val ratio = max / progress
52 | val progressWidth = ((totalWidth - (padding * 2)) / ratio).toInt()
53 | val progressParams = layoutProgress.layoutParams as MarginLayoutParams
54 | progressParams.width = progressWidth
55 | if (padding + (progressWidth / 2) < radius) {
56 | val margin = (radius - padding).coerceAtLeast(0) - (progressWidth / 2)
57 | progressParams.topMargin = margin
58 | progressParams.bottomMargin = margin
59 | } else {
60 | progressParams.topMargin = 0
61 | progressParams.bottomMargin = 0
62 | }
63 | layoutProgress.layoutParams = progressParams
64 | }
65 |
66 | override fun onViewDraw() {}
67 | }
68 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/TextRoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.graphics.drawable.GradientDrawable
6 | import android.os.Build
7 | import android.os.Parcel
8 | import android.os.Parcelable
9 | import android.util.AttributeSet
10 | import android.util.TypedValue
11 | import android.view.ViewTreeObserver
12 | import android.widget.LinearLayout
13 | import android.widget.RelativeLayout
14 | import android.widget.TextView
15 | import androidx.annotation.*
16 | import androidx.customview.view.AbsSavedState
17 | import com.akexorcist.roundcornerprogressbar.common.AnimatedRoundCornerProgressBar
18 |
19 | @Suppress("unused", "MemberVisibilityCanBePrivate")
20 | @Keep
21 | open class TextRoundCornerProgressBar : AnimatedRoundCornerProgressBar,
22 | ViewTreeObserver.OnGlobalLayoutListener {
23 | companion object {
24 | protected const val DEFAULT_TEXT_SIZE = 16
25 | protected const val DEFAULT_TEXT_MARGIN = 10
26 | const val GRAVITY_START = 0
27 | const val GRAVITY_END = 1
28 | const val PRIORITY_INSIDE = 0
29 | const val PRIORITY_OUTSIDE = 1
30 | }
31 |
32 | private lateinit var tvProgress: TextView
33 |
34 | private var colorTextProgress = 0
35 | private var textProgressSize = 0
36 | private var textProgressMargin = 0
37 | private var textProgress: String? = null
38 | private var textInsideGravity = 0
39 | private var textOutsideGravity = 0
40 | private var textPositionPriority = 0
41 |
42 | constructor(context: Context) : super(context)
43 |
44 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
45 |
46 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
47 | context,
48 | attrs,
49 | defStyleAttr
50 | )
51 |
52 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
53 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
54 | context,
55 | attrs,
56 | defStyleAttr,
57 | defStyleRes
58 | )
59 |
60 | override fun initLayout(): Int = R.layout.layout_text_round_corner_progress_bar
61 |
62 | override fun initStyleable(context: Context, attrs: AttributeSet?) {
63 | if (attrs == null) return
64 | val typedArray =
65 | context.obtainStyledAttributes(attrs, R.styleable.TextRoundCornerProgressBar)
66 |
67 | with(typedArray) {
68 | colorTextProgress = getColor(
69 | R.styleable.TextRoundCornerProgressBar_rcTextProgressColor, Color.WHITE
70 | )
71 |
72 | textProgressSize = getDimension(
73 | R.styleable.TextRoundCornerProgressBar_rcTextProgressSize,
74 | dp2px(DEFAULT_TEXT_SIZE.toFloat())
75 | ).toInt()
76 | textProgressMargin = getDimension(
77 | R.styleable.TextRoundCornerProgressBar_rcTextProgressMargin,
78 | dp2px(DEFAULT_TEXT_MARGIN.toFloat())
79 | ).toInt()
80 |
81 | textProgress = getString(R.styleable.TextRoundCornerProgressBar_rcTextProgress)
82 |
83 | textInsideGravity = getInt(
84 | R.styleable.TextRoundCornerProgressBar_rcTextInsideGravity, GRAVITY_START
85 | )
86 | textOutsideGravity = getInt(
87 | R.styleable.TextRoundCornerProgressBar_rcTextOutsideGravity, GRAVITY_START
88 | )
89 | textPositionPriority = getInt(
90 | R.styleable.TextRoundCornerProgressBar_rcTextPositionPriority,
91 | PRIORITY_INSIDE
92 | )
93 | recycle()
94 | }
95 | }
96 |
97 | override fun initView() {
98 | tvProgress = findViewById(R.id.tv_progress)
99 | tvProgress.viewTreeObserver.addOnGlobalLayoutListener(this)
100 | }
101 |
102 | override fun drawProgress(
103 | layoutProgress: LinearLayout,
104 | progressDrawable: GradientDrawable,
105 | max: Float,
106 | progress: Float,
107 | totalWidth: Float,
108 | radius: Int,
109 | padding: Int,
110 | isReverse: Boolean,
111 | ) {
112 | val newRadius = radius - (padding / 2f)
113 | progressDrawable.cornerRadii = floatArrayOf(
114 | newRadius,
115 | newRadius,
116 | newRadius,
117 | newRadius,
118 | newRadius,
119 | newRadius,
120 | newRadius,
121 | newRadius,
122 | )
123 | layoutProgress.background = progressDrawable
124 |
125 | val ratio = max / progress
126 | val progressWidth = ((totalWidth - (padding * 2)) / ratio).toInt()
127 | val progressParams = layoutProgress.layoutParams as MarginLayoutParams
128 | if (padding + (progressWidth / 2) < radius) {
129 | val margin = (radius - padding).coerceAtLeast(0) - (progressWidth / 2)
130 | progressParams.topMargin = margin
131 | progressParams.bottomMargin = margin
132 | } else {
133 | progressParams.topMargin = 0
134 | progressParams.bottomMargin = 0
135 | }
136 | progressParams.width = progressWidth
137 | layoutProgress.layoutParams = progressParams
138 | }
139 |
140 | override fun onViewDraw() {
141 | drawTextProgress()
142 | drawTextProgressSize()
143 | drawTextProgressMargin()
144 | // Can't instantly change the text position of child view
145 | // when `onSizeChanged(...)` called. Using `post` method then
146 | // call these methods inside the Runnable will solved this.
147 | // Can't instantly change the text position of child view
148 | // when `onSizeChanged(...)` called. Using `post` method then
149 | // call these methods inside the Runnable will solved this.
150 | post { drawTextProgressPosition() }
151 | drawTextProgressColor()
152 | }
153 |
154 | private fun drawTextProgress() {
155 | tvProgress.text = textProgress
156 | }
157 |
158 | private fun drawTextProgressColor() {
159 | tvProgress.setTextColor(colorTextProgress)
160 | }
161 |
162 | private fun drawTextProgressSize() {
163 | tvProgress.setTextSize(TypedValue.COMPLEX_UNIT_PX, textProgressSize.toFloat())
164 | }
165 |
166 | private fun drawTextProgressMargin() {
167 | val params = tvProgress.layoutParams as MarginLayoutParams
168 | params.setMargins(textProgressMargin, 0, textProgressMargin, 0)
169 | tvProgress.layoutParams = params
170 | }
171 |
172 | private fun drawTextProgressPosition() {
173 | clearTextProgressAlign()
174 | val textProgressWidth: Int = tvProgress.measuredWidth + getTextProgressMargin() * 2
175 | val ratio = getMax() / getProgress()
176 | val progressWidth = ((getLayoutWidth() - (getPadding() * 2)) / ratio).toInt()
177 | if (textPositionPriority == PRIORITY_OUTSIDE) {
178 | if (getLayoutWidth() - progressWidth > textProgressWidth) {
179 | alignTextProgressOutsideProgress()
180 | } else {
181 | alignTextProgressInsideProgress()
182 | }
183 | } else {
184 | if (textProgressWidth + textProgressMargin > progressWidth) {
185 | alignTextProgressOutsideProgress()
186 | } else {
187 | alignTextProgressInsideProgress()
188 | }
189 | }
190 | }
191 |
192 | private fun clearTextProgressAlign() {
193 | val params = tvProgress.layoutParams as RelativeLayout.LayoutParams
194 | with(params) {
195 | removeRule(RelativeLayout.LEFT_OF)
196 | removeRule(RelativeLayout.RIGHT_OF)
197 | removeRule(RelativeLayout.ALIGN_LEFT)
198 | removeRule(RelativeLayout.ALIGN_RIGHT)
199 | removeRule(RelativeLayout.ALIGN_PARENT_LEFT)
200 | removeRule(RelativeLayout.ALIGN_PARENT_RIGHT)
201 | removeRule(RelativeLayout.START_OF)
202 | removeRule(RelativeLayout.END_OF)
203 | removeRule(RelativeLayout.ALIGN_START)
204 | removeRule(RelativeLayout.ALIGN_END)
205 | removeRule(RelativeLayout.ALIGN_PARENT_START)
206 | removeRule(RelativeLayout.ALIGN_PARENT_END)
207 |
208 | tvProgress.layoutParams = this
209 | }
210 | }
211 |
212 | private fun alignTextProgressInsideProgress() {
213 | val params = tvProgress.layoutParams as RelativeLayout.LayoutParams
214 |
215 | with(params) {
216 | if (isReverse()) {
217 | if (textInsideGravity == GRAVITY_END) {
218 | addRule(RelativeLayout.ALIGN_RIGHT, R.id.layout_progress)
219 | addRule(RelativeLayout.ALIGN_END, R.id.layout_progress)
220 | } else {
221 | addRule(RelativeLayout.ALIGN_LEFT, R.id.layout_progress)
222 | addRule(RelativeLayout.ALIGN_START, R.id.layout_progress)
223 | }
224 | } else {
225 | if (textInsideGravity == GRAVITY_END) {
226 | addRule(RelativeLayout.ALIGN_LEFT, R.id.layout_progress)
227 | addRule(RelativeLayout.ALIGN_START, R.id.layout_progress)
228 | } else {
229 | addRule(RelativeLayout.ALIGN_RIGHT, R.id.layout_progress)
230 | addRule(RelativeLayout.ALIGN_END, R.id.layout_progress)
231 | }
232 | }
233 |
234 | tvProgress.layoutParams = this
235 | }
236 | }
237 |
238 | private fun alignTextProgressOutsideProgress() {
239 | val params = tvProgress.layoutParams as RelativeLayout.LayoutParams
240 |
241 | with(params) {
242 | if (isReverse()) {
243 | if (textOutsideGravity == GRAVITY_END) {
244 | addRule(RelativeLayout.ALIGN_PARENT_LEFT)
245 | addRule(RelativeLayout.ALIGN_PARENT_START)
246 | } else {
247 | addRule(RelativeLayout.LEFT_OF, R.id.layout_progress)
248 | addRule(RelativeLayout.START_OF, R.id.layout_progress)
249 | }
250 | } else {
251 | if (textOutsideGravity == GRAVITY_END) {
252 | addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
253 | addRule(RelativeLayout.ALIGN_PARENT_END)
254 | } else {
255 | addRule(RelativeLayout.RIGHT_OF, R.id.layout_progress)
256 | addRule(RelativeLayout.END_OF, R.id.layout_progress)
257 | }
258 | }
259 | tvProgress.layoutParams = this
260 | }
261 | }
262 |
263 | fun getProgressText(): String? = textProgress
264 |
265 | fun setProgressText(text: String) {
266 | textProgress = text
267 | drawTextProgress()
268 | drawTextProgressPosition()
269 | }
270 |
271 | override fun setProgress(progress: Int) {
272 | setProgress(progress.toFloat())
273 | }
274 |
275 | override fun setProgress(progress: Float) {
276 | super.setProgress(progress)
277 | drawTextProgressPosition()
278 | }
279 |
280 | fun getTextProgressColor(): Int = colorTextProgress
281 |
282 | fun setTextProgressColor(@ColorInt color: Int) {
283 | colorTextProgress = color
284 | drawTextProgressColor()
285 | }
286 |
287 | fun getTextProgressSize(): Int = textProgressSize
288 |
289 | fun setTextProgressSize(@Px size: Int) {
290 | textProgressSize = size
291 | drawTextProgressSize()
292 | drawTextProgressPosition()
293 | }
294 |
295 | fun getTextProgressMargin(): Int = textProgressMargin
296 |
297 | fun setTextProgressMargin(@Px margin: Int) {
298 | textProgressMargin = margin
299 | drawTextProgressMargin()
300 | drawTextProgressPosition()
301 | }
302 |
303 | @TextPositionPriority
304 | fun getTextPositionPriority(): Int = textPositionPriority
305 |
306 | fun setTextPositionPriority(@TextPositionPriority priority: Int) {
307 | textPositionPriority = priority
308 | drawTextProgressPosition()
309 | }
310 |
311 | @TextProgressGravity
312 | fun getTextInsideGravity(): Int = textInsideGravity
313 |
314 | fun setTextInsideGravity(@TextProgressGravity gravity: Int) {
315 | textInsideGravity = gravity
316 | drawTextProgressPosition()
317 | }
318 |
319 | @TextProgressGravity
320 | fun getTextOutsideGravity(): Int = textOutsideGravity
321 |
322 | fun setTextOutsideGravity(@TextProgressGravity gravity: Int) {
323 | textOutsideGravity = gravity
324 | drawTextProgressPosition()
325 | }
326 |
327 | override fun onGlobalLayout() {
328 | tvProgress.viewTreeObserver.removeOnGlobalLayoutListener(this)
329 | drawTextProgressPosition()
330 | }
331 |
332 | @Retention(AnnotationRetention.SOURCE)
333 | @IntDef(GRAVITY_START, GRAVITY_END)
334 | annotation class TextProgressGravity
335 |
336 | @Retention(AnnotationRetention.SOURCE)
337 | @IntDef(PRIORITY_INSIDE, PRIORITY_OUTSIDE)
338 | annotation class TextPositionPriority
339 |
340 | override fun onSaveInstanceState(): Parcelable? {
341 | val superState = super.onSaveInstanceState() ?: return null
342 | val state = SavedState(superState)
343 | state.colorTextProgress = this.colorTextProgress
344 | state.textProgressSize = this.textProgressSize
345 | state.textProgressMargin = this.textProgressMargin
346 |
347 | state.textProgress = this.textProgress
348 |
349 | state.textInsideGravity = this.textInsideGravity
350 | state.textOutsideGravity = this.textOutsideGravity
351 | state.textPositionPriority = this.textPositionPriority
352 | return state
353 | }
354 |
355 | override fun onRestoreInstanceState(state: Parcelable?) {
356 | if (state !is SavedState) {
357 | super.onRestoreInstanceState(state)
358 | return
359 | }
360 | super.onRestoreInstanceState(state.superState)
361 |
362 | colorTextProgress = state.colorTextProgress
363 | textProgressSize = state.textProgressSize
364 | textProgressMargin = state.textProgressMargin
365 |
366 | textProgress = state.textProgress
367 |
368 | textInsideGravity = state.textInsideGravity
369 | textOutsideGravity = state.textOutsideGravity
370 | textPositionPriority = state.textPositionPriority
371 | }
372 |
373 | protected class SavedState : AbsSavedState {
374 | var colorTextProgress = 0
375 | var textProgressSize = 0
376 | var textProgressMargin = 0
377 |
378 | var textProgress: String? = null
379 |
380 | var textInsideGravity = 0
381 | var textOutsideGravity = 0
382 | var textPositionPriority = 0
383 |
384 | constructor(superState: Parcelable) : super(superState)
385 |
386 | constructor(source: Parcel) : super(source, null)
387 |
388 | constructor(source: Parcel, loader: ClassLoader? = null) : super(source, loader) {
389 | with(source) {
390 | colorTextProgress = readInt()
391 | textProgressSize = readInt()
392 | textProgressMargin = readInt()
393 |
394 | textProgress = readString()
395 |
396 | textInsideGravity = readInt()
397 | textOutsideGravity = readInt()
398 | textPositionPriority = readInt()
399 | }
400 | }
401 |
402 | override fun writeToParcel(dest: Parcel, flags: Int) {
403 | super.writeToParcel(dest, flags)
404 | with(dest) {
405 | writeInt(colorTextProgress)
406 | writeInt(textProgressSize)
407 | writeInt(textProgressMargin)
408 |
409 | writeString(textProgress)
410 |
411 | writeInt(textInsideGravity)
412 | writeInt(textOutsideGravity)
413 | writeInt(textPositionPriority)
414 | }
415 | }
416 |
417 | companion object {
418 | @JvmField
419 | val CREATOR: Parcelable.ClassLoaderCreator =
420 | object : Parcelable.ClassLoaderCreator {
421 | override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState =
422 | SavedState(source, loader)
423 |
424 | override fun createFromParcel(source: Parcel): SavedState = SavedState(source)
425 |
426 | override fun newArray(size: Int): Array = newArray(size)
427 | }
428 | }
429 | }
430 | }
431 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/common/AnimatedRoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.common
2 |
3 | import android.animation.Animator
4 | import android.animation.AnimatorListenerAdapter
5 | import android.animation.ValueAnimator
6 | import android.animation.ValueAnimator.AnimatorUpdateListener
7 | import android.content.Context
8 | import android.os.Build
9 | import android.os.Parcel
10 | import android.os.Parcelable
11 | import android.os.Parcelable.ClassLoaderCreator
12 | import android.util.AttributeSet
13 | import android.widget.LinearLayout
14 | import androidx.annotation.FloatRange
15 | import androidx.annotation.RequiresApi
16 | import androidx.customview.view.AbsSavedState
17 | import com.akexorcist.roundcornerprogressbar.R
18 | import kotlin.math.abs
19 |
20 | @Suppress("unused")
21 | abstract class AnimatedRoundCornerProgressBar : BaseRoundCornerProgressBar {
22 | companion object {
23 | const val DEFAULT_DURATION = 500L
24 | }
25 |
26 | private var _isProgressAnimating = false
27 | private var _isSecondaryProgressAnimating = false
28 | private var _lastProgress = 0f
29 | private var _lastSecondaryProgress = 0f
30 |
31 | private var _animationSpeedScale = 1f
32 | private var _isAnimationEnabled = false
33 |
34 | private var _progressAnimator: ValueAnimator? = null
35 | private var _secondaryProgressAnimator: ValueAnimator? = null
36 |
37 | constructor(context: Context) : super(context)
38 |
39 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
40 |
41 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
42 | context,
43 | attrs,
44 | defStyleAttr
45 | )
46 |
47 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
48 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
49 | context,
50 | attrs,
51 | defStyleAttr,
52 | defStyleRes
53 | )
54 |
55 | override fun setupStyleable(context: Context, attrs: AttributeSet?) {
56 | super.setupStyleable(context, attrs)
57 | if (attrs == null) return
58 |
59 | val typedArray = context.obtainStyledAttributes(
60 | attrs, R.styleable.AnimatedRoundCornerProgressBar
61 | )
62 |
63 | with(typedArray) {
64 | _isAnimationEnabled = getBoolean(
65 | R.styleable.AnimatedRoundCornerProgressBar_rcAnimationEnable, false
66 | )
67 | _animationSpeedScale = getFloat(
68 | R.styleable.AnimatedRoundCornerProgressBar_rcAnimationSpeedScale, 1f
69 | )
70 | recycle()
71 | }
72 | _lastProgress = super.getProgress()
73 | _lastSecondaryProgress = super.getSecondaryProgress()
74 | }
75 |
76 | override fun getProgress(): Float {
77 | return if (!_isAnimationEnabled && !_isProgressAnimating) {
78 | super.getProgress()
79 | } else {
80 | _lastProgress
81 | }
82 | }
83 |
84 | override fun setProgress(progress: Int) {
85 | setProgress(progress.toFloat())
86 | }
87 |
88 | override fun setProgress(progress: Float) {
89 | val actualProgress =
90 | if (progress < 0) 0f
91 | else progress.coerceAtMost(_max)
92 |
93 | clearProgressAnimation()
94 | this._lastProgress = actualProgress
95 |
96 | if (this._isAnimationEnabled) {
97 | startProgressAnimation(super.getProgress(), actualProgress)
98 | } else {
99 | super.setProgress(actualProgress)
100 | }
101 | }
102 |
103 | override fun getSecondaryProgress(): Float {
104 | return if (!_isAnimationEnabled && !_isSecondaryProgressAnimating) {
105 | super.getSecondaryProgress()
106 | } else {
107 | _lastSecondaryProgress
108 | }
109 | }
110 |
111 | override fun setSecondaryProgress(progress: Int) {
112 | setSecondaryProgress(progress.toFloat())
113 | }
114 |
115 | override fun setSecondaryProgress(progress: Float) {
116 | val actualProgress =
117 | if (progress < 0) 0f
118 | else progress.coerceAtMost(_max)
119 | clearSecondaryProgressAnimation()
120 | _lastSecondaryProgress = actualProgress
121 | if (_isAnimationEnabled) {
122 | startSecondaryProgressAnimation(super.getSecondaryProgress(), actualProgress)
123 | } else {
124 | super.setSecondaryProgress(actualProgress)
125 | }
126 | }
127 |
128 | @FloatRange(from = 0.2, to = 5.toDouble())
129 | open fun getAnimationSpeedScale(): Float {
130 | return _animationSpeedScale
131 | }
132 |
133 | fun enableAnimation() {
134 | _isAnimationEnabled = true
135 | }
136 |
137 | fun disableAnimation() {
138 | _isAnimationEnabled = false
139 | }
140 |
141 | fun setAnimationSpeedScale(@FloatRange(from = 0.2, to = 5.toDouble()) scale: Float) {
142 | _animationSpeedScale = scale.coerceIn(0.2f, 5f)
143 | }
144 |
145 | fun isProgressAnimating(): Boolean = _isProgressAnimating
146 |
147 | fun isSecondaryProgressAnimating(): Boolean = _isSecondaryProgressAnimating
148 |
149 | protected open fun onProgressChangeAnimationUpdate(
150 | layout: LinearLayout,
151 | current: Float,
152 | to: Float
153 | ) {
154 | }
155 |
156 | protected open fun onProgressChangeAnimationEnd(layout: LinearLayout) {}
157 |
158 | protected open fun stopProgressAnimationImmediately() {
159 | clearProgressAnimation()
160 | clearSecondaryProgressAnimation()
161 | if (_isAnimationEnabled && _isProgressAnimating) {
162 | disableAnimation()
163 | if (_isProgressAnimating) {
164 | super.setProgress(_lastProgress)
165 | }
166 | if (_isSecondaryProgressAnimating) {
167 | super.setSecondaryProgress(_lastProgress)
168 | }
169 | enableAnimation()
170 | }
171 | }
172 |
173 | private fun getAnimationDuration(from: Float, to: Float, max: Float, scale: Float): Long {
174 | val diff = abs(from - to)
175 | return (diff * DEFAULT_DURATION / max * scale).toLong()
176 | }
177 |
178 | private fun startProgressAnimation(from: Float, to: Float) {
179 | _isProgressAnimating = true
180 | _progressAnimator?.apply {
181 | removeUpdateListener(progressAnimationUpdateListener)
182 | removeListener(progressAnimationAdapterListener)
183 | cancel()
184 | }
185 | _progressAnimator = ValueAnimator.ofFloat(from, to).apply {
186 | duration = getAnimationDuration(from, to, _max, _animationSpeedScale)
187 | addUpdateListener(progressAnimationUpdateListener)
188 | addListener(progressAnimationAdapterListener)
189 | start()
190 | }
191 | }
192 |
193 | private val progressAnimationUpdateListener = AnimatorUpdateListener { animation ->
194 | onUpdateProgressByAnimation(animation.animatedValue as Float)
195 | }
196 |
197 | private val progressAnimationAdapterListener: AnimatorListenerAdapter =
198 | object : AnimatorListenerAdapter() {
199 | override fun onAnimationEnd(animation: Animator) {
200 | _isProgressAnimating = false
201 | onProgressAnimationEnd()
202 | }
203 |
204 | override fun onAnimationCancel(animation: Animator) {
205 | _isProgressAnimating = false
206 | }
207 | }
208 |
209 | private fun onUpdateProgressByAnimation(progress: Float) {
210 | super.setProgress(progress)
211 | onProgressChangeAnimationUpdate(layoutProgress, progress, _lastProgress)
212 | }
213 |
214 | private fun onProgressAnimationEnd() {
215 | onProgressChangeAnimationEnd(layoutProgress)
216 | }
217 |
218 | private fun restoreProgressAnimationState() {
219 | if (_isProgressAnimating) {
220 | startProgressAnimation(super.getProgress(), _lastProgress)
221 | }
222 | }
223 |
224 | private fun clearProgressAnimation() {
225 | if (_progressAnimator?.isRunning == true) {
226 | _progressAnimator?.cancel()
227 | }
228 | }
229 |
230 | private fun startSecondaryProgressAnimation(from: Float, to: Float) {
231 | _isSecondaryProgressAnimating = true
232 | _secondaryProgressAnimator?.apply {
233 | removeUpdateListener(secondaryProgressAnimationUpdateListener)
234 | removeListener(secondaryProgressAnimationAdapterListener)
235 | cancel()
236 | }
237 | _secondaryProgressAnimator = ValueAnimator.ofFloat(from, to).apply {
238 | duration = getAnimationDuration(from, to, _max, _animationSpeedScale)
239 | addUpdateListener(secondaryProgressAnimationUpdateListener)
240 | addListener(secondaryProgressAnimationAdapterListener)
241 | start()
242 | }
243 | }
244 |
245 | private val secondaryProgressAnimationUpdateListener = AnimatorUpdateListener { animation ->
246 | onUpdateSecondaryProgressByAnimation(animation.animatedValue as Float)
247 | }
248 |
249 | private val secondaryProgressAnimationAdapterListener: AnimatorListenerAdapter =
250 | object : AnimatorListenerAdapter() {
251 | override fun onAnimationEnd(animation: Animator) {
252 | _isSecondaryProgressAnimating = false
253 | onSecondaryProgressAnimationEnd()
254 | }
255 |
256 | override fun onAnimationCancel(animation: Animator) {
257 | _isSecondaryProgressAnimating = false
258 | }
259 | }
260 |
261 | private fun onUpdateSecondaryProgressByAnimation(progress: Float) {
262 | super.setSecondaryProgress(progress)
263 | onProgressChangeAnimationUpdate(layoutSecondaryProgress, progress, _lastProgress)
264 | }
265 |
266 | private fun onSecondaryProgressAnimationEnd() {
267 | onProgressChangeAnimationEnd(layoutSecondaryProgress)
268 | }
269 |
270 | private fun restoreSecondaryProgressAnimationState() {
271 | if (_isSecondaryProgressAnimating) {
272 | startSecondaryProgressAnimation(super.getSecondaryProgress(), _lastSecondaryProgress)
273 | }
274 | }
275 |
276 | private fun clearSecondaryProgressAnimation() {
277 | if (_secondaryProgressAnimator?.isRunning == true) {
278 | _secondaryProgressAnimator?.cancel()
279 | }
280 | }
281 |
282 | override fun onSaveInstanceState(): Parcelable? {
283 | val superState = super.onSaveInstanceState() ?: return null
284 | val state = SavedState(superState)
285 | with(state) {
286 | isProgressAnimating = _isProgressAnimating
287 | isSecondaryProgressAnimating = _isSecondaryProgressAnimating
288 | lastProgress = _lastProgress
289 | lastSecondaryProgress = _lastSecondaryProgress
290 | animationSpeedScale = _animationSpeedScale
291 | isAnimationEnabled = _isAnimationEnabled
292 | }
293 | return state
294 | }
295 |
296 | override fun onRestoreInstanceState(state: Parcelable?) {
297 | if (state !is SavedState) {
298 | super.onRestoreInstanceState(state)
299 | return
300 | }
301 | super.onRestoreInstanceState(state.superState)
302 | with(state) {
303 | _isProgressAnimating = isProgressAnimating
304 | _isSecondaryProgressAnimating = isSecondaryProgressAnimating
305 | _lastProgress = lastProgress
306 | _lastSecondaryProgress = lastSecondaryProgress
307 | _animationSpeedScale = animationSpeedScale
308 | _isAnimationEnabled = isAnimationEnabled
309 | }
310 | restoreProgressAnimationState()
311 | restoreSecondaryProgressAnimationState()
312 | }
313 |
314 | protected class SavedState : AbsSavedState {
315 | var isProgressAnimating = false
316 | var isSecondaryProgressAnimating = false
317 | var lastProgress = 0f
318 | var lastSecondaryProgress = 0f
319 | var animationSpeedScale = 0f
320 | var isAnimationEnabled = false
321 |
322 | constructor(superState: Parcelable) : super(superState)
323 |
324 | constructor(source: Parcel) : super(source)
325 |
326 | constructor(source: Parcel, loader: ClassLoader?) : super(source, loader) {
327 | with(source) {
328 | isProgressAnimating = readByte().toInt() != 0
329 | isSecondaryProgressAnimating = readByte().toInt() != 0
330 | lastProgress = readFloat()
331 | lastSecondaryProgress = readFloat()
332 | animationSpeedScale = readFloat()
333 | isAnimationEnabled = readByte().toInt() != 0
334 | }
335 | }
336 |
337 | override fun writeToParcel(dest: Parcel, flags: Int) {
338 | super.writeToParcel(dest, flags)
339 | with(dest) {
340 | writeByte((if (isProgressAnimating) 1 else 0).toByte())
341 | writeByte((if (isSecondaryProgressAnimating) 1 else 0).toByte())
342 | writeFloat(lastProgress)
343 | writeFloat(lastSecondaryProgress)
344 | writeFloat(animationSpeedScale)
345 | writeByte((if (isAnimationEnabled) 1 else 0).toByte())
346 | }
347 | }
348 |
349 | companion object {
350 | @JvmField
351 | val CREATOR: ClassLoaderCreator = object : ClassLoaderCreator {
352 | override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState =
353 | SavedState(source, loader)
354 |
355 | override fun createFromParcel(source: Parcel): SavedState = SavedState(source)
356 |
357 | override fun newArray(size: Int): Array = newArray(size)
358 | }
359 | }
360 | }
361 | }
362 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/indeterminate/IndeterminateCenteredRoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.indeterminate
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import android.util.AttributeSet
6 | import android.view.View
7 | import android.widget.LinearLayout
8 | import androidx.annotation.Keep
9 | import androidx.annotation.RequiresApi
10 | import com.akexorcist.roundcornerprogressbar.CenteredRoundCornerProgressBar
11 |
12 | @Suppress("unused")
13 | @Keep
14 | open class IndeterminateCenteredRoundCornerProgressBar : CenteredRoundCornerProgressBar {
15 | constructor(context: Context) : super(context)
16 |
17 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
18 |
19 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
20 | context,
21 | attrs,
22 | defStyleAttr
23 | )
24 |
25 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
26 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
27 | context,
28 | attrs,
29 | defStyleAttr,
30 | defStyleRes
31 | )
32 |
33 | override fun initView() {
34 | super.initView()
35 | setMax(100)
36 | }
37 |
38 | override fun onProgressChangeAnimationUpdate(layout: LinearLayout, current: Float, to: Float) {
39 | if (!isShown) {
40 | super.stopProgressAnimationImmediately()
41 | }
42 | }
43 |
44 | override fun onProgressChangeAnimationEnd(layout: LinearLayout) {
45 | if (isShown) {
46 | startIndeterminateAnimation()
47 | }
48 | }
49 |
50 | override fun onVisibilityChanged(changedView: View, visibility: Int) {
51 | super.onVisibilityChanged(changedView, visibility)
52 | if (visibility == View.VISIBLE) {
53 | startIndeterminateAnimation()
54 | }
55 | }
56 |
57 | private fun startIndeterminateAnimation() {
58 | disableAnimation()
59 | setProgress(0)
60 | enableAnimation()
61 | setProgress(100)
62 | }
63 | }
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/java/com/akexorcist/roundcornerprogressbar/indeterminate/IndeterminateRoundCornerProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.akexorcist.roundcornerprogressbar.indeterminate
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import android.util.AttributeSet
6 | import android.view.View
7 | import android.widget.LinearLayout
8 | import androidx.annotation.Keep
9 | import androidx.annotation.RequiresApi
10 | import com.akexorcist.roundcornerprogressbar.RoundCornerProgressBar
11 |
12 | @Suppress("unused")
13 | @Keep
14 | open class IndeterminateRoundCornerProgressBar : RoundCornerProgressBar {
15 | constructor(context: Context) : super(context)
16 |
17 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
18 |
19 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
20 |
21 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
22 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
23 |
24 | override fun initView() {
25 | super.initView()
26 | setMax(100)
27 | }
28 |
29 | override fun onProgressChangeAnimationUpdate(layout: LinearLayout, current: Float, to: Float) {
30 | if (!isShown) {
31 | super.stopProgressAnimationImmediately()
32 | }
33 | }
34 |
35 | override fun onProgressChangeAnimationEnd(layout: LinearLayout) {
36 | if (isShown) {
37 | startIndeterminateAnimation()
38 | }
39 | }
40 |
41 | override fun onVisibilityChanged(changedView: View, visibility: Int) {
42 | super.onVisibilityChanged(changedView, visibility)
43 | if (visibility == View.VISIBLE) {
44 | startIndeterminateAnimation()
45 | }
46 | }
47 |
48 | private fun startIndeterminateAnimation() {
49 | disableAnimation()
50 | setProgress(0)
51 | enableAnimation()
52 | setProgress(100)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/res/layout/layout_icon_round_corner_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
26 |
27 |
34 |
35 |
39 |
40 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/res/layout/layout_round_corner_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
24 |
25 |
29 |
30 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/res/layout/layout_text_round_corner_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
24 |
25 |
29 |
30 |
35 |
36 |
41 |
42 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
--------------------------------------------------------------------------------
/round-corner-progress-bar/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #5f5f5f
5 | #7f7f7f
6 | #00000000
7 |
8 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "Round Corner Progress Bar"
16 | include ':app', ':round-corner-progress-bar'
17 |
--------------------------------------------------------------------------------