如何设计具有圆边和倾斜进度的自定义进度条?

时间:2015-12-22 16:49:30

标签: android android-view android-custom-view android-progressbar rounded-corners

这是我希望实现的目标: Clicky

容器颜色,进度颜色,进度背景颜色和圆角半径以及厚度都应该是可编辑和可修改的。

如何通过轻量级自定义UI元素实现这一目标?

3 个答案:

答案 0 :(得分:2)

经过数天的研究,我能够通过清晰的UI以及所有上述要求和灵活性实现预期目标。可以实现上面的精确UI,也可以实现以下参数: 1.进步颜色 2.进展背景颜色 3.容器颜色(由您设置的容器颜色,您可以设置圆角边缘的颜色以匹配容器颜色) 4.进度条的高度和宽度,以满足您的需求。

以下是实现它的代码和步骤:

予。将此代码放在文件夹下的 attrs.xml 文件中

<declare-styleable name="SlantingProgressBar">
    <attr name="slantingProgress" format="integer"/>
    <attr name="borderRadius" format="integer"/>
    <attr name="borderColor" format="integer"/>
    <attr name="slantingProgressColor" format="string"/>
    <attr name="progressBackgroundColor" format="string"/>
    <attr name="slantingProgressFullColor" format="string"/>

</declare-styleable>

II。创建一个这样的java类:

public class SlantingProgressbar extends View {
private float height = 0;
private float width = 0;
private int borderRadius = 20;
private float progress = 0;

private int rawProgress = 0;
private static final String OPACITY_30_PERCENT = "#66";

private int roundedBorderColor;
private String backgroundColor = "";
private String progressColor = "";
private String progressFullColor = "#fc3d39";

public SlantingProgressbar(Context context) {
    super(context);

}

public SlantingProgressbar(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray array = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.SlantingProgressBar,
            0, 0);

    try {
        setProgress(array.getInt(R.styleable.SlantingProgressBar_slantingProgress, 0));
        setBackgroundColor(array.getString(R.styleable.SlantingProgressBar_progressBackgroundColor));    //Default color set in the method
        setBorderRadius(array.getInt(R.styleable.SlantingProgressBar_borderRadius, 20));
        setRoundedBorderColor(array.getInt(R.styleable.SlantingProgressBar_borderColor, 0));
        setProgressColor(array.getString(R.styleable.SlantingProgressBar_slantingProgressColor));
    } finally {
        array.recycle();
    }
}

public void setBorderRadius(int borderRadius) {
    this.borderRadius = borderRadius;
}


public int getProgress() {
    return rawProgress;
}

public void setProgress(int progress) {
    if(progress >=0)
    {
        this.rawProgress = progress;
        this.invalidate();
    }
    else
        Log.e("ChlorophyllProgressBar", "Invalid 'progress' value detected, value should be between 0 and 100");

}


public void setRoundedBorderColor(int roundedBorderColor) {
    if ( roundedBorderColor == 0) {
        this.roundedBorderColor = getResources().getColor(R.color.white);
        Log.e("CUSTOM_TAG", "Color set to White: " + this.roundedBorderColor);
        return;
    }

    this.roundedBorderColor = roundedBorderColor;
    Log.e("CUSTOM_TAG", "Color set to custom: " + this.roundedBorderColor);

}

private int getRoundedBorderColor()
{
    return roundedBorderColor;
}

public void setSlantingProgressFullColor(String color)
{
    if (TextUtils.isEmpty(progressFullColor)) {
        this.progressFullColor = "#fc3d39";
        return;
    }
}


public void setBackgroundColor(String backgroundColor) {
    if (TextUtils.isEmpty(backgroundColor)) {
        this.backgroundColor = "#bfe8d4";
        return;
    }

    this.backgroundColor = backgroundColor;
}


public void setProgressColor(String progressColor) {
    if (TextUtils.isEmpty(progressColor)) {
        this.progressColor = "#2bb673"; //Green
        return;
    }
    this.progressColor = progressColor;
}

public float getViewHeight() {
    return height;
}

public void setViewHeight(float height) {
    this.height = height;
}

public float getViewWidth() {
    return width;
}

public void setViewWidth(float width) {
    this.width = width;
}


@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    height = getHeight();
    width = getWidth();
    progress = getProcessedProgress();

    Paint paint = new Paint();
    paint.setStyle(Paint.Style.FILL);
    paint.setColor(Color.parseColor(backgroundColor));
    canvas.drawPaint(paint);
    paint.setColor(getProcessedProgressColor());
    paint.setAntiAlias(true);

    Log.d("CUSTOM_TAG", "Height: " + height);
    canvas.drawRect(0, 0, progress, height, paint);


    Path triangle = new Path();
    triangle.setFillType(Path.FillType.EVEN_ODD);

    triangle.moveTo(progress, 0);
    triangle.lineTo(progress + height, 0);
    triangle.lineTo(progress, height);
    triangle.close();

    canvas.drawPath(triangle, paint);

    drawBorders(canvas, getRoundedBorderColor());
}


