Search code examples
androidandroid-custom-viewseekbar

Android Music Seekbar match_parent


Basically, I cloned a material design widget library and wanted to use the Seekbar view. Even when using match_parent for the width, there was still some padding on the left and right. To combat this, I cloned the project from GitHub and went to the Slider.java class to try and figure out how to truly make this a full length media SeekBar.

I've included my current code, which basically shows a full length seekbar, but starts it a little to the right from the beginning (and consequently stops a little to the left from the end). Here it is mid-media-playback:

enter image description here

CODE

public class Slider extends CustomView {

    private int backgroundColor = Color.parseColor("#614E8D");
    private Ball   ball;
    private Bitmap bitmap;
    private int max = 100;
    private int min = 0;
    private NumberIndicator        numberIndicator;
    private OnValueChangedListener onValueChangedListener;
    private boolean placedBall          = false;
    private boolean press               = false;
    private boolean showNumberIndicator = false;
    private int     value               = 0;

    public Slider(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAttributes(attrs);
    }

    public int getMax() {
        return max;
    }

    public void setMax(int max) {
        this.max = max;
    }

    public int getMin() {
        return min;
    }

    public void setMin(int min) {
        this.min = min;
    }

    public OnValueChangedListener getOnValueChangedListener() {
        return onValueChangedListener;
    }

    public void setOnValueChangedListener(
            OnValueChangedListener onValueChangedListener) {
        this.onValueChangedListener = onValueChangedListener;
    }

    // GETERS & SETTERS

    public int getValue() {
        return value;
    }

    public void setValue(final int value) {
        if (placedBall == false)
            post(new Runnable() {

                @Override
                public void run() {
                    setValue(value);
                }
            });
        else {
            this.value = value;
            float division = (ball.xFin - ball.xIni) / max;
            ViewHelper.setX(ball,
                    value * division + getHeight() / 2 - ball.getWidth() / 2);
            ball.changeBackground();
        }

    }

    @Override
    public void invalidate() {
        ball.invalidate();
        super.invalidate();
    }

    public boolean isShowNumberIndicator() {
        return showNumberIndicator;
    }

    public void setShowNumberIndicator(boolean showNumberIndicator) {
        this.showNumberIndicator = showNumberIndicator;
        numberIndicator = (showNumberIndicator) ? new NumberIndicator(
                getContext()) : null;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        isLastTouch = true;
        if (isEnabled()) {
            if (event.getAction() == MotionEvent.ACTION_DOWN
                    || event.getAction() == MotionEvent.ACTION_MOVE) {
                if (numberIndicator != null
                        && numberIndicator.isShowing() == false)
                    numberIndicator.show();
                if ((event.getX() <= getWidth() && event.getX() >= 0)) {
                    press = true;
                    // calculate value
                    int newValue = 0;
                    float division = (ball.xFin - ball.xIni) / (max - min);
                    if (event.getX() > ball.xFin) {
                        newValue = max;
                    } else if (event.getX() < ball.xIni) {
                        newValue = min;
                    } else {
                        newValue = min + (int) ((event.getX() - ball.xIni) / division);
                    }
                    if (value != newValue) {
                        value = newValue;
                        if (onValueChangedListener != null)
                            onValueChangedListener.onValueChanged(newValue);
                    }
                    // move ball indicator
                    float x = event.getX();
                    x = (x < ball.xIni) ? ball.xIni : x;
                    x = (x > ball.xFin) ? ball.xFin : x;
                    ViewHelper.setX(ball, x);
                    ball.changeBackground();

                    // If slider has number indicator
                    if (numberIndicator != null) {
                        // move number indicator
                        numberIndicator.indicator.x = x;
                        numberIndicator.indicator.finalY = Utils
                                .getRelativeTop(this) - getHeight() / 2;
                        numberIndicator.indicator.finalSize = getHeight() / 2;
                        numberIndicator.numberIndicator.setText("");
                    }

                } else {
                    press = false;
                    isLastTouch = false;
                    if (numberIndicator != null)
                        numberIndicator.dismiss();

                }

            } else if (event.getAction() == MotionEvent.ACTION_UP ||
                    event.getAction() == MotionEvent.ACTION_CANCEL) {
                if (numberIndicator != null)
                    numberIndicator.dismiss();
                isLastTouch = false;
                press = false;
            }
        }
        return true;
    }

