Progress bar with divider

10.4k views Asked by At

Can someone please explain to me how to implement a progress bar with a divider just like its shown on the image below?

enter image description here

For the progress bar I am using https://github.com/akexorcist/Android-RoundCornerProgressBar but this does not seem to have a divider option.

3

There are 3 answers

3
pskink On BEST ANSWER

replace ProgressDrawable from my answer with the modified one:

class ProgressDrawable extends Drawable {
    private static final int NUM_SEGMENTS = 4;
    private final int mForeground;
    private final int mBackground;
    private final Paint mPaint = new Paint();
    private final RectF mSegment = new RectF();

    public ProgressDrawable(int fgColor, int bgColor) {
        mForeground = fgColor;
        mBackground = bgColor;
    }

    @Override
    protected boolean onLevelChange(int level) {
        invalidateSelf();
        return true;
    }

    @Override
    public void draw(Canvas canvas) {
        float level = getLevel() / 10000f;
        Rect b = getBounds();
        float gapWidth = b.height() / 2f;
        float segmentWidth = (b.width() - (NUM_SEGMENTS - 1) * gapWidth) / NUM_SEGMENTS;
        mSegment.set(0, 0, segmentWidth, b.height());
        mPaint.setColor(mForeground);

        for (int i = 0; i < NUM_SEGMENTS; i++) {
            float loLevel = i / (float) NUM_SEGMENTS;
            float hiLevel = (i + 1) / (float) NUM_SEGMENTS;
            if (loLevel <= level && level <= hiLevel) {
                float middle = mSegment.left + NUM_SEGMENTS * segmentWidth * (level - loLevel);
                canvas.drawRect(mSegment.left, mSegment.top, middle, mSegment.bottom, mPaint);
                mPaint.setColor(mBackground);
                canvas.drawRect(middle, mSegment.top, mSegment.right, mSegment.bottom, mPaint);
            } else {
                canvas.drawRect(mSegment, mPaint);
            }
            mSegment.offset(mSegment.width() + gapWidth, 0);
        }
    }