private void drawBorders(Canvas canvas, int color) {
    float height = getHeight();
    float trueWidth = getWidth();

    Paint paint = new Paint();
    paint.setStyle(Paint.Style.FILL);
    paint.setColor(color);
    //paint.setColor(getResources().getColor(R.color.white));
    paint.setAntiAlias(true);

    Path border = new Path();

    border.moveTo(0, 0);
    border.lineTo(0, height / 2);
    border.quadTo(height / borderRadius, height / borderRadius, height / 2, 0);
    border.lineTo(0, 0);

    canvas.drawPath(border, paint);

    border.reset();

    border.moveTo(0, height);
    border.lineTo(height / 2, height);
    border.quadTo(height / borderRadius, (height - height / borderRadius), 0, height / 2);
    border.lineTo(0, height);

    canvas.drawPath(border, paint);

    border.reset();

    border.moveTo(trueWidth, 0);
    border.lineTo(trueWidth - (height / 2), 0);
    border.quadTo((trueWidth - height / borderRadius), height / borderRadius, trueWidth, height / 2);
    border.lineTo(trueWidth, 0);

    canvas.drawPath(border, paint);

    border.reset();

    border.moveTo(trueWidth, height);
    border.lineTo(trueWidth - (height / 2), height);
    border.quadTo((trueWidth - height / borderRadius), (height - height / borderRadius), trueWidth, height / 2);
    border.lineTo(trueWidth, height);

    canvas.drawPath(border, paint);

    //Adding 1 pixel color
    Paint paint1 = new Paint();
    paint1.setStyle(Paint.Style.FILL);
    int fadedColor = (color & 0x00FFFFFF) | 0x66000000;
    Log.d("CUSTOM_TAG", "Faded Color Code: " + fadedColor);
    paint1.setColor(fadedColor);
    canvas.drawRect(0, 0, 1, height, paint1);
    canvas.drawRect(trueWidth-1, 0, trueWidth, height, paint1);
}

private float getProcessedProgress()
{
    return (rawProgress == 99) ? ((getWidth() * 98) / 100) : ((getWidth() * rawProgress) / 100);
}

private int getProcessedProgressColor()
{
    if(rawProgress > 100)
    {
        return Color.parseColor(progressFullColor);
    }
    else
    {
        return Color.parseColor(progressColor);
    }


}
}

III。要在xml文件中使用布局:

<com.whatever.package.SlantingProgressbar
        android:id="@+id/progressbar_detail"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimension1"
        android:layout_alignParentLeft="true"
        slanting_progress:borderColor="@color/darkgray"
        android:layout_below="@id/alphacon_detail"
        android:layout_marginBottom="@dimen/budget_list_item_paddingBottom"
        android:progress="50" />

我会在一段时间之后分享这段代码,所以我可能错过了一两件事,我很确定你能解决这个问题,请随时纠正我。

说明: 我们在java中使用'draw'方法来实现此功能。优点是,绘制UI元素可以为我们提供清晰明了的UI,无论您做多大或多小。 可能存在一些硬编码值,因此请务必在实现之前对其进行编辑。

祝你好运,如果这篇文章对你有帮助,不要忘了向上投票。谢谢! :)

答案 1 :(得分:0)

我会在这里发布一个答案,以显示您的代码的一些改进。

  • 您应避免在draw期间创建新对象。

draw一次又一次被多次调用以重绘自定义元素,所有这些对new Paint()的调用都在创建新对象,需要新的内存分配,并且它会使垃圾收集器变得疯狂并使您的查看资源更加密集,可能会导致滚动元素滞后,例如RecyclerView

或者你应该将它们声明为private Paint border然后private Paint triangle等等。然后你应该在一个单独的方法中初始化所有油漆的值,并且只有在参数改变时。示例代码:

private boolean initPaint = false;
private void initPaintsIfNecessary(){
   if(!initPaint) return;
   initPaint = false;

   triangle = new Paint();
   triangle.set.... etc

   border = new Paint();
   border.set.... etc
}

然后是所有方法setRoundedBorderColorsetProgressColor等。您拨打initPaint = true;并在draw的开头呼叫initPaintsIfNecessary();。这将避免所有额外的垃圾收集器工作,并将允许您的应用程序的UI运行更顺畅。

这也包括Paint方法中的所有drawBorders

  • 使用format="color" instead of string`。

调用Color.parse(String)是一个非常慢的调用,它非常容易出错。或者,您应该使用正确的color元素,如下所示:

<attr name="slantingProgressColor" format="color"/>

这不仅是正确的方法,而是在编辑器上为您提供颜色预览,可以在应用程序样式参数上建立索引,并避免对parse的低效调用

当然你应该适当调整或方法。例如:     setProgressColor(array.getColor(R.styleable.SlantingProgressBar_slantingProgressColor));

getColor将返回一个可以在paint.setColor(int);

中直接使用的整数

我希望这些提示能够帮助您(以及社区中的其他人)创建更高效​​的View元素。快乐的编码!

答案 2 :(得分:0)

我知道这个老问题要回答,但这个答案可能有帮助.. 您可以使用drawArc方法来实现此目的。

RectF oval = new RectF();
oval.set(left, top ,right, bottom);
canvas.drawArc(oval, 270, 360, false, paint);