圆形展开

本文介绍了一种在Android应用中实现加载界面扩散效果的方法。通过自定义View绘制空心圆并利用ValueAnimator实现扩散动画,最终达到优雅地显示加载完成界面的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果

        在加载数据时,界面上需要一个进度条提示用户等待。当数据加载完成后,需要隐藏进度条。在隐藏时,可以使用一些效果,比如一个空心圆从中间开始,一点点的扩大,显露出下面的内容。如:


原理

        在展示时,其实是画一个空心圆,内圆的半径不断地增大,这样就类似于一个扩散效果。

        在画空心圆时,需要不断地调整笔画的宽度,这样就能保证外面一层始终是被遮盖住的。

代码

package com.example.hufeng.demo;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;


public class MyLinearLayout extends View {
    private int radius = 90;
    private int smallRadius = 15;
    private Paint circlePaint;
    private Paint spreadPaint;
    private static final int STATE_ROTATION = 1;
    private static final int STATE_MERGE = 2;
    private static final int STATE_SPREAD = 3;
    private int mCurrState = STATE_ROTATION;
    private int startAngle = 0;
    private float tempRadius;
    private ValueAnimator rotationAnimator, mergeAnimator;
    private int[] mColors = new int[]{Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.GRAY, Color.BLACK};
    private float centerX, centerY,length;

    public MyLinearLayout(Context context, AttributeSet set) {
        super(context, set);
        init();
        startRotation();
    }

    private void init() {
        circlePaint = new Paint();
        circlePaint.setStyle(Paint.Style.FILL);
        circlePaint.setAntiAlias(true);
        spreadPaint = new Paint();
        spreadPaint.setStyle(Paint.Style.STROKE);//只画边框,这样能保证中间是空白,从而画出同心圆
        spreadPaint.setAntiAlias(true);
        spreadPaint.setColor(Color.rgb(0xaa, 0x55, 0x88));//与该控件的背影色一样
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = getWidth() / 2.0f;
        centerY = getHeight() / 2.0f;
        length = (float)Math.sqrt((getWidth() * getWidth())+(getHeight() * getHeight()))/2;
    }

    private void startRotation() {
        rotationAnimator = ValueAnimator.ofInt(0, 360);
        rotationAnimator.setInterpolator(new LinearInterpolator());
        rotationAnimator.setDuration(1000);
        rotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
        rotationAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                startAngle = (Integer) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        rotationAnimator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        switch (mCurrState) {
            case STATE_MERGE:
                canvas.drawColor(Color.rgb(0xaa, 0x55, 0x88));//重新绘上背影色
                drawMerge(canvas);
                break;
            case STATE_ROTATION:
                canvas.drawColor(Color.rgb(0xaa, 0x55, 0x88));
                drawRotation(canvas);
                break;
            case STATE_SPREAD:
                drawSpread(canvas);
                break;
        }

    }

    private void drawSpread(Canvas canvas) {
        // 圆的半径=内环小圆半径+画笔宽度的一半
        canvas.drawCircle(centerX,centerY,tempRadius+spreadPaint.getStrokeWidth()/2,spreadPaint);
    }


    private void drawMerge(Canvas canvas) {
        for (int x = 0; x < mColors.length; x++) {
            double rotation = Math.toRadians(x * 60 + startAngle);
            circlePaint.setColor(mColors[x]);
            double cx = centerX + tempRadius * Math.cos(rotation);//不断缩小半径,这样就显示出内聚效果
            double cy = centerY + tempRadius * Math.sin(rotation);
            canvas.drawCircle((float) cx, (float) cy, smallRadius, circlePaint);
        }
    }

    private void drawRotation(Canvas canvas) {
        for (int x = 0; x < mColors.length; x++) {
            double rotation = Math.toRadians(x * 60 + startAngle);
            circlePaint.setColor(mColors[x]);
            double cx = centerX + radius * Math.cos(rotation);//不断改变角度,呈现出旋转效果
            double cy = centerY + radius * Math.sin(rotation);
            canvas.drawCircle((float) cx, (float) cy, smallRadius, circlePaint);
        }
    }


    public void stop() {
        mCurrState = STATE_MERGE;
        rotationAnimator.cancel();
        rotationAnimator = null;

        mergeAnimator = ValueAnimator.ofFloat(0, radius);
        mergeAnimator.setInterpolator(new OvershootInterpolator(6));
        mergeAnimator.setDuration(1000);
        mergeAnimator.setRepeatCount(0);
        mergeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                tempRadius = (Float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        mergeAnimator.reverse();//反向开始,这样在内聚之间会往外扩展一下
        mergeAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {//结束后,开始画同心圆,展示加载出来的界面
                startSpread();
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
    }

    private void startSpread() {
        mergeAnimator.cancel();
        mergeAnimator = null;

        mCurrState = STATE_SPREAD;
        final ValueAnimator spreadAnimator = ValueAnimator.ofFloat(0,length);//半径由0到length
        spreadAnimator.setDuration(1000);
        spreadAnimator.setInterpolator(new LinearInterpolator());
        spreadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                tempRadius = (Float)valueAnimator.getAnimatedValue();//内环小圆半径
                spreadPaint.setStrokeWidth(length - tempRadius);//设置画笔宽度
                invalidate();
            }
        });
        spreadAnimator.start();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值