android 高仿华为充电动画

 







public class BubbleViscosity extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private static ScheduledExecutorService scheduledThreadPool;
    private Context context;
    private String paintColor = "#25DA29";// 不透明圆弧的颜色
    private String centreColor = "#00000000"; // 中间圆的颜色
    private String minCentreColor = "#9025DA29"; //透明的圆弧
    private int screenHeight;
    private int screenWidth;


    private float lastRadius;  // 底部半圆的半径
    private float rate = 0.32f;// 底部曲线的控制点
    private float rate2 = 0.45f;// 底部曲线的控制点
    private PointF lastCurveStrat = new PointF();//底部圆的起点坐标
    private PointF lastCurveEnd = new PointF();//底部圆的结束坐标
    private PointF centreCirclePoint = new PointF();// 中间圆的坐标
    private float centreRadius;//中间圆的 半径
    private float bubbleRadius;


    // 所有圆弧的坐标数组
    private PointF[] arcPointStrat = new PointF[8];
    private PointF[] arcPointEnd = new PointF[8];
    private PointF[] control = new PointF[8];
    private PointF arcStrat = new PointF();
    private PointF arcEnd = new PointF();
    private PointF controlP = new PointF();

    // 气泡的其实点保存集合
    List<PointF> bubbleList = new ArrayList<>();
    List<BubbleBean> bubbleBeans = new ArrayList<>();

    private int rotateAngle = 0;  //旋转的角度
    private float controlrate = 1.66f; // 圆弧的控制点
    private float controlrateS = 1.3f; // 可变圆弧的控制点
    private int i = 0;// 无限循环的下标
    private SurfaceHolder mHolder;
    private float scale = 0;//  圆得开口值

    private Paint arcPaint;
    private Paint minCentrePaint;
    private Paint bubblePaint;
    private Paint centrePaint;
    private Paint lastPaint;
    private Path lastPath; // 所有的路劲
    private Random random;
    private Paint textPaint;
    private String text="78 %";
    private Rect rect;

    public BubbleViscosity(Context context) {
        this(context, null);
    }

    public BubbleViscosity(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BubbleViscosity(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initTool();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        screenHeight = getMeasuredHeight();
        screenWidth = getMeasuredWidth();
        setBubbleList();
    }

    private void initTool() {
        rect = new Rect();
        mHolder = getHolder();//获取SurfaceHolder对象
        mHolder.addCallback(this);//注册SurfaceHolder的回调方法
        setFocusable(true); // 设置焦点
        //TODO:保证该SurfaceView在最上层,避免两个SurfaceView叠加,遮挡问题
        mHolder.setFormat(PixelFormat.TRANSPARENT);
        setZOrderOnTop(true);
        lastRadius = dip2Dimension(40f, context);//底部圆的半径
        centreRadius = dip2Dimension(100f, context);//中间圆的半径
        bubbleRadius = dip2Dimension(10f, context);//气泡的半径
        random = new Random();
        //底部圆
        lastPaint = new Paint();
        lastPaint.setAntiAlias(true);
        lastPaint.setStyle(Paint.Style.FILL);
        lastPaint.setColor(Color.parseColor(paintColor));
        lastPaint.setStrokeWidth(2);

        lastPath = new Path();

        //中间圆的画笔
        centrePaint = new Paint();
        centrePaint.setAntiAlias(true);
        centrePaint.setStyle(Paint.Style.FILL);
        centrePaint.setStrokeWidth(2);
        centrePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        centrePaint.setColor(Color.parseColor(centreColor));
        // 不透明圆弧的画笔
        arcPaint = new Paint();
        arcPaint.setAntiAlias(true);
        arcPaint.setStyle(Paint.Style.FILL);
        arcPaint.setColor(Color.parseColor(paintColor));
        arcPaint.setStrokeWidth(2);
        //  透明圆弧的画笔
        minCentrePaint = new Paint();
        minCentrePaint.setAntiAlias(true);
        minCentrePaint.setStyle(Paint.Style.FILL);
        minCentrePaint.setColor(Color.parseColor(minCentreColor));
        minCentrePaint.setStrokeWidth(2);
        // 气泡的画笔
        bubblePaint = new Paint();
        bubblePaint.setAntiAlias(true);
        bubblePaint.setStyle(Paint.Style.FILL);
        bubblePaint.setColor(Color.parseColor(minCentreColor));
        bubblePaint.setStrokeWidth(2);
        //文字画笔
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setColor(Color.parseColor("#FFFFFF"));
        textPaint.setStrokeWidth(2);
        textPaint.setTextSize(dip2Dimension(40f, context));



    }


    private void onMDraw() {
        Canvas canvas = mHolder.lockCanvas();
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//绘制透明色
        bubbleDraw(canvas);  //画气泡
        lastCircleDraw(canvas);//画底部的半圆
        centreCircleDraw(canvas);// 中间的圆
        textPaint.getTextBounds(text,0,text.length(),rect);
        canvas.drawText(text,centreCirclePoint.x-rect.width()/2,centreCirclePoint.y+rect.height()/2,textPaint);
        mHolder.unlockCanvasAndPost(canvas);
    }

    private void centreCircleDraw(Canvas canvas) {
        centreCirclePoint.set(screenWidth / 2, screenHeight / 2);
        circleInCoordinateDraw(canvas);//绘制四个圆弧
        canvas.drawCircle(centreCirclePoint.x, centreCirclePoint.y, centreRadius, centrePaint);

    }

    private void lastCircleDraw(Canvas canvas) {
        lastCurveStrat.set(screenWidth / 2 - lastRadius, screenHeight);//第一段曲线的开始点
        lastCurveEnd.set((screenWidth / 2), screenHeight);//第一段的结束点

        float k = (lastRadius / 2) / lastRadius;// 三角函数 正切

        float aX = lastRadius - lastRadius * rate2; //任意取一个点 为控制点 rate 控制曲线的弯曲度
        float aY = lastCurveStrat.y - aX * k;
        float bX = lastRadius - lastRadius * rate;
        float bY = lastCurveEnd.y - bX * k;

        lastPath.rewind();
        lastPath.moveTo(lastCurveStrat.x, lastCurveStrat.y);
        lastPath.cubicTo(lastCurveStrat.x + aX, aY, lastCurveEnd.x - bX, bY, lastCurveEnd.x, lastCurveEnd.y - lastRadius / 2);
        lastPath.cubicTo(lastCurveEnd.x + bX, bY, lastCurveEnd.x + lastRadius - aX, aY, lastCurveEnd.x + lastRadius, lastCurveEnd.y);

        lastPath.lineTo(lastCurveStrat.x, lastCurveStrat.y);//闭合曲线 进行填充
        canvas.drawPath(lastPath, lastPaint);

    }

    private int bubbleIndex = 0;

    private void bubbleDraw(Canvas canvas) {
        for (int i = 0; i < bubbleBeans.size(); i++) {
            if (bubbleBeans.get(i).getY() <= (int) (screenHeight / 2 + centreRadius)) {
                bubblePaint.setAlpha(000);
                canvas.drawCircle(bubbleBeans.get(i).getX(), bubbleBeans.get(i).getY(), bubbleRadius, bubblePaint);
            }else {
                bubblePaint.setAlpha(150);
                canvas.drawCircle(bubbleBeans.get(i).getX(), bubbleBeans.get(i).getY(), bubbleRadius, bubblePaint);
            }
            //底部黏性动画
            if (bubbleBeans.get(i).getY()<=bubbleList.get(0).y&&bubbleList.get(0).y-bubbleBeans.get(i).getY()<15){
                lastPath.moveTo(lastCurveStrat.x,lastCurveStrat.y);
                int y= (int) (screenHeight-(screenHeight-bubbleBeans.get(i).getY())/2);
                lastPath.quadTo(lastCurveEnd.x-lastRadius,y,bubbleBeans.get(i).getX()-bubbleRadius,bubbleBeans.get(i).getY());
                lastPath.lineTo(bubbleBeans.get(i).getX()+bubbleRadius,bubbleBeans.get(i).getY());
                lastPath.quadTo(lastCurveEnd.x+lastRadius,y,lastCurveEnd.x+lastRadius,lastCurveStrat.y);
                canvas.drawPath(lastPath,bubblePaint);
            }
           //气泡和 中部圆的黏性动画

            if (bubbleBeans.get(i).getY()-arcPointStrat[5].y<110&&rotateAngle>20&&rotateAngle<100){

                lastPath.moveTo(arcPointStrat[5].x,arcPointStrat[5].y);
                float  x= Math.abs(arcPointEnd[5].x - arcPointStrat[5].x)/2;
                float  y=screenHeight/2+centreRadius+(bubbleBeans.get(i).getY()-arcPointStrat[5].y)/2;
                lastPath.quadTo(screenWidth/2+x,y,bubbleBeans.get(i).getX()+bubbleRadius,bubbleBeans.get(i).getY());
                lastPath.lineTo(bubbleBeans.get(i).getX()-bubbleRadius,bubbleBeans.get(i).getY());
                lastPath.quadTo(screenWidth/2-x,y,arcPointEnd[5].x,arcPointEnd[5].y);
                canvas.drawPath(lastPath,bubblePaint);
            }
        }

    }




    /**
     * dip 转换成 px
     *
     * @param dip
     * @param context
     * @return
     */
    public  float dip2Dimension(float dip, Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
    }


    public void circleInCoordinateDraw(Canvas canvas) {
        int angle;
        for (int i = 0; i < arcPointStrat.length; i++) {
            if (i > 3 && i < 6) {//透明圆弧的位置
                if (i == 4) {
                    angle = rotateAngle + i * 60;

                } else {
                    angle = rotateAngle + i * 64;
                }
            } else if (i > 5) {//隐藏显示圆弧的位置
                if (i == 6) {
                    angle = rotateAngle + i * 25;
                } else {
                    angle = rotateAngle + i * 48;
                }

            } else {
                angle = rotateAngle + i * 90;
            }

            //求弧度坐标点的 公式
            float radian = (float) Math.toRadians(angle);
            float adjacent = (float) Math.cos(radian) * centreRadius; //邻边
            float right = (float) Math.sin(radian) * centreRadius;//对边
            //求控制点的坐标 公式
            float radianControl = (float) Math.toRadians(90 - (45 + angle));
            float xStrat = (float) Math.cos(radianControl) * centreRadius; //邻边
            float yEnd = (float) Math.sin(radianControl) * centreRadius; //对边
            if (i == 0 || i == 1) {
                if (i == 1) {
                    arcStrat.set(centreCirclePoint.x + adjacent - scale, centreCirclePoint.y + right + scale);//这个是改变开口大小
                    arcEnd.set(centreCirclePoint.x - right, centreCirclePoint.y + adjacent);

                } else {
                    arcStrat.set(centreCirclePoint.x + adjacent, centreCirclePoint.y + right);
                    arcEnd.set(centreCirclePoint.x - right - scale, centreCirclePoint.y + adjacent + scale);//这个是改变开口大小

                }
                controlP.set(centreCirclePoint.x + yEnd * controlrate, centreCirclePoint.y + xStrat * controlrate);
            } else {
                arcStrat.set(centreCirclePoint.x + adjacent, centreCirclePoint.y + right);
                arcEnd.set(centreCirclePoint.x - right, centreCirclePoint.y + adjacent);
                if (i > 5) {
                    controlP.set(centreCirclePoint.x + yEnd * controlrateS, centreCirclePoint.y + xStrat * controlrateS);
                } else {
                    controlP.set(centreCirclePoint.x + yEnd * controlrate, centreCirclePoint.y + xStrat * controlrate);
                }
            }
            arcPointStrat[i] = arcStrat;
            arcPointEnd[i] = arcEnd;
            control[i] = controlP;

            lastPath.rewind();
            lastPath.moveTo(arcPointStrat[i].x, arcPointStrat[i].y);
            lastPath.quadTo(control[i].x, control[i].y, arcPointEnd[i].x, arcPointEnd[i].y);

            if (i > 3 && i < 6) {
                canvas.drawPath(lastPath, minCentrePaint);
            } else {
                canvas.drawPath(lastPath, arcPaint);
            }
            lastPath.rewind();
        }
    }


    private void setAnimation() {
        setScheduleWithFixedDelay(this, 0, 5);
        setScheduleWithFixedDelay(new Runnable() {//添加气泡的线程
            @Override
            public void run() {//添加气泡
                if (bubbleIndex > 2) bubbleIndex = 0;
                if (bubbleBeans.size() < 8) {
                    bubbleBeans.add(new BubbleBean(bubbleList.get(bubbleIndex).x, bubbleList.get(bubbleIndex).y,random.nextInt(4)+2,bubbleIndex));
                }else {
                    for (int i=0;i<bubbleBeans.size();i++){
                        if (bubbleBeans.get(i).getY() <= (int) (screenHeight / 2 + centreRadius)) {
                            bubbleBeans.get(i).set(bubbleList.get(bubbleIndex).x, bubbleList.get(bubbleIndex).y,random.nextInt(4)+2,bubbleIndex);
                            if (random.nextInt(bubbleBeans.size())+3==3? true : false){
                            }else {
                                break;
                            }
                        }
                    }
                }
                bubbleIndex++;
            }
        }, 0, 300);
    }


    private static ScheduledExecutorService getInstence() {
        if (scheduledThreadPool == null) {
            synchronized (BubbleViscosity.class) {
                if (scheduledThreadPool == null) {
                    scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();//newScheduledThreadPool
                }
            }
        }
        return scheduledThreadPool;
    }

    /*
     * 定时任务 每隔多少秒执行一次
     * */
    private static void setScheduleWithFixedDelay(Runnable var1, long var2, long var4) {
        getInstence().scheduleWithFixedDelay(var1, var2, var4, TimeUnit.MILLISECONDS);

    }


    /*
     * 结束线程 任务
     * */
    public static void onDestroyThread() {
        getInstence().shutdownNow();
        if (scheduledThreadPool != null) {
            scheduledThreadPool = null;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        setAnimation();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        onDestroyThread();
    }

    @Override
    public void run() {
        i++;
        rotateAngle = i;
        if (i > 90 && i < 180) {
            scale += 0.25;
            if (controlrateS < 1.66)
                controlrateS += 0.005;
        } else if (i >= 180) {
            scale -= 0.12;
            if (i > 300)
                controlrateS -= 0.01;
        }
        onMDraw();
        if (i == 360) {
            i = 0;
            rotateAngle = 0;
            controlrate = 1.66f;
            controlrateS = 1.3f;
            scale = 0;
        }

    }


    public void setBubbleList() {
        //求弧度坐标点的 公式
        float radian = (float) Math.toRadians(35);
        float adjacent = (float) Math.cos(radian) * lastRadius / 3; //邻边
        float right = (float) Math.sin(radian) * lastRadius / 3;//对边
        if (!bubbleList.isEmpty()) return;
        bubbleList.add(new PointF(screenWidth / 2 - adjacent, screenHeight - right)); //左边气泡的位置
        bubbleList.add(new PointF(screenWidth / 2, screenHeight - lastRadius / 4));  // 中间气泡的位置
        bubbleList.add(new PointF(screenWidth / 2 + adjacent, screenHeight - right));  //右边气泡的位置


        setScheduleWithFixedDelay(new Runnable() {// 移动气泡的线程
            @Override
            public void run() {
                for (int i = 0; i < bubbleBeans.size(); i++) {
                    bubbleBeans.get(i).setMove(screenHeight,(int) (screenHeight / 2 + centreRadius));
                }
            }
        }, 0, 4);

    }
}

 

 

===========  分装气泡的类

public class BubbleBean {

    private float randomY=3;
    private float x;
    private float y;
    private int index;
    public BubbleBean(float x, float y,float randomY,int index) {
        this.x = x;
        this.y = y;
        this.randomY = randomY;
        this.index = index;
    }

    public void set(float x, float y,float randomY,int index){
        this.x = x;
        this.y = y;
        this.randomY = randomY;
        this.index = index;
    }

    public void setMove(int screenHeight,int maxDistance){
        if (y-maxDistance<110){
            this.y-=2;
            return;
        }

       if (maxDistance<=y&&screenHeight-y>110){
            this.y-=randomY;
      }else {
           this.y-=0.6;//气泡开始的移动的时候比较慢,造成气泡开始的 黏性气泡
       }

        if (index==0){
            this.x-=0.4;
        }else if (index==2){
            this.x+=0.4;
        }
    }


    public int getIndex(){
        return  index;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }
}

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值