0

I want to create a custom progress bar :

enter image description here

And i use a custom drawable :

<?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="10dip" />
            <gradient
                android:endColor="#3d3d3d"
                android:startColor="#3d3d3d" />
        </shape>
    </item>
    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <corners android:radius="10dip" />
                <gradient
                    android:angle="0"
                    android:endColor="#33bc90"
                    android:startColor="#4686ef" />
            </shape>
        </clip>
    </item>
</layer-list>

Now i getting next result :

enter image description here

And i see a most important problems :

  • in center my progress is not edged
  • i will can see end_color only in case progress = 100

How i can fix this in accordance to my requirenments?

Sergey Shustikov
  • 13,329
  • 9
  • 57
  • 110
  • I don't know how to fix your error but I used that question to do something similar thing, it's works for me, only I change your colours and try it http://stackoverflow.com/a/5745923/3626214 – Aspicas Jun 22 '15 at 12:45

1 Answers1

0

After such of investigation i make a decision to write my own implementation.

Code :

/**
 * Copyright 2015-present Sergey Shustikov.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pandarium.android;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;

/**
 * @author Sergey Shustikov (pandarium.shustkov@gmail.com).
 * <p/>
 * EdgedProgressBar is a view, like a progress bar, but with the addition of features such as:
 * <p/>
 * - added the possibility to round off the corners at the progress indicator
 * - added the possibility to create gradient from code or XML.
 * <p/>
 * Created in YouShido company at 2015.
 */
public class EdgedProgressBar extends View
{
    /**
     * Default values
     */
    public static final int DEFAULT_START_COLOR = Color.WHITE;
    public static final int DEFAULT_END_COLOR = Color.WHITE;
    public static final boolean DEFAULT_EDGE_CORNERS = false;
    public static final int DEFAULT_MAX_PROGRESS = 100;
    public static final int DEFAULT_CURRENT_PROGRESS = 10;
    public static final int DEFAULT_EDGE_VALUE = 10;
    public static final int DEFAULT_BACKGROUND_COLOR = Color.BLACK;

    /**
     * TypedArray for obtaining attributes
     */
    private TypedArray attributes;

    /**
     * The start color of progress gradient.
     *
     * @see #setStartColor(int)
     * @see #getStartColor()
     */
    private int startColor = DEFAULT_START_COLOR;

    /**
     * The end color of progress gradient.
     *
     * @see #setEndColor(int)
     * @see #getEndColor()
     */
    private int endColor = DEFAULT_END_COLOR;

    /**
     * The end color of progress gradient.
     *
     * @see #setRoundValue(int)
     * @see #getRoundValue()
     */
    private int roundValue = DEFAULT_EDGE_VALUE;

    /**
     * The flag indicates enabled edges or not.
     *
     * @see #setRoundEdgesEnabled(boolean)
     * @see #isRoundEdgesEnabled()
     */
    private boolean roundEdgesEnabled = DEFAULT_EDGE_CORNERS;

    /**
     * The max progress. Similar to maximum progress in ProgressBar
     *
     * @see #setMax(int)
     * @see #getMax()
     */
    private int maxProgress = DEFAULT_MAX_PROGRESS;

    /**
     * The current progress. Similar to current progress in ProgressBar
     *
     * @see #setProgress(int)
     * @see #getProgress()
     */
    private int currentProgress = DEFAULT_CURRENT_PROGRESS;

    /**
     * Background color of progressBar.
     *
     * @see #setBackgroundColor(int)
     * @see #getBackgroundColor()
     */
    private int backgroundColor = DEFAULT_BACKGROUND_COLOR;

    /**
     * Internal values
     */
    private int finalHeight;
    private int finalWidth;
    private Paint paint = new Paint();
    private LinearGradient gradient;
    private int lastGradientWidth, lastGradientHeight;
    private int lastL, lastT, lastR, lastB;
    private RectF drawingRect;

    public EdgedProgressBar(Context context)
    {
        super(context);
        init();
    }

    public EdgedProgressBar(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        readAttributes(context, attrs);
        init();
    }

    public EdgedProgressBar(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        readAttributes(context, attrs);
        init();
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public EdgedProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
        readAttributes(context, attrs);
        init();
    }

