Android - 如何将进度条设置为垂直显示而不是水平显示?

41

我正在尝试将 ProgressBar 作为类似计量的显示。我原以为这是一项容易的任务,并认为 ProgressBar 有一个可以设置为垂直的属性,但我没有看到任何东西。

此外,我希望能够在条形图的侧面显示标尺样式的指示器,以清晰地指示当前水平。

欢迎提供指引 - 谢谢!


http://android-coding.blogspot.co.uk/2013/02/implement-vertical-progressbar.html - M--
16个回答

73

我最近需要使用垂直进度条,但无法通过现有的进度条小部件找到解决方案。我找到的解决方案通常要求扩展当前的进度条或完全创建一个新类。我不认为必须要推出一个新类来实现简单的方向更改。

本文介绍了一种简单、优雅且最重要的是非黑客解决方案来达到垂直进度条。 我将跳过解释,直接提供一个万能解决方案。如果您需要更多详情,请随时与我联系或在下面评论。

在drawable文件夹中创建一个xml文件(不是drawable-hdpi或drawable-mdpi -- 放置于drawable中)。以本示例为例,我称之为vertical_progress_bar.xml

以下是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>
      <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>

创建一个名为styles.xml的xml文件并将其放置在res/values目录中。如果您的项目已经在res/values目录中包含了styles.xml文件,则可以跳过此步骤。

修改您的styles.xml文件,在文件末尾追加以下代码:

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

将新的垂直进度条添加到您的布局中。这里是一个例子:

<ProgressBar
  android:id="@+id/vertical_progressbar"
  android:layout_width="12dip"
  android:layout_height="300dip"
  style="@style/Widget.ProgressBar.Vertical"
/>

这是你在项目中使用垂直进度条所需的全部内容。如果有自定义的可拉伸图形用于进度条,需要相应地在progress_bar_vertical.xml文件中进行更改。 希望这对你的项目有所帮助!


3
@jagsaund 给出的链接中没有文件。 - yuva ツ
1
@jagasund:链接已失效。 - Phantômaxx
使用在Lollipop版本中的主题,恐怕这不会与水平进度条的默认行为保持一致。或许不应该使用它 :( - Martin Devillers
解决方案不可用。不能绘制可绘制对象。我收到错误信息:“颜色格式应该以#开头”。成功应用了此线程中Daniel S.的解决方案。 - Gaucho
快速修复,谢谢,但由于某些原因在Android 4.1上无法工作 :( - Advanced
显示剩余3条评论

33

您需要创建自己的自定义进度条。

在您的xml中添加以下布局:

 <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);

    }
}

或者:Jagsaund的解决方案也非常完美。


1
很不幸,当高度等于进度条宽度(从顶部开始)时,进度条未能正确更新,我认为某些x/y可能被混淆了,但我找不到简单的解决方法,所以采用了jagsaund的解决方案。 - SAKIROGLU Koray
2
在onSizeChanged()之后添加invalidate();以避免出现提到的渲染问题。 - Oliver Jonas

26

我知道这是一篇旧帖子,但我找到了一个非常简单的解决方案,也许可以帮助某些人。 首先创建一个名为progress_drawable_vertical.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="vertical"
        android:gravity="bottom">
        <shape>
            <gradient
                android:startColor="#00FF00"
                android:centerColor="#FFFF00"
                android:endColor="#FF0000"
                android:angle="90" />
        </shape>
    </clip>
</item>
</layer-list>

然后在您的进度条中使用此代码:

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

我也创建了一个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>

旨在保持progress_drawable_vertical.xml文件中定义的相同风格。

关键在于正确使用android:clipOrientationandroid:gravity属性。

我在这里找到了这个解决方案,核心思想与jagsaund类似,但更简单一些。


1
很棒!使用这个,我还能够创建一个从底部到顶部的圆形填充进度。 - humblerookie

13
我发现可能是最好的(最简单和最通用)解决方案:)
虽然这是一篇旧文章,但对于我来说很难找到这么简单的解决方案,所以我觉得应该发布它。。
只需使用一个scale-drawable(或9-patch,如果您想要),不需要任何其他代码。
例如:
<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>  

当然,还有正常的代码:
<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" />  

请注意scale-drawable的xml代码(神奇的代码):
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

8
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"/>

7

简单易行的方法:

只需将一个视图添加到LinearLayout中并进行缩放。

在此输入图片描述

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

将视图的pivotY设置为零:

progressView.pivotY = 0F

现在你可以使用 scaleY0F1F 之间填充进度:

progressView.scaleY = 0.3F

奖励:使用animate()动画进度:
progressView.animate().scaleY(0.3F).start()

你能提供一个完整的例子吗? - TomSelleck
1
@TomSelleck 示例已经完成!只需在视图中的任何位置添加XML代码,并使用progressView.animate().scaleY(0.3F).start()来调整进度,其中0.3F是进度值。 - Amir

6

创建进度条(我将我的代码从C#转换成Java,因此可能不是100%正确)

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>

使你的垂直进度条竖直的是 vertical_progress_bar.xml 中的 scaleHeightscaleGravity 属性。

最终效果如下图所示:

enter image description here


你是天才老板。 - A.I.Shakil
完美运行中... - Ashish Choudhary

5
这里有一个简单的解决方案,只需旋转您的进度条。
android:rotation="270"

经过一些实验,我终于让它工作了。在LinearLayout中,android:layout_width必须是“fill_parent”,而且我不得不稍微调整一下layout_weight,使其扩展到我想要的位置。但是嘿 - 它起作用了!而且比制作自定义内容简单得多。谢谢! - Mark Phillips
它只能在方形布局下运作得完美。 - Nikunj Paradva
但是你需要声明scaleX来管理进度条的高度。 - Er. Amreesh Arya

2
将以下内容添加到xml代码中 android:rotation="90" android:transformPivotX="0dp" 这样,您的进度条xml应该如下所示
<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" />

1
我有同样的问题。创建一个自定义类(扩展ProgressBar)会产生难以维护的代码。使用自定义风格将导致与新操作系统不同主题的兼容性问题(例如lollipop)。
最终,我只是将旋转动画应用于水平进度条。受Pete的启发。
  1. 像普通的水平进度条一样在您的布局xml中创建标签。
  2. 确保进度条的大小和位置在旋转后符合您的要求。(也许设置负边距会有所帮助)。在我的代码中,我将视图从0,0旋转。
  3. 使用下面的方法旋转并设置新的进度。

代码:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接