bursk
bursk

Reputation: 1667

Android - set a ProgressBar to be a vertical bar instead of horizontal?

I am trying to use a ProgressBar as a metering like display. I thought it was going to be an easy task and thought that ProgressBar had a property to set to be vertical, but I'm not seeing anything.

Additionally I'd like to be able to show ruler like indicator along the side of the bar to clearly indicate the current level.

Pointers appreciated - Thanks!

Upvotes: 43

Views: 58141

Answers (17)

Mike L
Mike L

Reputation: 1

After hours of searching, I had an idea:
If you can rotate the div then putting rotate: 90deg or rotate: 270deg in the STYLE will work.

Upvotes: 0

jhwblender
jhwblender

Reputation: 1066

For making a vertical ProgressBar, The way that I solved it was first rotating it by 90 degrees, then scaling it with a value entered by hand.

scaleX = layout_height/layout_width

Here's an example of my attributes on the ProgressBar

android:layout_width="20dp"
android:layout_height="233dp"
android:rotation="-90"
android:scaleX="11.65"

This can be a little manual, but because they don't have a vertical progress bar by default, this was a pretty good workaround for me. The scaleX could be calculated automatically, but it would have to be after everything is drawn on the screen.

Upvotes: 0

Amir
Amir

Reputation: 1815

Simple and Easy way:

Just add a view to a LinearLayout and scale it.

enter image description here

<LinearLayout
        android:layout_width="4dp"
        android:layout_height="300dp"
        android:background="@color/md_green_50"
        android:orientation="vertical">
    <View
            android:id="@+id/progressView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_gravity="top"
            android:layout_weight="1"
            android:background="@color/md_green_500"
            android:scaleY="0.0" />
</LinearLayout>

Set View's pivotY to zero:

progressView.pivotY = 0F

Now you can fill the progress using scaleY between 0F and 1F:

progressView.scaleY = 0.3F

Bonus: Animate progress using animate():

progressView.animate().scaleY(0.3F).start()

Upvotes: 7

user11264141
user11264141

Reputation:

Here is a simple solution, just rotate your progress bar

android:rotation="270"

Upvotes: 6

Emmanuel Kibicho
Emmanuel Kibicho

Reputation: 21

Add this to the xml code android:rotation="90" android:transformPivotX="0dp" So this is how your Progress Bar xml should look

<ProgressBar
    android:id="@+id/progressBar6"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:rotation="90"
    android:transformPivotX="0dp"
    tools:layout_editor_absoluteX="101dp"
    tools:layout_editor_absoluteY="187dp" />

Upvotes: 2

Prashant singh
Prashant singh

Reputation: 113

enter link description here

**Check this link out, I was trying to use a similar thing and also you can use stepper for your requirement, few projects are available on Github about HOW TO USE STEPPER IN ANDROID STUDIO **

Upvotes: 0

Anupam
Anupam

Reputation: 2853

This perfectly works

<?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>
            <gradient
                android:startColor="#DDDDDD"
                android:centerColor="#DDDDDD"
                android:centerY="0.75"
                android:endColor="#DDDDDD"
                android:angle="270"
                />
        </shape>
    </item>

    <item
        android:id="@android:id/progress">
        <clip
            android:clipOrientation="vertical"
            android:gravity="top">
            <shape>
                <gradient
                    android:angle="0"
                    android:startColor="#302367"
                    android:centerColor="#7A5667"
                    android:endColor="#C86D67"/>
            </shape>
        </clip>
    </item>
</layer-list>

    <ProgressBar
            android:id="@+id/progress_bar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="5dp"
            android:layout_height="match_parent"`enter code here`
            android:progressDrawable="@drawable/progress_dialog"/>

Upvotes: 8

Met-u
Met-u

Reputation: 675