    private void init()
    {
        ViewTreeObserver vto = getViewTreeObserver();
        vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
        {
            public boolean onPreDraw()
            {
                getViewTreeObserver().removeOnPreDrawListener(this);
                finalHeight = getMeasuredHeight();
                finalWidth = getMeasuredWidth();

                return true;
            }
        });
    }

    private void readAttributes(Context context, AttributeSet attrs)
    {
        attributes = context.obtainStyledAttributes(attrs, R.styleable.EdgedProgressBar);
        try {
            startColor =
                    attributes.getColor(R.styleable.EdgedProgressBar_startColor, DEFAULT_START_COLOR);
            endColor =
                    attributes.getColor(R.styleable.EdgedProgressBar_endColor, DEFAULT_END_COLOR);
            roundEdgesEnabled =
                    attributes.getBoolean(R.styleable.EdgedProgressBar_roundEdgesEnabled, DEFAULT_EDGE_CORNERS);
            maxProgress =
                    attributes.getInteger(R.styleable.EdgedProgressBar_maxProgress, DEFAULT_MAX_PROGRESS);
            currentProgress =
                    attributes.getInteger(R.styleable.EdgedProgressBar_progress, DEFAULT_CURRENT_PROGRESS);
            roundValue =
                    attributes.getInteger(R.styleable.EdgedProgressBar_roundValue, DEFAULT_EDGE_VALUE);
            backgroundColor =
                    attributes.getColor(R.styleable.EdgedProgressBar_backgroundColor, DEFAULT_BACKGROUND_COLOR);
        } finally {
            attributes.recycle();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        finalHeight = getMeasuredHeight();
        finalWidth = getMeasuredWidth();
    }

    @Override
    protected synchronized void onDraw(Canvas canvas)
    {
        int width = finalWidth;
        int height = finalHeight;
        int progressDrawableWidth = (currentProgress * width) / maxProgress;

        paint.setAntiAlias(true);

        int round = roundEdgesEnabled ? roundValue : 0;

        paint.setColor(backgroundColor);

        int paddingTop = getPaddingTop();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();
        checkAndRecreate(paddingLeft, paddingTop, paddingRight, paddingBottom, progressDrawableWidth, height);

        //draw background
        canvas.drawRoundRect(drawingRect, round, round, paint);

        paint.setShader(gradient);
        //draw progress
        canvas.drawRoundRect(drawingRect, round, round, paint);
    }

    private void checkAndRecreate(int paddingLeft, int paddingTop, int paddingRight, int paddingBottom, int gradientWidth, int gradientHeight)
    {
        if (gradientWidth != lastGradientWidth || gradientHeight != lastGradientHeight) {
            gradient =
                    new LinearGradient(0, 0, gradientWidth, gradientHeight, startColor, endColor, Shader.TileMode.CLAMP);
            lastGradientWidth = gradientWidth;
            lastGradientHeight = gradientHeight;
        }

        if (lastL != paddingLeft || lastT != paddingTop || lastR != paddingRight || lastB != paddingBottom) {
            drawingRect =
                    new RectF(paddingLeft, paddingTop, gradientWidth - paddingRight, gradientHeight - paddingBottom);
            lastL = paddingLeft;
            lastT = paddingTop;
            lastR = paddingRight;
            lastB = paddingBottom;
        }
    }

    /**
     * @return current progress.
     */
    public int getProgress()
    {
        return currentProgress;
    }

    /**
     * Set current progress.
     */
    public void setProgress(int progress)
    {
        currentProgress = progress;
    }

    /**
     * @return maximum progress.
     */
    public int getMax()
    {
        return maxProgress;
    }

    /**
     * Set maximum progress.
     */
    public void setMax(int progress)
    {
        maxProgress = progress;
    }

    /**
     * @return round value of edges.
     */
    public int getRoundValue()
    {
        return roundValue;
    }

    /**
     * Set round value of progress bar.
     */
    public void setRoundValue(int roundValue)
    {
        this.roundValue = roundValue;
    }

    /**
     * @return edged corners or not.
     */
    public boolean isRoundEdgesEnabled()
    {
        return roundEdgesEnabled;
    }

    /**
     * True - edges in progressBar enabled.
     * False - edges disabled.
     */
    public void setRoundEdgesEnabled(boolean enabled)
    {
        roundEdgesEnabled = enabled;
    }

    /**
     * @return start color of gradient in progressBar.
     */
    public int getStartColor()
    {
        return startColor;
    }

    /**
     * Set start color of gradient in progressBar.
     */
    public void setStartColor(int color)
    {
        startColor = color;
    }

    /**
     * @return end color of gradient in progressBar.
     */
    public int getEndColor()
    {
        return endColor;
    }

    /**
     * Set end color of gradient in progressBar.
     */
    public void setEndColor(int color)
    {
        endColor = color;
    }

    /**
     * @return background color of progressBar.
     */
    public int getBackgroundColor()
    {
        return backgroundColor;
    }

    /**
     * Set background color of progressBar.
     */
    public void setBackgroundColor(int color)
    {
        backgroundColor = color;
    }
}

attr.xml

<declare-styleable name="EdgedProgressBar">
    <attr name="backgroundColor" format="color"/>
    <attr name="startColor" format="color"/>
    <attr name="endColor" format="color"/>
    <attr name="roundEdgesEnabled" format="boolean"/>
    <attr name="maxProgress" format="integer"/>
    <attr name="progress" format="integer"/>
    <attr name="roundValue" format="integer"/>
</declare-styleable>

in layout :

    <com.pandarium.android.EdgedProgressBar
        android:layout_width="wrap_content"
        android:layout_height="24dp"
        android:id="@+id/view"
        edged:backgroundColor="#3d3d3d"
        edged:startColor="#4686ef"
        edged:endColor="#33bc90"
        edged:roundEdgesEnabled="true"
        edged:roundValue="30"
        edged:maxProgress="100"
        edged:progress="50"
        android:padding="2dp"/>

Results

50% : enter image description here

75% : enter image description here

Note: When you copy-paste this code you need to import R.java file to class.

And don't forget to add

xmlns:edged="http://schemas.android.com/apk/res-auto"

into your layout.xml file.

Sergey Shustikov
  • 13,329
  • 9
  • 57
  • 110