    @Override
    public void setBackgroundColor(int color) {
        backgroundColor = color;
        if (isEnabled())
            beforeBackground = backgroundColor;
    }

    /**
     * Make a dark color to press effect
     *
     * @return
     */
    protected int makePressColor() {
        int r = (this.backgroundColor >> 16) & 0xFF;
        int g = (this.backgroundColor >> 8) & 0xFF;
        int b = (this.backgroundColor >> 0) & 0xFF;
        r = (r - 30 < 0) ? 0 : r - 30;
        g = (g - 30 < 0) ? 0 : g - 30;
        b = (b - 30 < 0) ? 0 : b - 30;
        return Color.argb(70, r, g, b);
    }

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

        if (!placedBall) {
            placeBall();
        }

        Paint paint = new Paint();

        if (value == min) {
            // Crop line to transparent effect
            // before song loaded, basically. Need to make this similar to value != min

            if (bitmap == null) {

                bitmap = Bitmap.createBitmap(canvas.getWidth(),
                        canvas.getHeight(), Bitmap.Config.ARGB_8888);
            }
            Canvas temp = new Canvas(bitmap);
            paint.setColor(Color.parseColor("#54457A")); //purple
            paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
//            temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
//                    - getHeight() / 2, getHeight() / 2, paint);
            temp.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, paint);
            Paint transparentPaint = new Paint();
            transparentPaint.setColor(getResources().getColor(
                    android.R.color.transparent));
            transparentPaint.setXfermode(new PorterDuffXfermode(
                    PorterDuff.Mode.CLEAR));
            temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
                    ViewHelper.getY(ball) + ball.getHeight() / 2,
                    ball.getWidth() / 2, transparentPaint);

            canvas.drawBitmap(bitmap, 0, 0, new Paint());
        } else {
            /*TRACK*/
            paint.setColor(Color.parseColor("#5A5A5C")); //track
            paint.setStrokeWidth(Utils.dpToPx(10, getResources()));
            canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint); //track length
            paint.setColor(backgroundColor);
            /*END TRACK*/
            float division = (ball.xFin - ball.xIni) / (max - min);
            int value = this.value - min;

            //DO NOT TOUCH -- Progress coloring
            canvas.drawLine(getHeight() / 2, getHeight() / 2, value * division
                    + getHeight() / 2, getHeight() / 2, paint);
        }

        if (press && !showNumberIndicator) {
            paint.setColor(backgroundColor);
            paint.setAntiAlias(true);
            canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
                    getHeight() / 2, getHeight() / 3, paint);
        }
        invalidate();
    }

    // Set atributtes of XML to View
    protected void setAttributes(AttributeSet attrs) {

        setBackgroundResource(R.drawable.background_transparent);

        // Set size of view
        setMinimumHeight(Utils.dpToPx(48, getResources()));
        setMinimumWidth(Utils.dpToPx(80, getResources()));

        // Set background Color
        // Color by resource
        int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
                "background", -1);
        if (bacgroundColor != -1) {
            setBackgroundColor(getResources().getColor(bacgroundColor));
        } else {
            // Color by hexadecimal
            int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
            if (background != -1)
                setBackgroundColor(background);
        }

        showNumberIndicator = attrs.getAttributeBooleanValue(MATERIALDESIGNXML,
                "showNumberIndicator", false);
        min = attrs.getAttributeIntValue(MATERIALDESIGNXML, "min", 0);
        max = attrs.getAttributeIntValue(MATERIALDESIGNXML, "max", 0);
        value = attrs.getAttributeIntValue(MATERIALDESIGNXML, "value", min);

        ball = new Ball(getContext());
        RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
                getResources()), Utils.dpToPx(20, getResources()));
        params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
        ball.setLayoutParams(params);
        addView(ball);

        // Set if slider content number indicator
        // TODO
        if (showNumberIndicator) {
            numberIndicator = new NumberIndicator(getContext());
        }

    }

    private void placeBall() {
        ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
        ViewHelper.setX(ball, ball.getWidth());
        ball.xIni = ViewHelper.getX(ball);
        ball.xFin = getWidth() - ball.getWidth();// - getHeight() / 2 - ball.getWidth() / 2;
        ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
        placedBall = true;
    }

    // Event when slider change value
    public interface OnValueChangedListener {
        public void onValueChanged(int value);
    }

    class Ball extends View {

        float xIni, xFin, xCen;

        public Ball(Context context) {
            super(context);
            setBackgroundResource(R.drawable.background_switch_ball_uncheck);
        }

        public void changeBackground() {
            if (value != min) {
                setBackgroundResource(R.drawable.background_checkbox);
                LayerDrawable layer = (LayerDrawable) getBackground();
                GradientDrawable shape = (GradientDrawable) layer
                        .findDrawableByLayerId(R.id.shape_bacground);
                shape.setColor(Color.parseColor("#D5C46A")); //yellow ball
            } else {
                setBackgroundResource(R.drawable.background_switch_ball_uncheck);
            }
        }

    }

    // Slider Number Indicator

    class Indicator extends RelativeLayout {

        boolean animate               = true;
        // Final size after animation
        float   finalSize             = 0;
        // Final y position after animation
        float   finalY                = 0;
        boolean numberIndicatorResize = false;
        // Size of number indicator
        float   size                  = 0;
        // Position of number indicator
        float   x                     = 0;
        float   y                     = 0;

        public Indicator(Context context) {
            super(context);
            setBackgroundColor(getResources().getColor(
                    android.R.color.transparent));
        }

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

            if (numberIndicatorResize == false) {
                LayoutParams params = (LayoutParams) numberIndicator.numberIndicator
                        .getLayoutParams();
                params.height = (int) finalSize * 2;
                params.width = (int) finalSize * 2;
                numberIndicator.numberIndicator.setLayoutParams(params);
            }

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(backgroundColor);
            if (animate) {
                if (y == 0)
                    y = finalY + finalSize * 2;
                y -= Utils.dpToPx(6, getResources());
                size += Utils.dpToPx(2, getResources());
            }
            canvas.drawCircle(
                    ViewHelper.getX(ball)
                            + Utils.getRelativeLeft((View) ball.getParent())
                            + ball.getWidth() / 2, y, size, paint);
            if (animate && size >= finalSize)
                animate = false;
            if (animate == false) {
                ViewHelper
                        .setX(numberIndicator.numberIndicator,
                                (ViewHelper.getX(ball)
                                        + Utils.getRelativeLeft((View) ball
                                        .getParent()) + ball.getWidth() / 2)
                                        - size);
                ViewHelper.setY(numberIndicator.numberIndicator, y - size);
                numberIndicator.numberIndicator.setText(value + "");
            }

            invalidate();
        }

    }

    class NumberIndicator extends Dialog {

        Indicator indicator;
        TextView  numberIndicator;

        public NumberIndicator(Context context) {
            super(context, android.R.style.Theme_Translucent);
        }

        @Override
        public void dismiss() {
            super.dismiss();
            indicator.y = 0;
            indicator.size = 0;
            indicator.animate = true;
        }

        @Override
        public void onBackPressed() {
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.number_indicator_spinner);
            setCanceledOnTouchOutside(false);

            RelativeLayout content = (RelativeLayout) this
                    .findViewById(R.id.number_indicator_spinner_content);
            indicator = new Indicator(this.getContext());
            content.addView(indicator);

            numberIndicator = new TextView(getContext());
            numberIndicator.setTextColor(Color.WHITE);
            numberIndicator.setGravity(Gravity.CENTER);
            content.addView(numberIndicator);

            indicator.setLayoutParams(new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.FILL_PARENT,
                    RelativeLayout.LayoutParams.FILL_PARENT));
        }

    }

}