Creating the progress bar (I converted my code from c# to java so might not be 100% correct)

ProgressBar progBar = new ProgressBar(Context, null, Android.resource.attribute.progressDrawable);
progBar.progressDrawable = ContextCompat.getDrawable(Context, resource.drawable.vertical_progress_bar);
progBar.indeterminate = false;

vertical_progress_bar.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">
        <shape>
          <solid android:color="@color/grey" />

          <corners android:radius="20dip" />
        </shape>
      </item>
      <item android:id="@android:id/progress">
        <scale
            android:drawable="@drawable/vertical_progress_bar_blue_progress"
            android:scaleHeight="100%"
            android:scaleGravity="bottom"/>
      </item>
    </layer-list>

vertical_progress_bar_blue_progress.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

  <corners
      android:radius="20dip" />

  <solid android:color="@color/ProgressBarFourth" />

</shape>

What's going to make your bar vertical is the scaleHeight and scaleGravity attributes in vertical_progress_bar.xml.

It ends up looking something like this:

enter image description here

Upvotes: 6

Beto Caldas
Beto Caldas

Reputation: 2323

<ProgressBar
        android:id="@+id/battery_pb"
        android:rotation="270"
        android:progress="100"
...
/>

Use android:rotation="270" to 100% be like bottom to top or android:rotation="90" to 100% be like top to bottom

Upvotes: 0

guy_m
guy_m

Reputation: 3307

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

Upvotes: 14

Vahe Gharibyan
Vahe Gharibyan

Reputation: 5683

Simple progrebar image view

example

viewHolder.proBarTrueImage.setMaximalValue(147);
viewHolder.proBarTrueImage.setLevel(45);
viewHolder.proBarTrueImage.setColorResource(R.color.corner_blue);

simple class

public class ProgressImageView extends ImageView {

private Context mContext;
private Paint paint;
private RectF rectf;

private int maximalValue = 1;
private int level = 0;
private int width;
private int height;

public ProgressImageView(Context context) {
    super(context);
    init(context, null, 0);
}

public ProgressImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs, 0);
}

public ProgressImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs, defStyleAttr);
}

private  void init(Context context, AttributeSet attrs, int defStyleAttr){

    mContext = context;
    paint = new Paint();
    rectf = new RectF();
    paint.setColor(Color.GRAY);
    paint.setStyle(Paint.Style.FILL);
};

@Override
protected void onDraw(Canvas canvas) {

    float dif = (float) height / (float) maximalValue;
    int newHeight = height - (int) (dif * level);

    rectf.set(0,newHeight, width, height);
    canvas.drawRect(rectf, paint);

    super.onDraw(canvas);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    this.width = w;
    this.height = h;
}

public void setMaximalValue(int maximalValue) {
    this.maximalValue = maximalValue;
    invalidate();
}

public void setLevel(int level) {
    this.level = level;
    invalidate();
}

public void setColorResource(int color) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        color = mContext.getResources().getColor(color,mContext.getTheme());
    }else {
        color = mContext.getResources().getColor(R.color.corner_blue);
    }

    setColor(color);
}

public void setColor(int color){
    if (paint != null){
        paint.setColor(color);
        invalidate();
    }
}

}

Upvotes: 0

Daniel S.
Daniel S.

Reputation: 2677

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.

Upvotes: 26

Pan Ng
Pan Ng

Reputation: 106

I have the exact problem. Making a custom class (extending ProgressBar) will create code that are hard to maintain. Using a custom style will cause compatibility issue with different theme from new OS (e.g. lollipop)

Eventually, I just apply a rotation animation to an horizontal progress bar. Inspired by Pete.

  1. Create the tag in your layout xml like normal horizontal progress bar.
  2. Make sure that the size and position of the ProgressBar is what you want after rotation. (Perhaps setting negative margin will help). In my code I rotate the view from 0,0.
  3. Use the method below to rotate and set new progress.

Code:

private void setProgress(final ProgressBar progressBar, int progress) {
    progressBar.setWillNotDraw(true);
    progressBar.setProgress(progress);
    progressBar.setWillNotDraw(false);
    progressBar.invalidate();
}

private void rotateView(final View v, float degree) {
    Animation an = new RotateAnimation(0.0f, degree);
    an.setDuration(0);
    an.setRepeatCount(0);
    an.setFillAfter(true);               // keep rotation after animation
    v.setAnimation(an);
}

Upvotes: 1

jagsaund
jagsaund

Reputation: 2387

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!

Upvotes: 73

Ramesh Akula
Ramesh Akula

Reputation: 5750

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.

Upvotes: 33

John Leehey
John Leehey

Reputation: 22240

To utilize the ProgressBar and make it vertical, you would have to create your own custom View extending the ProgressBar view and override the onDraw() method. This will allow you to draw it in a reverse orientation. Take a look at the source code of the ProgressBar.onDraw() (located at the bottom of the link) for help on how to do this. Best case scenario, you'll just have to swap a few x and y variables.

Upvotes: 1

Romain Guy
Romain Guy

Reputation: 98501

Vertical progress bars are not supported by default.

Upvotes: -18

Related Questions