CircularSeekBar

Additional

Language
Kotlin
Version
v1.0.2 (Mar 29, 2023)
Created
Oct 9, 2022
Updated
Mar 29, 2023
Owner
Seunghwan Seo (seosh817)
Contributor
Seunghwan Seo (seosh817)
1
Activity
N/A
Badge
Generate
Download
Source code

CircularSeekBar


???? CircularSeekBar is a circular progress bar/seek bar android library that supports animations, dashes and gradients.

Getting Started

Youtube Demo Video

An example project can be found in the example directory of this repository.

Basic Examples

1. Basic SeekBar

Xml code:

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>

2. Gradient SeekBar

Xml code(colors.xml):

<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 code(activity_main.xml):

<?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>

3. Dashed SeekBar

Xml code:

<?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 code:

<?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 code:

<?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>

4. Listen to the progress changed.

Xml code:

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
            }
        }
    }
}

5. Animations

Xml code:

<?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>

Kotlin code:

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
    }
  }
}

Installing

Gradle

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"
}

Properties

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.

License

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.

Contribution

Feel free to file an issue if you find a problem or make pull requests.
All contributions are welcome ????