I have created a circle with a stroke and white background using xml. How can this be filled gradually from bottom to top on user actions(e.g. on successive button press)?
Is there any free library which can be used to achieve similar thing?
If you arrange your drawable like so:
res/drawable/custom_progress.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingMode="stack">
<item android:id="@android:id/background">
<inset android:inset="@dimen/border_width">
<shape android:shape="oval">
<solid android:color="@color/background" />
</shape>
</inset>
</item>
<item android:id="@android:id/progress">
<inset android:inset="@dimen/border_width">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape android:shape="oval">
<solid android:color="@color/progress" />
</shape>
</clip>
</inset>
</item>
<item>
<shape android:shape="oval">
<stroke
android:width="@dimen/border_width"
android:color="@color/border" />
</shape>
</item>
</layer-list>
It can be used directly with a ProgressBar
, like so:
res/layout/activity_example.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ProgressBar
android:id="@+id/custom_progress_bar"
style="?android:progressBarStyleHorizontal"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginVertical="10dp"
android:progressDrawable="@drawable/custom_progress" />
<com.google.android.material.slider.Slider
android:id="@+id/slider"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:valueTo="100"
app:labelBehavior="gone" />
</LinearLayout>
Then it can be wired up to that Slider
like so:
class ExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val ui = ActivityExampleBinding.inflate(layoutInflater)
setContentView(ui.root)
ui.slider.addOnChangeListener { _, value, _ ->
ui.customProgressBar.progress = value.roundToInt()
}
}
}
And you'll get something like this:
The <item>
s in custom_progress
are just regular drawables that can be set
up and configured like in any other context. For example, the <solid>
inside
the <shape>
could be replaced with a <gradient>
, like is shown on
the relevant developer page.
The previous versions of this answer used a bespoke custom View
to do this. I wouldn't necessarily recommend that approach these days, now that
I'm a little more familiar with things, but it does show a pretty
straightforward example of custom attributes, if you should need that for your
setup. ProgressBar
could be subclassed to apply custom attributes to the
progress drawable, though it'd take a bit of tedious work to find the actual
drawables that are wrapped in InsetDrawable
s and ClipDrawable
s and added to
a LayerDrawable
(unless you'd want to instantiate them manually, of course).
Starting with API level 24, the other option for custom attributes would be to
create a Drawable
subclass that overrides inflate()
to process them,
allowing it to be configured in drawable XML.
<drawable xmlns:app="http://schemas.android.com/apk/res-auto"
class="com.your.package.CustomDrawable"
app:progressColor="@color/blue"
… />
You can consult the platform Drawable
classes to see how
inflate()
should be implemented.