博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CircularSeekBar
阅读量:5942 次
发布时间:2019-06-19

本文共 14981 字,大约阅读时间需要 49 分钟。

/** * @author Raghav Sood * @version 1 * @date 26 January, 2013 */package com.appaholics.circularseekbar;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;/** * The Class CircularSeekBar. */public class CircularSeekBar extends View {    /** The context */    private Context mContext;    /** The listener to listen for changes */    private OnSeekChangeListener mListener;    /** The color of the progress ring */    private Paint circleColor;    /** the color of the inside circle. Acts as background color */    private Paint innerColor;    /** The progress circle ring background */    private Paint circleRing;    /** The angle of progress */    private int angle = 0;    /** The start angle (12 O'clock */    private int startAngle = 270;    /** The width of the progress ring */    private int barWidth = 5;    /** The width of the view */    private int width;    /** The height of the view */    private int height;    /** The maximum progress amount */    private int maxProgress = 100;    /** The current progress */    private int progress;    /** The progress percent */    private int progressPercent;    /** The radius of the inner circle */    private float innerRadius;    /** The radius of the outer circle */    private float outerRadius;    /** The circle's center X coordinate */    private float cx;    /** The circle's center Y coordinate */    private float cy;    /** The left bound for the circle RectF */    private float left;    /** The right bound for the circle RectF */    private float right;    /** The top bound for the circle RectF */    private float top;    /** The bottom bound for the circle RectF */    private float bottom;    /** The X coordinate for the top left corner of the marking drawable */    private float dx;    /** The Y coordinate for the top left corner of the marking drawable */    private float dy;    /** The X coordinate for 12 O'Clock */    private float startPointX;    /** The Y coordinate for 12 O'Clock */    private float startPointY;    /**     * The X coordinate for the current position of the marker, pre adjustment     * to center     */    private float markPointX;    /**     * The Y coordinate for the current position of the marker, pre adjustment     * to center     */    private float markPointY;    /**     * The adjustment factor. This adds an adjustment of the specified size to     * both sides of the progress bar, allowing touch events to be processed     * more user friendly (yes, I know that's not a word)     */    private float adjustmentFactor = 100;    /** The progress mark when the view isn't being progress modified */    private Bitmap progressMark;    /** The progress mark when the view is being progress modified. */    private Bitmap progressMarkPressed;    /** The flag to see if view is pressed */    private boolean IS_PRESSED = false;    /**     * The flag to see if the setProgress() method was called from our own     * View's setAngle() method, or externally by a user.     */    private boolean CALLED_FROM_ANGLE = false;    private boolean SHOW_SEEKBAR = true;    /** The rectangle containing our circles and arcs. */    private RectF rect = new RectF();    {        mListener = new OnSeekChangeListener() {            @Override            public void onProgressChange(CircularSeekBar view, int newProgress) {            }        };        circleColor = new Paint();        innerColor = new Paint();        circleRing = new Paint();        circleColor.setColor(Color.parseColor("#ff33b5e5")); // Set default        // progress        // color to holo        // blue.        innerColor.setColor(Color.BLACK); // Set default background color to        // black        circleRing.setColor(Color.GRAY);// Set default background color to Gray        circleColor.setAntiAlias(true);        innerColor.setAntiAlias(true);        circleRing.setAntiAlias(true);        circleColor.setStrokeWidth(5);        innerColor.setStrokeWidth(5);        circleRing.setStrokeWidth(5);        circleColor.setStyle(Paint.Style.FILL);    }    /**     * Instantiates a new circular seek bar.     *      * @param context     *            the context     * @param attrs     *            the attrs     * @param defStyle     *            the def style     */    public CircularSeekBar(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        mContext = context;        initDrawable();    }    /**     * Instantiates a new circular seek bar.     *      * @param context     *            the context     * @param attrs     *            the attrs     */    public CircularSeekBar(Context context, AttributeSet attrs) {        super(context, attrs);        mContext = context;        initDrawable();    }    /**     * Instantiates a new circular seek bar.     *      * @param context     *            the context     */    public CircularSeekBar(Context context) {        super(context);        mContext = context;        initDrawable();    }    /**     * Inits the drawable.     */    public void initDrawable() {        progressMark = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.scrubber_control_normal_holo);        progressMarkPressed = BitmapFactory.decodeResource(mContext.getResources(),                R.drawable.scrubber_control_pressed_holo);    }    /*     * (non-Javadoc)     *      * @see android.view.View#onMeasure(int, int)     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        width = getWidth(); // Get View Width        height = getHeight();// Get View Height        int size = (width > height) ? height : width; // Choose the smaller        // between width and        // height to make a        // square        cx = width / 2; // Center X for circle        cy = height / 2; // Center Y for circle        outerRadius = size / 2; // Radius of the outer circle        innerRadius = outerRadius - barWidth; // Radius of the inner circle        left = cx - outerRadius; // Calculate left bound of our rect        right = cx + outerRadius;// Calculate right bound of our rect        top = cy - outerRadius;// Calculate top bound of our rect        bottom = cy + outerRadius;// Calculate bottom bound of our rect        startPointX = cx; // 12 O'clock X coordinate        startPointY = cy - outerRadius;// 12 O'clock Y coordinate        markPointX = startPointX;// Initial locatino of the marker X coordinate        markPointY = startPointY;// Initial locatino of the marker Y coordinate        rect.set(left, top, right, bottom); // assign size to rect    }    /*     * (non-Javadoc)     *      * @see android.view.View#onDraw(android.graphics.Canvas)     */    @Override    protected void onDraw(Canvas canvas) {        canvas.drawCircle(cx, cy, outerRadius, circleRing);        canvas.drawArc(rect, startAngle, angle, true, circleColor);        canvas.drawCircle(cx, cy, innerRadius, innerColor);        if(SHOW_SEEKBAR){            dx = getXFromAngle();            dy = getYFromAngle();            drawMarkerAtProgress(canvas);        }        super.onDraw(canvas);    }    /**     * Draw marker at the current progress point onto the given canvas.     *      * @param canvas     *            the canvas     */    public void drawMarkerAtProgress(Canvas canvas) {        if (IS_PRESSED) {            canvas.drawBitmap(progressMarkPressed, dx, dy, null);        } else {            canvas.drawBitmap(progressMark, dx, dy, null);        }    }    /**     * Gets the X coordinate of the arc's end arm's point of intersection with     * the circle     *      * @return the X coordinate     */    public float getXFromAngle() {        int size1 = progressMark.getWidth();        int size2 = progressMarkPressed.getWidth();        int adjust = (size1 > size2) ? size1 : size2;        float x = markPointX - (adjust / 2);        return x;    }    /**     * Gets the Y coordinate of the arc's end arm's point of intersection with     * the circle     *      * @return the Y coordinate     */    public float getYFromAngle() {        int size1 = progressMark.getHeight();        int size2 = progressMarkPressed.getHeight();        int adjust = (size1 > size2) ? size1 : size2;        float y = markPointY - (adjust / 2);        return y;    }    /**     * Get the angle.     *      * @return the angle     */    public int getAngle() {        return angle;    }    /**     * Set the angle.     *      * @param angle     *            the new angle     */    public void setAngle(int angle) {        this.angle = angle;        float donePercent = (((float) this.angle) / 360) * 100;        float progress = (donePercent / 100) * getMaxProgress();        setProgressPercent(Math.round(donePercent));        CALLED_FROM_ANGLE = true;        setProgress(Math.round(progress));    }    /**     * Sets the seek bar change listener.     *      * @param listener     *            the new seek bar change listener     */    public void setSeekBarChangeListener(OnSeekChangeListener listener) {        mListener = listener;    }    /**     * Gets the seek bar change listener.     *      * @return the seek bar change listener     */    public OnSeekChangeListener getSeekBarChangeListener() {        return mListener;    }    /**     * Gets the bar width.     *      * @return the bar width     */    public int getBarWidth() {        return barWidth;    }    /**     * Sets the bar width.     *      * @param barWidth     *            the new bar width     */    public void setBarWidth(int barWidth) {        this.barWidth = barWidth;    }    /**     * The listener interface for receiving onSeekChange events. The class that     * is interested in processing a onSeekChange event implements this     * interface, and the object created with that class is registered with a     * component using the component's     * setSeekBarChangeListener(OnSeekChangeListener) method. When     * the onSeekChange event occurs, that object's appropriate     * method is invoked.     *      * @see OnSeekChangeEvent     */    public interface OnSeekChangeListener {        /**         * On progress change.         *          * @param view         *            the view         * @param newProgress         *            the new progress         */        public void onProgressChange(CircularSeekBar view, int newProgress);    }    /**     * Gets the max progress.     *      * @return the max progress     */    public int getMaxProgress() {        return maxProgress;    }    /**     * Sets the max progress.     *      * @param maxProgress     *            the new max progress     */    public void setMaxProgress(int maxProgress) {        this.maxProgress = maxProgress;    }    /**     * Gets the progress.     *      * @return the progress     */    public int getProgress() {        return progress;    }    /**     * Sets the progress.     *      * @param progress     *            the new progress     */    public void setProgress(int progress) {        if (this.progress != progress) {            this.progress = progress;            if (!CALLED_FROM_ANGLE) {                int newPercent = (this.progress * 100) / this.maxProgress;                int newAngle = (newPercent * 360) / 100 ;                this.setAngle(newAngle);                this.setProgressPercent(newPercent);            }            mListener.onProgressChange(this, this.getProgress());            CALLED_FROM_ANGLE = false;        }    }    /**     * Gets the progress percent.     *      * @return the progress percent     */    public int getProgressPercent() {        return progressPercent;    }    /**     * Sets the progress percent.     *      * @param progressPercent     *            the new progress percent     */    public void setProgressPercent(int progressPercent) {        this.progressPercent = progressPercent;    }    /**     * Sets the ring background color.     *      * @param color     *            the new ring background color     */    public void setRingBackgroundColor(int color) {        circleRing.setColor(color);    }    /**     * Sets the back ground color.     *      * @param color     *            the new back ground color     */    public void setBackGroundColor(int color) {        innerColor.setColor(color);    }    /**     * Sets the progress color.     *      * @param color     *            the new progress color     */    public void setProgressColor(int color) {        circleColor.setColor(color);    }    /*     * (non-Javadoc)     *      * @see android.view.View#onTouchEvent(android.view.MotionEvent)     */    @Override    public boolean onTouchEvent(MotionEvent event) {        float x = event.getX();        float y = event.getY();        boolean up = false;        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            moved(x, y, up);            break;        case MotionEvent.ACTION_MOVE:            moved(x, y, up);            break;        case MotionEvent.ACTION_UP:            up = true;            moved(x, y, up);            break;        }        return true;    }    /**     * Moved.     *      * @param x     *            the x     * @param y     *            the y     * @param up     *            the up     */    private void moved(float x, float y, boolean up) {        float distance = (float) Math.sqrt(Math.pow((x - cx), 2) + Math.pow((y - cy), 2));        if (distance < outerRadius + adjustmentFactor && distance > innerRadius - adjustmentFactor && !up) {            IS_PRESSED = true;            markPointX = (float) (cx + outerRadius * Math.cos(Math.atan2(x - cx, cy - y) - (Math.PI /2)));            markPointY = (float) (cy + outerRadius * Math.sin(Math.atan2(x - cx, cy - y) - (Math.PI /2)));            float degrees = (float) ((float) ((Math.toDegrees(Math.atan2(x - cx, cy - y)) + 360.0)) % 360.0);            // and to make it count 0-360            if (degrees < 0) {                degrees += 2 * Math.PI;            }            setAngle(Math.round(degrees));            invalidate();        } else {            IS_PRESSED = false;            invalidate();        }    }    /**     * Gets the adjustment factor.     *      * @return the adjustment factor     */    public float getAdjustmentFactor() {        return adjustmentFactor;    }    /**     * Sets the adjustment factor.     *      * @param adjustmentFactor     *            the new adjustment factor     */    public void setAdjustmentFactor(float adjustmentFactor) {        this.adjustmentFactor = adjustmentFactor;    }    /**     * To display seekbar     */    public void ShowSeekBar() {        SHOW_SEEKBAR = true;    }    /**     * To hide seekbar     */    public void hideSeekBar() {        SHOW_SEEKBAR = false;    }}

 

转载地址:http://jnmtx.baihongyu.com/

你可能感兴趣的文章
开发安全的 API 所需要核对的清单
查看>>
Mycat源码中的单例模式
查看>>
WPF Dispatcher介绍
查看>>
fiddler展示serverIP方法
查看>>
C语言中的随意跳转
查看>>
006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载、Route初始化加载...
查看>>
WPF中如何将ListViewItem双击事件绑定到Command
查看>>
《聚散两依依》
查看>>
小tips:你不知道的 npm init
查看>>
Mac笔记本中是用Idea开发工具在Java项目中调用python脚本遇到的环境变量问题解决...
查看>>
Jmeter也能IP欺骗!
查看>>
Rust 阴阳谜题,及纯基于代码的分析与化简
查看>>
ASP.NET Core的身份认证框架IdentityServer4(4)- 支持的规范
查看>>
(原創) array可以使用reference方式傳進function嗎? (C/C++)
查看>>
170多个Ionic Framework学习资源(转载)
查看>>
Azure:不能把同一个certificate同时用于Azure Management和RDP
查看>>
Directx11教程(15) D3D11管线(4)
查看>>
Microsoft Excel软件打开文件出现文件的格式与文件扩展名指定格式不一致?
查看>>
ios ble 参考
查看>>
[转]Pass a ViewBag instance to a HiddenFor field in Razor
查看>>