汽水小公举控件

来源:互联网 发布:java web消息推送框架 编辑:程序博客网 时间:2024/04/25 15:50


github: https://github.com/ChanJLee/SodaLady

转载请注明出处:http://blog.csdn.net/u013022222/article/details/50066095


package com.os.magic.progressbar.soda.view;import android.annotation.TargetApi;import android.content.Context;import android.content.res.Resources;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.drawable.BitmapDrawable;import android.os.Build;import android.util.AttributeSet;import android.view.View;import com.o.democanvas.R;import com.os.magic.progressbar.soda.util.Util;import java.util.ArrayList;import java.util.List;import java.util.Random;/** * Created by chan on 15-11-26. * 橘子汽水进度条 * 汽水小公举 */public class OrangeSodaProgressBar extends View {    ////////////////////////////////////////////////////////////////////////////////////////////////    /**     *      */    private static final int COLOR_WHITE = 0xfffde399;    private static final int COLOR_ORANGE = 0xffffa800;    /**     * 振幅     */    private static final int AMPLITUDE_MIDDLE = 13;    /**     * 振幅差     */    private static final int AMPLITUDE_DISPARITY = 5;    /**     *  果粒飘动一个周期所花的时间     */    private static final long TIME_FLOAT = 3000;    /**     * 果粒旋转一周需要的时间     */    private static final long TIME_ROTATE = 2000;    /**     *  用于控制绘制的进度条距离左/上/下的距离     */    private static final int LEFT_MARGIN = 9;    /**     * 用于控制绘制的进度条距离右的距离     */    private static final int RIGHT_MARGIN = 25;    ////////////////////////////////////////////////////////////////////////////////////////////////    /**     * 由颜色的画笔     */    private Paint m_whitePaint, m_orangePaint;    /**     * 画出图片的画笔     */    private Paint m_bitmapPaint;    /**     * 当前的进度值     */    private int m_currentProgressPosition = 0;    /**     * 最大的长度     */    private int m_maxLength = 100;    /**     * 当前处理到的部分     */    private int m_progress = 0;    /**     * 左右边距     */    private int m_leftMargin, m_rightMargin;    /**     * 白色矩形 橙色矩形 扇形区域     */    private RectF m_whiteRectF, m_orangeRectF, m_arcRectF;    /**     * 所绘制的进度条部分的宽度     */    private int m_progressWidth;    /**     * 弧形的半径     */    private int m_arcRadius;    private int m_totalWidth;    private int m_totalHeight;    // arc的右上角的x坐标,也是矩形x坐标的起始点    private int m_arcRightLocation;    /**     * 果粒集群     */    private List<Pulp> m_pulps;    private float m_floatDuration = TIME_FLOAT;    private float m_rotateDuration = TIME_ROTATE;    private Bitmap m_pulpBitmap;    private Bitmap m_outRoundedBitmap;    private int m_pulpWidth;    private int m_pulpHeight;    private int m_outerWidth;    private int m_outerHeight;    private Rect m_outerSrcRect;    private Rect m_outerDestRect;    private Bitmap m_orangeBitmap;    private int m_orangeWidth, m_orangeHeight;    private int m_orangeAngle = 0;    ////////////////////////////////////////////////////////////////////////////////////////////////    public OrangeSodaProgressBar(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public OrangeSodaProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context, attrs, defStyleAttr);    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public OrangeSodaProgressBar(Context context, AttributeSet attrs,                                 int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init(context, attrs, defStyleAttr);    }    ////////////////////////////////////////////////////////////////////////////////////////////////    /**     * 做一些初始化工作     *     * @param context     * @param attributeSet     * @param defStyleAttr     */    private void init(Context context, AttributeSet attributeSet, int defStyleAttr) {        initAttribute(context, attributeSet, defStyleAttr);        initBase();        initBitmap();        initPaint();    }    /**     * 初始化属性     * @param context     * @param attributeSet     * @param defStyleAttr     */    private void initAttribute(Context context,AttributeSet attributeSet,int defStyleAttr){        TypedArray typedArray  = context.obtainStyledAttributes(attributeSet,                R.styleable.OrangeSodaProgressBar, defStyleAttr, 0);        try {            final int length = typedArray.getIndexCount();            for(int i = 0; i < length; ++i) {                switch (typedArray.getIndex(i)) {                    case R.styleable.OrangeSodaProgressBar_maxLength:                        m_maxLength = typedArray.getInt(i, 100);                        break;                }            }        } finally {            if (typedArray != null)                typedArray.recycle();        }    }    /**     * 初始基础部分     */    private void initBase() {        Context context = getContext();        m_leftMargin = Util.dp2Px(context, LEFT_MARGIN);        m_rightMargin = Util.dp2Px(context, RIGHT_MARGIN);        m_pulps = PulpFactory.newInstances(m_floatDuration);    }    /**     * 初始化要显示的图片     */    @SuppressWarnings("deprecated")    private void initBitmap(){        Resources resources = getResources();        m_pulpBitmap = ((BitmapDrawable)                resources.getDrawable(R.drawable.pupl)).getBitmap();        m_pulpWidth = m_pulpBitmap.getWidth();        m_pulpHeight = m_pulpBitmap.getHeight();        m_outRoundedBitmap = ((BitmapDrawable)                resources.getDrawable(R.drawable.bar)).getBitmap();        m_outerWidth = m_outRoundedBitmap.getWidth();        m_outerHeight = m_outRoundedBitmap.getHeight();        BitmapFactory.Options options = new BitmapFactory.Options();        options.inSampleSize = 2;        options.inJustDecodeBounds = false;        m_orangeBitmap = BitmapFactory.decodeResource(resources, R.drawable.orange, options);        m_orangeWidth = m_orangeBitmap.getWidth();        m_orangeHeight = m_orangeBitmap.getHeight();    }    /**     * 初始化画刷     */    private void initPaint(){        m_bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG                | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);        m_orangePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        m_orangePaint.setColor(COLOR_ORANGE);        m_whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        m_whitePaint.setColor(COLOR_WHITE);    }    @Override    protected void onSizeChanged(int w, int h, int ow, int oh) {        super.onSizeChanged(w, h, ow, oh);        initSizeParameter(w, h, ow, oh);    }    /**     * 当大小发生改变时 变更新一下绘制的参数     * @param newWidth     * @param newHeight     * @param prevWidth     * @param prevHeight     */    private void initSizeParameter(int newWidth, int newHeight, int prevWidth, int prevHeight) {        //算出总的长度        m_totalWidth = newWidth;        m_totalHeight = newHeight;        //计算出进度条实际的长度        m_progressWidth = m_totalWidth - m_leftMargin - m_rightMargin;        //本来是扇形的半径应该是高度的一半减去上下两个边界        m_arcRadius = (m_totalHeight - 2 * m_leftMargin) / 2;        //绘制图片        m_outerSrcRect = new Rect(                0,                0,                m_outerWidth,                m_outerHeight        );        m_outerDestRect = new Rect(                0,                0,                m_totalWidth,                m_totalHeight        );        //绘制颜色        m_whiteRectF = new RectF(                m_leftMargin + m_currentProgressPosition,                m_leftMargin,                m_totalWidth - m_rightMargin,                m_totalHeight - m_leftMargin        );        m_orangeRectF = new RectF(                m_leftMargin + m_arcRadius,                m_leftMargin,                m_currentProgressPosition                , m_totalHeight - m_leftMargin        );        m_arcRectF = new RectF(                m_leftMargin,                m_leftMargin,                m_leftMargin + 2 * m_arcRadius,                m_totalHeight - m_leftMargin        );        //扇形和举行的分界点        m_arcRightLocation = m_leftMargin + m_arcRadius;        //橘子的高度        m_orangeBitmapSize = Math.min(Math.min(newHeight,                m_orangeHeight), m_orangeWidth) - 20;    }    private int m_orangeBitmapSize;    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        drawProgressBar(canvas);        drawBackground(canvas);        drawOrange(canvas);        postInvalidate();    }    /**     * 绘制橘子     * @param canvas     */    private void drawOrange(Canvas canvas) {        m_orangeAngle = (m_orangeAngle + 5) % 360;        canvas.save();        Matrix matrix = new Matrix();        float dx = m_totalWidth - m_totalHeight / 2 - m_orangeWidth / 2;        float dy = m_totalHeight / 2 - m_orangeHeight / 2;        matrix.postTranslate(dx, dy);        float px = dx + m_orangeWidth / 2;        float py = dy + m_orangeHeight / 2;        matrix.postRotate(m_orangeAngle, px, py);        canvas.drawBitmap(m_orangeBitmap, matrix, m_bitmapPaint);        canvas.restore();    }    /**     * 绘制背景     * @param canvas     */    private void drawBackground(Canvas canvas) {        canvas.drawBitmap(m_outRoundedBitmap, m_outerSrcRect, m_outerDestRect, m_bitmapPaint);    }    //取一个不可能的值    private float m_previousProgressPosition = -1;    /**     * 绘制出进度条的形状     * @param canvas     */    private void drawProgressBar(Canvas canvas){        //计算出当前的位置        m_currentProgressPosition = m_progressWidth * m_progress /                (m_maxLength == 0 ? 1 : m_maxLength);        //如果超出长度 那么就是最长的长度 不能再增加        if(m_currentProgressPosition > m_progressWidth)            m_currentProgressPosition = m_progressWidth;        //如果进度还是在扇形之内        if(m_currentProgressPosition < m_arcRadius) {            //首先要画出所有白色的部分            canvas.drawArc(m_arcRectF, 90, 180, false, m_whitePaint);            m_whiteRectF.left = m_arcRightLocation;            canvas.drawRect(m_whiteRectF, m_whitePaint);            //之后是橘色的扇形部分            //计算出sin值            float sinXValue = (m_arcRadius - m_currentProgressPosition) / m_arcRadius;            float angleX = (float) Math.asin(sinXValue);            float sweep = 2 * (90 - angleX);            float start = 90 + angleX;            canvas.drawArc(m_arcRectF, start, sweep, false, m_whitePaint);        }else if(m_currentProgressPosition >= m_arcRadius) {            //橘色扇形 橘色矩形部分            canvas.drawArc(m_arcRectF, 90, 180, false, m_orangePaint);            m_orangeRectF.right = m_currentProgressPosition;            m_orangeRectF.left = m_arcRightLocation;            canvas.drawRect(m_orangeRectF,m_orangePaint);            //画出白色矩形部分            m_whiteRectF.left = m_currentProgressPosition;            canvas.drawRect(m_whiteRectF,m_whitePaint);        }//        //记录一下现在的长度//        m_previousProgressPosition = m_currentProgressPosition;        //绘制果粒        drawPulps(canvas);    }    private void drawPulps(Canvas canvas) {        final int size = m_pulps.size();        long current = System.currentTimeMillis();        for (int i = 0; i < size; ++i) {            Pulp pulp = m_pulps.get(i);            if(current < pulp.m_startTime) continue;            calPulpParameter(pulp);            canvas.save();            Matrix matrix = new Matrix();            float dx = m_leftMargin + pulp.m_x;            float dy = m_leftMargin + pulp.m_y;            matrix.postTranslate(dx, dy);            float rotate = pulp.m_rotateAngle;            float px = dx + m_pulpWidth / 2;            float py = dy + m_pulpHeight / 2;            matrix.postRotate(rotate, px, py);            canvas.drawBitmap(m_pulpBitmap, matrix, m_bitmapPaint);            canvas.restore();        }    }    /**     *     * @param pulp 计算果粒的参数     */    private void calPulpParameter(Pulp pulp) {        long currentTime = System.currentTimeMillis();        calPulpLocation(pulp, currentTime);        calPulpRotateAngle(pulp, currentTime);    }    /**     * 计算果粒的旋转角度     * @param pulp     * @param currentTime     */    private void calPulpRotateAngle(Pulp pulp,long currentTime){        // 通过时间关联旋转角度        float rotateFraction = ((currentTime - pulp.m_startTime) % m_rotateDuration)                / (float) m_rotateDuration;        int angle = (int) (rotateFraction * 360);        // 根据叶子旋转方向确定叶子旋转角度        pulp.m_rotateAngle = (pulp.m_rotateOrientation == Pulp.ORIENTATION_LEFT                ? angle : -angle);    }    /**     * 计算果粒的当前位置     * @param pulp 果粒     * @param currentTime 当前的时间     */    private void calPulpLocation(Pulp pulp, long currentTime) {        //获得时间间隔 如果还没有准备好要播放 那就不执行下面的代码        long intervalTime = currentTime - pulp.m_startTime;        if (intervalTime < 0) {            return;        }        //如果已经超过了漂浮的时间 就重新计算一次开始的时间 以循环使用果粒        if (intervalTime > m_floatDuration) {            pulp.m_startTime = System.currentTimeMillis()                    + new Random().nextInt((int) m_floatDuration);            return;        }        pulp.m_x = calPulpX(intervalTime);        pulp.m_y = calPulpY(pulp);        if(pulp.m_x < m_currentProgressPosition){            pulp.m_x = m_progressWidth;        }    }    /**     * 计算果粒的x坐标     * @param intervalTime     * @return     */    private float calPulpX(long intervalTime){        //计算完成度        float fraction = (float) intervalTime / m_floatDuration;        return (m_progressWidth - m_progressWidth * fraction);    }    /**     * 计算果粒的y     * @param pulp     * @return     */    private float calPulpY(Pulp pulp) {        // y = A(wx+Q)+h        float w = (float) ((float) 2 * Math.PI / m_progressWidth);        float a = AMPLITUDE_MIDDLE;        switch (pulp.m_type) {            case Pulp.TYPE_LITTLE:                // 小振幅 = 中等振幅 - 振幅差                a = AMPLITUDE_MIDDLE - AMPLITUDE_DISPARITY;                break;            case Pulp.TYPE_MID:                a = AMPLITUDE_MIDDLE;                break;            case Pulp.TYPE_HIGH:                // 大振幅 = 中等振幅 + 振幅差                a = AMPLITUDE_MIDDLE + AMPLITUDE_DISPARITY;                break;            default:                break;        }        //三角函数        return (int) (a * Math.sin(w * pulp.m_x)) + m_arcRadius * 2 / 3;    }    /**     * 设置     * @return     */    public int getProgress() {        return m_progress;    }    public void setProgress(int progress) {        m_progress = progress;    }    public int getMaxLength() {        return m_maxLength;    }    public void setMaxLength(int maxLength) {        m_maxLength = maxLength;    }    ////////////////////////////////////////////////////////////////////////////////////////////////    /**     * 飘动的橘子果粒     */    static final private class Pulp{        ////////////////////////////////////////////////////////////////////////////////////////////        /**         * 果粒漂浮时候的幅度 分别为小中大         */        private static final short TYPE_LITTLE = 0x01;        private static final short TYPE_MID = 0x02;        private static final short TYPE_HIGH = 0x03;        /**         * 左旋         */        private static final short ORIENTATION_LEFT = 0x01;        /**         * 右旋         */        private static final short ORIENTATION_RIGHT = 0x02;        ////////////////////////////////////////////////////////////////////////////////////////////        /**         * 开始的x y 坐标         */        private float m_x, m_y;        /**         * 震动的幅度         */        private short m_type;        /**         * 旋转的方向         */        private short m_rotateOrientation;        /**         * 旋转的角度         */        private int m_rotateAngle;        /**         * 开始的时间         */        private long m_startTime;        ////////////////////////////////////////////////////////////////////////////////////////////        /**         * @param x 果粒的坐标         * @param y         * @param type 飘动幅度         *             {@link OrangeSodaProgressBar.Pulp#TYPE_HIGH}         *             {@link OrangeSodaProgressBar.Pulp#TYPE_LITTLE}         *             {@link OrangeSodaProgressBar.Pulp#TYPE_MID}         * @param rotateOrientation 旋转方向         *                          {@link OrangeSodaProgressBar.Pulp#ORIENTATION_LEFT}         *                          {@link OrangeSodaProgressBar.Pulp#ORIENTATION_RIGHT}         * @param rotateAngle 旋转的角度         * @param startTime 开始的时间         */        public Pulp(float x, float y, short type, short rotateOrientation, int rotateAngle, long startTime) {            m_x = x;            m_y = y;            m_type = type;            m_rotateOrientation = rotateOrientation;            m_startTime = startTime;            m_rotateAngle = rotateAngle;        }    }    /**     * 果粒工厂     */    static final private class PulpFactory {        ////////////////////////////////////////////////////////////////////////////////////////////        /**         * 随机数产生器         */        private static final Random RANDOM = new Random();        /**         * 默认的果粒个数         */        private static final short DEFAULT_SIZE = 0x0006;        /**         * 延迟的时间         */        private static int s_addTime = 0;        ////////////////////////////////////////////////////////////////////////////////////////////        /**         * 产生一个果粒         * @param floatTime 果粒飘动的时间         * @return         */        static public Pulp newInstance(float floatTime) {            //随机产生果粒飘动的幅度            short type = Pulp.TYPE_LITTLE;            switch (RANDOM.nextInt(3)) {                case 0:                    type = Pulp.TYPE_LITTLE;                    break;                case 1:                    type = Pulp.TYPE_MID;                    break;                case 2:                    type = Pulp.TYPE_HIGH;                    break;            }            //随机产生果粒旋转的方向            short rotateOrientation = Pulp.ORIENTATION_LEFT;            switch (RANDOM.nextInt(2)) {                case 0:                    rotateOrientation = Pulp.ORIENTATION_LEFT;                    break;                case 1:                    rotateOrientation = Pulp.ORIENTATION_RIGHT;                    break;            }            //旋转的角度            int rotateAngle = RANDOM.nextInt(360);            //播放时候延迟的时间            s_addTime += RANDOM.nextInt((int) (Math.abs(floatTime) * 2));            long startTime = s_addTime + System.currentTimeMillis();            //果粒默认的起始坐标为0 0            return new Pulp(0, 0, type, rotateOrientation, rotateAngle, startTime);        }        /**         * 产生果粒集合         * @param count 产生果粒的总个数         * @param floatTime 果粒飘动的时间         * @return         */        static public List<Pulp> newInstances(int count, float floatTime) {            List<Pulp> pulpList = new ArrayList<>();            for (int i = 0; i < count; ++i) {                pulpList.add(newInstance(floatTime));            }            return pulpList;        }        /**         * 产生默认大小的果粒集合         * @param floatTime         * @return         */        static public List<Pulp> newInstances(float floatTime) {            List<Pulp> pulpList = new ArrayList<>();            for (int i = 0; i < DEFAULT_SIZE; ++i) {                pulpList.add(newInstance(floatTime));            }            return pulpList;        }    }    ////////////////////////////////////////////////////////////////////////////////////////////////}


0 0
原创粉丝点击