【问题标题】:Rounded progress within rounded progress bar圆形进度条内的圆形进度
【发布时间】:2014-08-05 02:36:32
【问题描述】:

我正在尝试在我们正在开发的应用中创建自定义进度条,而我需要的最后一块是进度指示器本身。相反,我希望该栏像进度条本身的左右边缘一样圆润,就像在第二张图片中一样(当然减去红色圆圈)。

这是进度条的布局定义(为简洁起见,布局文件的其余部分省略):

<ProgressBar
    android:id="@+id/progress_bar"
    android:layout_width="fill_parent"
    android:layout_height="60dp"
    android:padding="3dp"
    android:max="100"
    android:progressDrawable="@drawable/progress_bar_states"
    android:layout_marginTop="10dp"
    style="?android:attr/progressBarStyleHorizontal"
    android:indeterminateOnly="false"
    android:layout_below="@id/textview2"
    android:layout_alignLeft="@id/textview2"
    />

这里是progress_bar_states.xml 文件:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@android:id/background">
        <shape>
            <solid android:color="#20ffff00"/>
            <corners android:radius="60dp"/>
        </shape>
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <solid android:color="#20ffffff"/>
                <corners android:radius="60dp"/>
            </shape>
        </clip>
    </item>

</layer-list>

我该怎么做?我根本看不到任何允许我定义进度指示器的选项。我应该以不同的方式这样做吗?我对 Android 还是很陌生,因此我们非常感谢任何指导。

@Ando - 您的解决方案非常接近我的需要。指标运动的开始是现在的问题,我猜这是因为它不像原始剪辑那样。当指标开始时,直到开始的某个点,它看起来像是被“挤压”了

直到它到达适当的点然后它看起来很好:

我们如何使用这个解决方案在开始时完成“剪辑”?

对于@bladefury - 如您所见,与上图的前缘相比,它确实看起来是扁平的。

编辑:在很长一段时间没有看这个之后,我在https://github.com/akexorcist/Android-RoundCornerProgressBar/issues 看了一个新组件,它和这里的建议有同样的问题。

【问题讨论】:

  • 我不明白你的担忧。 android:progress=".." 应该可以正常工作。您也可以将其设置为“不确定”
  • 我不是指增加进度 - 我是在谈论进度的呈现。而不是像你通常在进度条中看到的垂直“条”,我希望它是一个圆形指示器,以匹配条本身的外部边界。我会尝试用我想要的图像来更新问题。

标签: android android-progressbar


【解决方案1】:

只需更改您的 progress_bar_states.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="#20ffff00" />

        <corners android:radius="20dp" />
    </shape>
</item>
<item android:id="@android:id/progress">

    <!-- <clip> -->
    <!-- <shape> -->
    <!-- <solid android:color="@android:color/black" /> -->


    <!-- <corners -->
    <!-- android:bottomRightRadius="30dp" -->
    <!-- android:radius="60dp" -->
    <!-- android:topRightRadius="30dp" /> -->
    <!-- </shape> -->
    <!-- </clip> -->

    <scale
        android:drawable="@drawable/custom_progress_primary"
        android:scaleWidth="98%" /><!-- change here -->
</item>

这里是 custom_progress_primary.xml 文件:如下所示

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

<corners
    android:radius="20dp"
    android:topLeftRadius="20dp"
    android:topRightRadius="20dp" />

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

<stroke
    android:width="1dp"
    android:color="@android:color/darker_gray" />

</shape>

【讨论】:

  • 这是非常接近,但在指标移动开始时有一个小问题。我在原始问题中发布了几张图片来展示它。
  • @TheIcemanCometh 可能会尝试使用剪辑,我会尝试提供最好的剪辑
  • 检查我更新的答案,并请更改我测试过的进度条的大小,高度为 20dp,半径为 20dp @TheIcemanCometh
  • @AndoMasahashi 将 scaleWidth 更改为 96%,然后即使在进度值为 1 时它对我来说也能正常工作。你能解释一下 scaleWidth 在这里做什么吗?
  • @AndoMasahashi 如何设置可移动加载梯度?
【解决方案2】:

一个可能更实用的选项是实现自定义进度条视图。

public class CustomProgressBar extends View
{
    // % value of the progressbar.
    int progressBarValue = 0;

    public CustomProgressBar(Context context)
    {
        super(context);
    }

    public CustomProgressBar(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        progressBarValue = attrs.getAttributeIntValue(null, "progressBarValue", 0);
    }

    public void setValue(int value)
    {
        progressBarValue = value;
        invalidate();
    }

    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        float cornerRadius = 30.0f;

        // Draw the background of the bar.
        Paint backgroundPaint = new Paint();
        backgroundPaint.setColor(Color.LTGRAY);
        backgroundPaint.setStyle(Paint.Style.FILL);
        backgroundPaint.setAntiAlias(true);

        RectF backgroundRect = new RectF(0, 0, canvas.getWidth(), canvas.getHeight());
        canvas.drawRoundRect(backgroundRect, cornerRadius, cornerRadius, backgroundPaint);

        // Draw the progress bar.
        Paint barPaint = new Paint();
        barPaint.setColor(Color.GREEN);
        barPaint.setStyle(Paint.Style.FILL);
        barPaint.setAntiAlias(true);

        float progress = (backgroundRect.width() / 100) * progressBarValue;
        RectF barRect = new RectF(0, 0, progress, canvas.getClipBounds().bottom);

        canvas.drawRoundRect(barRect, cornerRadius, cornerRadius, barPaint);

