Progress bar with divider

后端 未结 3 583
清歌不尽
清歌不尽 2020-11-27 17:58

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

相关标签:
3条回答
  • 2020-11-27 18:10
    /**
     * 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 讨论(0)
  • 2020-11-27 18:11

    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);
    
    0 讨论(0)
  • 2020-11-27 18:17

    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);
    
    0 讨论(0)
提交回复
热议问题