Android - set a ProgressBar to be a vertical bar instead of horizontal?
I had recently come across the need for a vertical progress bar but was unable to find a solution using the existing Progress Bar widget. The solutions I came across generally required an extension of the current Progress Bar or a completely new class in it self. I wasn't convinced rolling out a new class to achieve a simple orientation change was necessary.
This article presents a simple, elegant, and most importantly, a no-hack solution to achieving a vertical progress bar. I'm going to skip the explanation and simply provide a cookie cutter solution. If you require further details feel free to contact me or leave a comment below.
Create an xml in your drawable folder (not drawable-hdpi or drawable-mdpi -- place it in drawable). For this example I call my xml vertical_progress_bar.xml
Here's what to place in the xml file:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ff9d9e9d"
android:centerColor="#ff5a5d5a"
android:centerY="0.75"
android:endColor="#ff747674"
android:angle="180"
/>
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip android:clipOrientation="vertical" android:gravity="bottom">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#80ffd300"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:angle="180"
/>
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip android:clipOrientation="vertical" android:gravity="bottom">
<shape>
<corners android:radius="5dip" />
<gradient
android:startColor="#ffffd300"
android:centerColor="#ffffb600"
android:centerY="0.75"
android:endColor="#ffffcb00"
android:angle="180"
/>
</shape>
</clip>
</item>
</layer-list>
Create an xml file called styles.xml and place it in res/values. If your project already contains styles.xml in res/values then skip this step.
Modify your styles.xml file and append the following code to the end of the file:
<style name="Widget">
</style>
<style name="Widget.ProgressBar">
<item name="android:indeterminateOnly">true</item>
<item name="android:indeterminateBehavior">repeat</item>
<item name="android:indeterminateDuration">3500</item>
<item name="android:minWidth">48dip</item>
<item name="android:maxWidth">48dip</item>
<item name="android:minHeight">48dip</item>
<item name="android:maxHeight">48dip</item>
</style>
<style name="Widget.ProgressBar.Vertical">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@drawable/progress_bar_vertical</item>
<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
<item name="android:minWidth">1dip</item>
<item name="android:maxWidth">12dip</item>
</style>
Add your new vertical progress bar to your layout. Here's an example:
<ProgressBar
android:id="@+id/vertical_progressbar"
android:layout_width="12dip"
android:layout_height="300dip"
style="@style/Widget.ProgressBar.Vertical"
/>
That should be all you need to do to make use of a vertical progress bar in your project. Optionally, you might have custom drawable nine-patch images that you are using for the progress bar. You should make the appropriate changes in the progress_bar_vertical.xml file. I hope this helps you out in your project!
I found the probably best(easiest & most versatile) solution:)
This is an old post, but it was so hard for me to find this so easy solution so I thought I should post it..
Just use a scale-drawable
(or a 9-patch if you want), no need for ANY OTHER code.
Example:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background" android:drawable="@color/transparent"/>
<item android:id="@android:id/progress">
<scale android:scaleGravity="bottom" android:scaleWidth="0%" android:scaleHeight="100%">
<shape >
<solid android:color="@color/blue"/>
<corners android:topRightRadius="1dp" android:topLeftRadius="1dp"/>
</shape>
</scale>
</item>
</layer-list>
And of course the normal code:
<ProgressBar
android:id="@+id/progress_bar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="24dp"
android:layout_height="match_parent"
android:max="1000"
android:progress="200"
android:progressDrawable="@drawable/progress_scale_drawable" />
Notice the scale-drawable
's xml lines (the magic lines):
android:scaleGravity="bottom" //scale from 0 in y axis (default scales from center Y)
android:scaleWidth="0%" //don't scale width (according to 'progress')
android:scaleHeight="100%" //do scale the height of the drawable
You have to create your own custom progressbar.
In your xml add this layout:
<com.example.component.VerticalProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:id="@+id/verticalRatingBar1"
android:layout_width="wrap_content"
android:progress="50"
android:layout_height="fill_parent" />
VerticalProgressBar.java
public class VerticalProgressBar extends ProgressBar{
private int x, y, z, w;
@Override
protected void drawableStateChanged() {
// TODO Auto-generated method stub
super.drawableStateChanged();
}
public VerticalProgressBar(Context context) {
super(context);
}
public VerticalProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
this.x = w;
this.y = h;
this.z = oldw;
this.w = oldh;
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setSelected(true);
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
setProgress(getMax()
- (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_UP:
setSelected(false);
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
@Override
public synchronized void setProgress(int progress) {
if (progress >= 0)
super.setProgress(progress);
else
super.setProgress(0);
onSizeChanged(x, y, z, w);
}
}
Or : Jagsaund solution is also being perfect.
I know that it´s an old post but I found a very simple solution to this problem that maybe can help somebody. First at all create a progress_drawable_vertical.xml like this:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<color android:color="#777" />
</item>
<item android:id="@android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<gradient
android:startColor="#00FF00"
android:centerColor="#FFFF00"
android:endColor="#FF0000"
android:angle="90" />
</shape>
</clip>
</item>
</layer-list>
Then just use this in your progressBar:
<ProgressBar
android:id="@+id/progress_bar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:max="100"
android:progress="33"
android:progressDrawable="@drawable/progress_drawable_vertical" />
I also have created an progress_drawable_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<color android:color="#777" />
</item>
<item android:id="@android:id/progress">
<clip
android:clipOrientation="horizontal"
android:gravity="left">
<shape>
<gradient
android:startColor="#00FF00"
android:centerColor="#FFFF00"
android:endColor="#FF0000" />
</shape>
</clip>
</item>
</layer-list>
with the objetive of mantain the same style defined in progress_drawable_vertical.xml
The key here is the correct use of android:clipOrientation
and android:gravity
.
I found this solution here and the core of the solution is similar to jagsaund but a little bit more simple.