Any help on how to get the circle to start at the very left and end at the very right would be greatly appreciated.


Solution

  • Playing around some more, I found that the original developer of this Slider.java class used a lot of getHeight() / 2 which caused some padding that I didn't want. I've included the edited class. Credit for original class to navasmdc, the creator of Material Design Library.. Feel free to use this class if you need a full sized SeekBar

    Slider.java

    package com.gc.materialdesign.views;
    
    import android.app.Dialog;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.drawable.GradientDrawable;
    import android.graphics.drawable.LayerDrawable;
    import android.os.Bundle;
    import android.util.AttributeSet;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.Window;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    import com.gc.materialdesign.R;
    import com.gc.materialdesign.utils.Utils;
    import com.nineoldandroids.view.ViewHelper;
    
    public class Slider extends CustomView {
    
        private int backgroundColor = Color.parseColor("#614E8D");
        private Ball   ball;
        private Bitmap bitmap;
        private int max = 100;
        private int min = 0;
        private NumberIndicator        numberIndicator;
        private OnValueChangedListener onValueChangedListener;
        private boolean placedBall          = false;
        private boolean press               = false;
        private boolean showNumberIndicator = false;
        private int     value               = 0;
    
        public Slider(Context context, AttributeSet attrs) {
            super(context, attrs);
            setAttributes(attrs);
        }
    
        public int getMax() {
            return max;
        }
    
        public void setMax(int max) {
            this.max = max;
        }
    
        public int getMin() {
            return min;
        }
    
        public void setMin(int min) {
            this.min = min;
        }
    
        public OnValueChangedListener getOnValueChangedListener() {
            return onValueChangedListener;
        }
    
        public void setOnValueChangedListener(
                OnValueChangedListener onValueChangedListener) {
            this.onValueChangedListener = onValueChangedListener;
        }
    
        // GETERS & SETTERS
    
        public int getValue() {
            return value;
        }
    
        public void setValue(final int value) {
            if (placedBall == false)
                post(new Runnable() {
    
                    @Override
                    public void run() {
                        setValue(value);
                    }
                });
            else {
                this.value = value;
                float division = (ball.xFin - ball.xIni) / max;
                ViewHelper.setX(ball,
                        value* division);//value * division - ball.getWidth() / 2);
                ball.changeBackground();
            }
    
        }
    
        @Override
        public void invalidate() {
            ball.invalidate();
            super.invalidate();
        }
    
        public boolean isShowNumberIndicator() {
            return showNumberIndicator;
        }
    
        public void setShowNumberIndicator(boolean showNumberIndicator) {
            this.showNumberIndicator = showNumberIndicator;
            numberIndicator = (showNumberIndicator) ? new NumberIndicator(
                    getContext()) : null;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            isLastTouch = true;
            if (isEnabled()) {
                if (event.getAction() == MotionEvent.ACTION_DOWN
                        || event.getAction() == MotionEvent.ACTION_MOVE) {
                    if (numberIndicator != null
                            && numberIndicator.isShowing() == false)
                        numberIndicator.show();
                    if ((event.getX() <= getWidth() && event.getX() >= 0)) {
                        press = true;
                        // calculate value
                        int newValue = 0;
                        float division = (ball.xFin - ball.xIni) / (max - min);
                        if (event.getX() > ball.xFin) {
                            newValue = max;
                        } else if (event.getX() < ball.xIni) {
                            newValue = min;
                        } else {
                            newValue = min + (int) ((event.getX() - ball.xIni) / division);
                        }
                        if (value != newValue) {
                            value = newValue;
                            if (onValueChangedListener != null)
                                onValueChangedListener.onValueChanged(newValue);
                        }
                        // move ball indicator
                        float x = event.getX();
                        x = (x < ball.xIni) ? ball.xIni : x;
                        x = (x > ball.xFin) ? ball.xFin : x;
                        ViewHelper.setX(ball, x);
                        ball.changeBackground();
    
                        // If slider has number indicator
                        if (numberIndicator != null) {
                            // move number indicator
                            numberIndicator.indicator.x = x;
                            numberIndicator.indicator.finalY = Utils
                                    .getRelativeTop(this) - getHeight() / 2;
                            numberIndicator.indicator.finalSize = getHeight() / 2;
                            numberIndicator.numberIndicator.setText("");
                        }
    
                    } else {
                        press = false;
                        isLastTouch = false;
                        if (numberIndicator != null)
                            numberIndicator.dismiss();
    
                    }
    
                } else if (event.getAction() == MotionEvent.ACTION_UP ||
                        event.getAction() == MotionEvent.ACTION_CANCEL) {
                    if (numberIndicator != null)
                        numberIndicator.dismiss();
                    isLastTouch = false;
                    press = false;
                }
            }
            return true;
        }
    
        @Override
        public void setBackgroundColor(int color) {
            backgroundColor = color;
            if (isEnabled())
                beforeBackground = backgroundColor;
        }
    
        /**
         * Make a dark color to press effect
         *
         * @return
         */
        protected int makePressColor() {
            int r = (this.backgroundColor >> 16) & 0xFF;
            int g = (this.backgroundColor >> 8) & 0xFF;
            int b = (this.backgroundColor >> 0) & 0xFF;
            r = (r - 30 < 0) ? 0 : r - 30;
            g = (g - 30 < 0) ? 0 : g - 30;
            b = (b - 30 < 0) ? 0 : b - 30;
            return Color.argb(70, r, g, b);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            if (!placedBall) {
                placeBall();
            }
    
            Paint paint = new Paint();
    
            if (value == min) {
                // Crop line to transparent effect
                // before song loaded, basically. Need to make this similar to value != min
    
                if (bitmap == null) {
    
                    bitmap = Bitmap.createBitmap(canvas.getWidth(),
                            canvas.getHeight(), Bitmap.Config.ARGB_8888);
                }
                Canvas temp = new Canvas(bitmap);
                paint.setColor(Color.parseColor("#54457A")); //purple
                paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
    //            temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
    //                    - getHeight() / 2, getHeight() / 2, paint);
                temp.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, paint);
                Paint transparentPaint = new Paint();
                transparentPaint.setColor(getResources().getColor(
                        android.R.color.transparent));
                transparentPaint.setXfermode(new PorterDuffXfermode(
                        PorterDuff.Mode.CLEAR));
                temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
                        ViewHelper.getY(ball) + ball.getHeight() / 2,
                        ball.getWidth() / 2, transparentPaint);
    
                canvas.drawBitmap(bitmap, 0, 0, new Paint());
            } else {
                /*TRACK*/
                paint.setColor(Color.parseColor("#5A5A5C")); //track
                paint.setStrokeWidth(Utils.dpToPx(10, getResources()));
                canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint); //track length
                paint.setColor(backgroundColor);
                /*END TRACK*/
                float division = (ball.xFin - ball.xIni) / (max - min);
                int value = this.value - min;
    
                //DO NOT TOUCH -- Progress coloring
                canvas.drawLine(0, getHeight() / 2, value * division
                        +ball.getWidth(), getHeight() / 2, paint);
            }
    
            if (press && !showNumberIndicator) {
                paint.setColor(backgroundColor);
                paint.setAntiAlias(true);
                canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
                        getHeight() / 2, getHeight() / 3, paint);
            }
            invalidate();
        }
    
        // Set atributtes of XML to View
        protected void setAttributes(AttributeSet attrs) {
    
            setBackgroundResource(R.drawable.background_transparent);
    
            // Set size of view
            setMinimumHeight(Utils.dpToPx(48, getResources()));
            setMinimumWidth(Utils.dpToPx(80, getResources()));
    
            // Set background Color
            // Color by resource
            int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
                    "background", -1);
            if (bacgroundColor != -1) {
                setBackgroundColor(getResources().getColor(bacgroundColor));
            } else {
                // Color by hexadecimal
                int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
                if (background != -1)
                    setBackgroundColor(background);
            }
    
            showNumberIndicator = attrs.getAttributeBooleanValue(MATERIALDESIGNXML,
                    "showNumberIndicator", false);
            min = attrs.getAttributeIntValue(MATERIALDESIGNXML, "min", 0);
            max = attrs.getAttributeIntValue(MATERIALDESIGNXML, "max", 0);
            value = attrs.getAttributeIntValue(MATERIALDESIGNXML, "value", min);
    
            ball = new Ball(getContext());
            RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
                    getResources()), Utils.dpToPx(20, getResources()));
            params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
            ball.setLayoutParams(params);
            addView(ball);
    
            // Set if slider content number indicator
            // TODO
            if (showNumberIndicator) {
                numberIndicator = new NumberIndicator(getContext());
            }
    
        }
    
        private void placeBall() {
    //        ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
    //        ViewHelper.setX(ball, 0);
            ViewHelper.setX(ball, ball.getWidth());
            ball.xIni = 0;//ViewHelper.getX(ball);
            ball.xFin = getWidth() - ball.getWidth();// - getHeight() / 2 - ball.getWidth() / 2;
            ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
            placedBall = true;
        }
    
        // Event when slider change value
        public interface OnValueChangedListener {
            public void onValueChanged(int value);
        }
    
        class Ball extends View {
    
            float xIni, xFin, xCen;
    
            public Ball(Context context) {
                super(context);
                setBackgroundResource(R.drawable.background_switch_ball_uncheck);
            }
    
            public void changeBackground() {
                if (value != min) {
                    setBackgroundResource(R.drawable.background_checkbox);
                    LayerDrawable layer = (LayerDrawable) getBackground();
                    GradientDrawable shape = (GradientDrawable) layer
                            .findDrawableByLayerId(R.id.shape_bacground);
                    shape.setColor(Color.parseColor("#D5C46A")); //yellow ball
                } else {
                    setBackgroundResource(R.drawable.background_switch_ball_uncheck);
                }
            }
    
        }
    
        // Slider Number Indicator
    
        class Indicator extends RelativeLayout {
    
            boolean animate               = true;
            // Final size after animation
            float   finalSize             = 0;
            // Final y position after animation
            float   finalY                = 0;
            boolean numberIndicatorResize = false;
            // Size of number indicator
            float   size                  = 0;
            // Position of number indicator
            float   x                     = 0;
            float   y                     = 0;
    
            public Indicator(Context context) {
                super(context);
                setBackgroundColor(getResources().getColor(
                        android.R.color.transparent));
            }
    
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
    
                if (numberIndicatorResize == false) {
                    LayoutParams params = (LayoutParams) numberIndicator.numberIndicator
                            .getLayoutParams();
                    params.height = (int) finalSize * 2;
                    params.width = (int) finalSize * 2;
                    numberIndicator.numberIndicator.setLayoutParams(params);
                }
    
                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setColor(backgroundColor);
                if (animate) {
                    if (y == 0)
                        y = finalY + finalSize * 2;
                    y -= Utils.dpToPx(6, getResources());
                    size += Utils.dpToPx(2, getResources());
                }
                canvas.drawCircle(
                        ViewHelper.getX(ball)
                                + Utils.getRelativeLeft((View) ball.getParent())
                                + ball.getWidth() / 2, y, size, paint);
                if (animate && size >= finalSize)
                    animate = false;
                if (animate == false) {
                    ViewHelper
                            .setX(numberIndicator.numberIndicator,
                                    (ViewHelper.getX(ball)
                                            + Utils.getRelativeLeft((View) ball
                                            .getParent()) + ball.getWidth() / 2)
                                            - size);
                    ViewHelper.setY(numberIndicator.numberIndicator, y - size);
                    numberIndicator.numberIndicator.setText(value + "");
                }
    
                invalidate();
            }
    
        }
    
        class NumberIndicator extends Dialog {
    
            Indicator indicator;
            TextView  numberIndicator;
    
            public NumberIndicator(Context context) {
                super(context, android.R.style.Theme_Translucent);
            }
    
            @Override
            public void dismiss() {
                super.dismiss();
                indicator.y = 0;
                indicator.size = 0;
                indicator.animate = true;
            }
    
            @Override
            public void onBackPressed() {
            }
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                requestWindowFeature(Window.FEATURE_NO_TITLE);
                super.onCreate(savedInstanceState);
                setContentView(R.layout.number_indicator_spinner);
                setCanceledOnTouchOutside(false);
    
                RelativeLayout content = (RelativeLayout) this
                        .findViewById(R.id.number_indicator_spinner_content);
                indicator = new Indicator(this.getContext());
                content.addView(indicator);
    
                numberIndicator = new TextView(getContext());
                numberIndicator.setTextColor(Color.WHITE);
                numberIndicator.setGravity(Gravity.CENTER);
                content.addView(numberIndicator);
    
                indicator.setLayoutParams(new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.FILL_PARENT,
                        RelativeLayout.LayoutParams.FILL_PARENT));
            }
    
        }
    
    }