π CircularSeekBar is a circular progress bar/seek bar android library that supports animations, dashes and gradients.
An example project can be found in the example directory of this repository.
If you want to use thumb, set the thumb property values.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seosh817.circularseekbar.CircularSeekBar
android:id="@+id/circular_seek_bar"
android:layout_width="match_parent"
android:layout_height="300dp"
app:circularSeekBar_animation="normal"
app:circularSeekBar_animationDurationMillis="1000"
app:circularSeekBar_barWidth="8dp"
app:circularSeekBar_innerThumbRadius="5dp"
app:circularSeekBar_innerThumbStrokeWidth="3dp"
app:circularSeekBar_min="0"
app:circularSeekBar_outerThumbRadius="5dp"
app:circularSeekBar_outerThumbStrokeWidth="10dp"
app:circularSeekBar_startAngle="90"
app:circularSeekBar_sweepAngle="360"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<resources>
<color name="red">#FFF44336</color>
<color name="orange">#FFFFAB40</color>
<color name="yellow">#FFFFEB3B</color>
<color name="green">#FF4CAF50</color>
<color name="blue">#FF2196F3</color>
<color name="indigo">#FF3F51B5</color>
<color name="purple">#FF9C27B0</color>
<array name="rainbow">
<item>@color/red</item>
<item>@color/orange</item>
<item>@color/yellow</item>
<item>@color/green</item>
<item>@color/blue</item>
<item>@color/indigo</item>
<item>@color/purple</item>
</array>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seosh817.circularseekbar.CircularSeekBar
android:id="@+id/circular_seek_bar"
android:layout_width="match_parent"
android:layout_height="300dp"
app:circularSeekBar_animation="normal"
app:circularSeekBar_animationDurationMillis="1000"
app:circularSeekBar_barWidth="8dp"
app:circularSeekBar_innerThumbRadius="5dp"
app:circularSeekBar_innerThumbStrokeWidth="3dp"
app:circularSeekBar_min="0"
app:circularSeekBar_outerThumbRadius="5dp"
app:circularSeekBar_outerThumbStrokeWidth="10dp"
app:circularSeekBar_startAngle="45"
app:circularSeekBar_sweepAngle="270"
app:circularSeekBar_progressGradientColors="@array/rainbow"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seosh817.circularseekbar.CircularSeekBar
android:id="@+id/circular_seek_bar"
android:layout_width="match_parent"
android:layout_height="300dp"
app:circularSeekBar_animation="normal"
app:circularSeekBar_animationDurationMillis="1000"
app:circularSeekBar_barWidth="8dp"
app:circularSeekBar_dashGap="15"
app:circularSeekBar_dashWidth="50"
app:circularSeekBar_innerThumbRadius="5dp"
app:circularSeekBar_innerThumbStrokeWidth="3dp"
app:circularSeekBar_min="0"
app:circularSeekBar_outerThumbRadius="5dp"
app:circularSeekBar_outerThumbStrokeWidth="10dp"
app:circularSeekBar_progressGradientColors="@array/rainbow"
app:circularSeekBar_startAngle="90"
app:circularSeekBar_sweepAngle="180"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seosh817.circularseekbar.CircularSeekBar
android:id="@+id/circular_seek_bar"
android:layout_width="match_parent"
android:layout_height="300dp"
app:circularSeekBar_animation="normal"
app:circularSeekBar_animationDurationMillis="1000"
app:circularSeekBar_barWidth="8dp"
app:circularSeekBar_innerThumbRadius="5dp"
app:circularSeekBar_innerThumbStrokeWidth="3dp"
app:circularSeekBar_min="0"
app:circularSeekBar_outerThumbRadius="5dp"
app:circularSeekBar_outerThumbStrokeWidth="10dp"
app:circularSeekBar_progressGradientColors="@array/rainbow"
app:circularSeekBar_startAngle="45"
app:circularSeekBar_dashWidth="80"
app:circularSeekBar_dashGap="15"
app:circularSeekBar_sweepAngle="270"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seosh817.circularseekbar.CircularSeekBar
android:id="@+id/circular_seek_bar"
android:layout_width="match_parent"
android:layout_height="300dp"
app:circularSeekBar_animation="normal"
app:circularSeekBar_animationDurationMillis="1000"
app:circularSeekBar_barStrokeCap="butt"
app:circularSeekBar_barWidth="8dp"
app:circularSeekBar_innerThumbRadius="5dp"
app:circularSeekBar_innerThumbStrokeWidth="3dp"
app:circularSeekBar_min="0"
app:circularSeekBar_outerThumbRadius="5dp"
app:circularSeekBar_outerThumbStrokeWidth="10dp"
app:circularSeekBar_progressGradientColors="@array/rainbow"
app:circularSeekBar_startAngle="45"
app:circularSeekBar_dashWidth="1"
app:circularSeekBar_dashGap="2"
app:circularSeekBar_sweepAngle="270"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
If you want to listen for value changes, implement the interface setOnProgressChangedListener
or setOnAnimationEndListener
.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
with(binding) {
circularSeekBar.setOnProgressChangedListener { progress ->
tvProgressValue.text = progress
.roundToInt()
.toString()
}
circularSeekBar.setOnAnimationEndListener { _ ->
// listen
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.seosh817.circularseekbar.CircularSeekBar
android:id="@+id/circular_seek_bar"
android:layout_width="match_parent"
android:layout_height="300dp"
app:circularSeekBar_animation="bounce"
app:circularSeekBar_animationDurationMillis="1000"
app:circularSeekBar_barStrokeCap="butt"
app:circularSeekBar_barWidth="8dp"
app:circularSeekBar_innerThumbRadius="5dp"
app:circularSeekBar_innerThumbStrokeWidth="3dp"
app:circularSeekBar_min="0"
app:circularSeekBar_outerThumbRadius="5dp"
app:circularSeekBar_outerThumbStrokeWidth="10dp"
app:circularSeekBar_progressGradientColors="@array/rainbow"
app:circularSeekBar_startAngle="45"
app:circularSeekBar_dashWidth="1"
app:circularSeekBar_dashGap="2"
app:circularSeekBar_sweepAngle="270"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
If you want to change the SeekBar's animation, implement the CircularSeekBar Animation properties.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
with(binding) {
circularSeekBar.circularSeekBarAnimation = CircularSeekBarAnimation.BOUNCE // NORMAL, BOUNCE, DECELERATE, ACCELERATE_DECELERATE
circularSeekBar.animationDurationMillis = 1000
}
}
}
If you want to apply a custom animation, implement the animationInterpolator property.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
with(binding) {
circularSeekBar.animationInterpolator = AccelerateInterpolator()
circularSeekBar.animationDurationMillis = 1000
}
}
}
Add mavenCentral()
to your project build.gradle file.
allprojects {
repositories {
mavenCentral()
}
}
Then, add dependency to your module's build.gradle file.
dependencies {
implementation "com.seosh817:circularseekbar:1.0.2"
}
You can customize the CircularSeekBar using the following properties:
Property | Type | Default | Description |
---|---|---|---|
progress | Float |
0f | Current value of seek bar. |
min | Float |
0f | Minimum value of seek bar. |
max | Float |
100f | Maximum value of seek bar. |
startAngle | Float |
0f | The Angle to start drawing this seek bar from. |
sweepAngle | Float |
360f | The Angle through which to draw the seek bar. |
barWidth | Float |
6f | The thickness of the seek bar. |
trackColor | Color |
Color.LTGRAY | Background track color of seek bar. |
trackGradientColors | IntArray |
intArrayOf() | Background track gradient colors of seek bar. If [trackGradientColors] is not empty, [trackColor] is not applied. |
progressColor | Color |
Color.parseColor("#FF189BFA") | Foreground progress color of seek bar. |
progressGradientColors | IntArray |
intArrayOf() | Foreground progressGradientColors of seek bar. If [progressGradientColors] is not empty, [progressColor] is not applied. |
strokeCap | BarStrokeCap |
BarStrokeCap.ROUND | Styles to use for arcs endings. |
showAnimation | Boolean |
true | Active seek bar animation. |
circularSeekBarAnimation | CircularSeekBarAnimation |
CircularSeekBarAnimation.BOUNCE | Animation of [CircularSeekBar]. |
animDurationMillis | Int |
1000 | Animation duration milliseconds. |
innerThumbRadius | Float |
0f | The radius of the [CircularSeekBar] inner thumb. |
innerThumbStrokeWidth | Float |
0f | The stroke width of the [CircularSeekBar] inner thumb. |
innerThumbColor | Color |
Color.parseColor("#FF189BFA") | Color of the [CircularSeekBar] inner thumb. |
innerThumbStyle | ThumbStyle |
ThumbStyle.FILL_AND_STROKE | Style of the [CircularSeekBar] inner thumb. |
outerThumbRadius | Float |
0f | The radius of the [CircularSeekBar] outer thumb. |
outerThumbStrokeWidth | Float |
0f | The stroke width of the [CircularSeekBar] outer thumb. |
outerThumbColor | Color |
Color.WHITE | Color of the [CircularSeekBar] outer thumb. |
outerThumbStyle | ThumbStyle |
ThumbStyle.FILL_AND_STROKE | Style of the [CircularSeekBar] outer thumb. |
dashWidth | Float |
0f | Dash width of [CircularSeekBar]. |
dashGap | Float |
0f | Dash gap of [CircularSeekBar]. |
interactive | Boolean |
true | Set to true if you want to interact with TapDown to change the seekbar's progress. |
Copyright 2023 seosh817 (Seunghwan Seo)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Feel free to file an issue if you find a problem or make pull requests.
All contributions are welcome π