        // Draw progress text in the middle.
        Paint textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(34);

        String text = progressBarValue + "%";
        Rect textBounds = new Rect();

        textPaint.getTextBounds(text, 0, text.length(), textBounds);

        canvas.drawText(text,
                backgroundRect.centerX() - (textBounds.width() / 2),
                backgroundRect.centerY() + (textBounds.height() / 2),
                textPaint);

    }
}

然后在你的布局中:

<view.CustomProgressBar
    android:layout_height="30dp"
    android:layout_width="match_parent"
    progressBarValue="66"/>

产生结果:

【讨论】:

  • 如何设置最大进度值?
  • 将progressBarValue设置为低值(例如1)效果不佳:绿色条脱离灰色背景。
【解决方案3】:

您可以将此库用于圆角进度条

<com.akexorcist.roundcornerprogressbar.RoundCornerProgressBar
        android:layout_width="dimension"
        android:layout_height="dimension"
        app:rcProgress="float"
        app:rcSecondaryProgress="float"
        app:rcMax="float"
        app:rcRadius="dimension"
        app:rcBackgroundPadding="dimension"
        app:rcReverse="boolean"
        app:rcProgressColor="color"
        app:rcSecondaryProgressColor="color"
        app:rcBackgroundColor="color" />

分级

compile 'com.akexorcist:RoundCornerProgressBar:2.0.3'

https://github.com/akexorcist/Android-RoundCornerProgressBar

【讨论】:

    【解决方案4】:

    ProgressBar 使用ClipDrawable,它使用矩形剪辑可绘制对象。因此,您可以设置一个将圆角矩形剪辑为进度条的可绘制对象,方法如下:

    首先,删除进度条drawable中的&lt;clip&gt;标签:

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
    <item android:id="@android:id/background">
        <shape>
            <solid android:color="#20ffff00"/>
            <corners android:radius="60dp"/>
        </shape>
    </item>
    
    <item android:id="@android:id/progress">
            <shape>
                <solid android:color="#20ffffff"/>
                <corners android:radius="60dp"/>
            </shape>
    </item>
    

    然后,像这样扩展进度条:

    public class RoundIndicatorProgressBar extends ProgressBar {
    
        private static final float CORNER_RADIUS_DP = 60.0f;
    
        public RoundIndicatorProgressBar(Context context) {
            this(context, null);
        }
    
        public RoundIndicatorProgressBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public RoundIndicatorProgressBar(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
    
        @Override
        public void setProgressDrawable(Drawable d) {
            super.setProgressDrawable(tileify(d, false));
        }
    
        private Drawable tileify(Drawable drawable, boolean clip) {
            if (drawable instanceof LayerDrawable) {
                LayerDrawable background = (LayerDrawable) drawable;
                final int N = background.getNumberOfLayers();
                Drawable[] outDrawables = new Drawable[N];
    
                for (int i = 0; i < N; i++) {
                    int id = background.getId(i);
                    outDrawables[i] = tileify(background.getDrawable(i),
                            (id == android.R.id.progress || id == android.R.id.secondaryProgress));
                }
    
                LayerDrawable newBg = new LayerDrawable(outDrawables);
    
                for (int i = 0; i < N; i++) {
                    newBg.setId(i, background.getId(i));
                }
    
                return newBg;
    
            } else {
                if (clip) {
                    return new RoundClipDrawable(drawable, dp2px(getContext(), CORNER_RADIUS_DP));
                }
            }
            return drawable;
        }
        public static float dp2px(Context context, float dp) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return dp * scale;
        }
    
    }
    

    这里是RoundClipDrawable,修改自ClipDrawable

    RoundClipDrawable.java Gist

    【讨论】:

    • 查看我在原始问题中添加的评论。您的解决方案中指标的前沿似乎变平了......
    • @TheIcemanCometh 当然它是扁平的,因为 RoundIndicatorProgressBar 中的 CORNER_RADIUS 是 50.0f,用于演示目的。在您的情况下,您应该将其设置为适当的值。
    • 您的评论基于以下假设,即我保留了与您上面相同的值,我已经根据我的要求进行了更改(它们在任何地方都是 60dp)。 :-)
    • 非常非常接近。现在它与@Ando 的解决方案大致相同,除了你的解决方案进行剪辑。但是两种解决方案现在都有相同的问题 - 进度指示的开始。当进度从零开始,直到达到大约 20%,它仍然在指标的前沿变平。它需要在开始时完全四舍五入 - 从 0% 到 100%。这是我用来测试的示例应用程序的截屏视频:screencast.com/t/ifdJEJMy2。我在 GitHub 上也有示例应用程序,地址为 github.com/TheIcemanCometh/RoundedProgressSample1
    【解决方案5】:

    你也可以使用搜索栏

    在这里查看我的帖子: https://stackoverflow.com/a/41206481/6033946

    试试这个,你可以通过在xml中修改拇指和seekbar的颜色和宽高来做你想做的事情。

    【讨论】:

      【解决方案6】:

      我们如何在此解决方案开始时完成“剪辑”?

      您需要的是限制最小进度值,例如:

      final int minProgress = pb.getMax() * {20dp} / pb.getWidth();
      progress = Math.max(minProgress, progress);
      pb.setProgress(progress);
      

      使用上面的代码对你的进度值进行后处理是可以的。这不是可绘制的错误,而是正确的拉伸效果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-08
        • 2015-08-13
        • 2022-01-17
        • 1970-01-01
        • 1970-01-01
        • 2020-12-21
        相关资源
        最近更新 更多