    @Override
    public void setAlpha(int alpha) {
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

and create it like this:

Drawable d = new ProgressDrawable(0xdd00ff00, 0x4400ff00);
4
Naga On
/**
 * Created by nagendra on 16/06/15.
 */
public class ProgressBarDrawable extends Drawable {

    private int parts = 10;

    private Paint paint = null;
    private int fillColor = Color.parseColor("#2D6EB9");
    private int emptyColor = Color.parseColor("#233952");
    private int separatorColor = Color.parseColor("#FFFFFF");
    private RectF rectFill = null;
    private RectF rectEmpty = null;
    private List<RectF> separators = null;

    public ProgressBarDrawable(int parts)
    {
        this.parts = parts;
        this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.separators = new ArrayList<RectF>();
    }

    @Override
    protected boolean onLevelChange(int level)
    {
        invalidateSelf();
        return true;
    }

    @Override
    public void draw(Canvas canvas)
    {
        // Calculate values
        Rect b = getBounds();
        float width = b.width();
        float height = b.height();

        int spaceFilled = (int)(getLevel() * width / 10000);
        this.rectFill = new RectF(0, 0, spaceFilled, height);
        this.rectEmpty = new RectF(spaceFilled, 0, width, height);

        int spaceBetween = (int)(width / 100);
        int widthPart = (int)(width / this.parts - (int)(0.9 * spaceBetween));
        int startX = widthPart;
        for (int i=0; i<this.parts - 1; i++)
        {
            this.separators.add( new RectF(startX, 0, startX + spaceBetween, height) );
            startX += spaceBetween + widthPart;
        }


        // Foreground
        this.paint.setColor(this.fillColor);
        canvas.drawRect(this.rectFill, this.paint);

        // Background
        this.paint.setColor(this.emptyColor);
        canvas.drawRect(this.rectEmpty, this.paint);

        // Separator
        this.paint.setColor(this.separatorColor);
        for (RectF separator : this.separators)
        {
            canvas.drawRect(separator, this.paint);
        }
    }

    @Override
    public void setAlpha(int alpha)
    {
    }

    @Override
    public void setColorFilter(ColorFilter cf)
    {
    }

    @Override
    public int getOpacity()
    {
        return PixelFormat.TRANSLUCENT;
    }
}

in XM Layout

<ProgressBar
        android:id="@+id/progress_bar_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"
        android:max="100"
        android:progress="10"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        />



ProgressBar progressBar= (ProgressBar)findViewById(R.id.progress_bar_test);
ProgressBarDrawable bgProgress= new ProgressBarDrawable(5);
progressBar.setProgressDrawable(bgProgress);
0
Riddhi Shah On

With the help of this and this answers, I could create my customized version of the segmented horizontal progress bar.

First, Create a class as follows.

public class SegmentedProgressDrawable extends Drawable {

    private int parts;

    private Paint paint;
    private int fillColor;
    private int emptyColor;
    private int cutOffWidth;
    private int separatorColor;

    public SegmentedProgressDrawable(int parts, int fillColor, int emptyColor, int separatorColor) {
        this.parts = parts;
        this.fillColor = fillColor;
        this.emptyColor = emptyColor;
        this.separatorColor = separatorColor;

        this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    @Override
    protected boolean onLevelChange(int level) {
        invalidateSelf();
        return true;
    }

    @Override
    public void draw(@NonNull Canvas canvas) {

        // Calculate values
        Rect bounds = getBounds();
        float actualWidth = bounds.width();
        float actualHeight = bounds.height();


        //width with dividers + segment width
        int fullBlockWidth = (int) (actualWidth / this.parts);
        //ToDo: to change the width of segment change this line
        int segmentWidth = (int) (fullBlockWidth * 0.2f);
//        int dividerWidth =fullBlockWidth-segmentWidth;

        cutOffWidth = (int) (getLevel() * actualWidth / 10000);

        //Draw separator as background
        RectF fullBox = new RectF(0, 0, actualWidth, actualHeight);
        this.paint.setColor(this.separatorColor);
        canvas.drawRect(fullBox, this.paint);

        //start drawing lines as segmented bars
        int startX = 0;
        for (int i = 0; i < this.parts; i++) {
            int endX = startX + segmentWidth;

            //in ideal condition this would be the rectangle
            RectF part = new RectF(startX, 0, endX, actualHeight);

            //if the segment is below level the paint color should be fill color
            if ((startX + segmentWidth) <= cutOffWidth) {

                this.paint.setColor(this.fillColor);    
                canvas.drawRect(part, this.paint);

            }
            //if the segment is started below the level but ends above the level than we need to create 2 different rectangle
            else if (startX < cutOffWidth) {

                RectF part1 = new RectF(startX, 0, cutOffWidth, actualHeight);
                this.paint.setColor(this.fillColor);
                canvas.drawRect(part1, this.paint);

                RectF part2 = new RectF(cutOffWidth, 0, startX + segmentWidth, actualHeight);
                this.paint.setColor(this.emptyColor);
                canvas.drawRect(part2, this.paint);

            }

            //if the segment is above level the paint color should be empty color
            else {
                this.paint.setColor(this.emptyColor);
                canvas.drawRect(part, this.paint);
            }

            //update the startX to start the new segment with the gap of divider and segment width
            startX += fullBlockWidth;
        }

    }


    @Override
    public void setAlpha(int alpha) {
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

And I, used it as follows:

horizontalProgressBar = findViewById(R.id.horizontal_progress_bar);
int fillColor = ContextCompat.getColor(getActivity(), R.color.primary);
int emptyColor = ContextCompat.getColor(getActivity(), R.color.color_redeem_badge_bg);
int separatorColor = ContextCompat.getColor(getActivity(), R.color.transparent);

SegmentedProgressDrawable progressDrawable = new SegmentedProgressDrawable(20, fillColor, emptyColor, separatorColor);
horizontalProgressBar.setProgressDrawable(progressDrawable);
horizontalProgressBar.setProgress(60);