闪屏的原理是画两层view,一层就是动画结束需要呈现的底层,我们这里定义为ContentView,另外一层就是我们的动画SplashView,动画都在这层上绘制,
在activity这里我们先画contentView,再画SplashView,这样SplashView就在contentView的上层,清除SplashView就可以显示contentView
public class SplanshActivity extends Activity {//AppCompat
private FrameLayout fragment;
private SplashView splashView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splansh);
fragment = new FrameLayout(this);
ContentView contentView = new ContentView(this);
fragment.addView(contentView);
splashView = new SplashView(this);
fragment.addView(splashView);
setContentView(fragment);
//开始加载数据
startSplanshDataLoad();
}
Handler handler = new Handler();
private void startSplanshDataLoad() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
//数据加载完毕--进入主界面--开启后面两个动画
splashView.SplashDisappear();
}
}, 2000);
}
}
contentView没有什么特别之处,我们用imageView演示就可以了
public class ContentView extends ImageView{
public ContentView(Context context) {
super(context);
setImageResource(R.drawable.a1);
}
}
所有的动画都在这层
我们的动画分三部分:
- 小球旋转加载
- 小球聚合
- 空心圆扩散
不使用ifelse来写,使用状态模式这种设计模式,好处不言而喻
private SplashState mState = null;
private abstract class SplashState {
public abstract void drawState(Canvas canvas);
}
用mState对象来保存当前执行的动画,写一个内部类或者接口,来规范我们的状态行为
public class SplashView extends View {
/**
* some adjustable paramerters
**/
//大圆(里面包括很多小圆)的半径
private float mRoatationRadius = 90;
//每个小圆的半径
private float mCircleRadius = 18;
//小圆圈颜色列表,在initiallize方法里面初始化
private int[] mCircleColors;
//大圆和小圆旋转的时间
private long mRoatationDuration = 1200;//ms
//第二部分动画的总执行时间(包第二个动画时间,各占用1/2)
private long mSplashDuration = 1200;//ms
//整体的背景颜色
private int mSplashBgColor = Color.WHITE;//ms
/**
* 参数,保存一些绘制的状态,会被动态地改变
*/
//空心圆初始半径
private float mHoleRadius = 0F;
//当前大圆旋转角度(弧度)
private float mCurrentRotationAngle = 0F;
//当前大圆的半径
private float mCurrentRotationRadius = mRoatationRadius;
//绘制圆的画笔
private Paint mPaint = new Paint();
//绘制背景的画笔
private Paint mPaintBackground = new Paint();
//屏幕正中心点坐标
private float mCenterX;
private float mCenterY;
//屏幕对角线一半
private float mDiagonalDist;
public SplashView(Context context) {
super(context);
init();
}
private void init() {
mPaint.setAntiAlias(true);
mPaintBackground.setAntiAlias(true);
mPaintBackground.setStyle(Paint.Style.STROKE);
mPaintBackground.setColor(mSplashBgColor);
mCircleColors = getContext().getResources().getIntArray(R.array.splash_circle_colors);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w / 2f;
mCenterY = h / 2f;
mDiagonalDist = (float) Math.sqrt(w * w + h * h) / 2;
}
public void SplashDisappear() {
//进入主页面 开启后面的两个动画
if (mState != null && mState instanceof RotationState) {
RotationState rotationState = (RotationState) mState;
rotationState.cancel();
post(new Runnable() {
@Override
public void run() {
//状态修改
mState = new MergingState();
}
});
// invalidate();
}
}
//保存当前动画状态--当前在执行哪种动画
private SplashState mState = null;
private abstract class SplashState {
public abstract void drawState(Canvas canvas);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制动画,三种状态
if (mState == null) {
//默认加载第一个
mState = new RotationState();
Log.i("wxh", "执行了");
}
//绘制的分发
mState.drawState(canvas);
}
/**
* 小球旋转动画
*/
private class RotationState extends SplashState {
private ValueAnimator animator;
public RotationState() {
//小圆的坐标-->大圆的旋转读书(0~2π)、半径
animator = ValueAnimator.ofFloat(0, (float) Math.PI * 2);
//设置线性插值器---平滑计算
animator.setInterpolator(new LinearInterpolator());
//计算时间
animator.setDuration(mRoatationDuration);
//设置监听
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//不断修改旋转的角度
mCurrentRotationAngle = (float) animation.getAnimatedValue();
// Log.i("wxh",mCurrentRota);
//提醒view重新绘制onDraw
invalidate();
}
});
//循环次数为无限
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();
Log.i("wxh", "cccc");
}
public void cancel() {
animator.cancel();
}
@Override
public void drawState(Canvas canvas) {
//绘制背景(还原纯色)
drawBackground(canvas);
//绘制小圆
drawCircle(canvas);
}
private void drawCircle(Canvas canvas) {
//绘制小圆(坐标、自身半径)核心算法哦
//得到每个小圆中间的间隔角度
float rotationAngle = (float) (2 * Math.PI / mCircleColors.length);
for (int i = 0; i < mCircleColors.length; i++) {
/**
* x=r*cos(a)
* y=r*sin(a)
*/
double angle = i * rotationAngle + mCurrentRotationAngle;
float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
mPaint.setColor(mCircleColors[i]);
canvas.drawCircle(cx, cy, mCircleRadius, mPaint);
}
}
private void drawBackground(Canvas canvas) {
//擦黑板
canvas.drawColor(mSplashBgColor);
}
}
/**
* 小球聚合动画
*/
private class MergingState extends SplashState {
private ValueAnimator animator;
public MergingState() {
//小圆的坐标-->大圆的旋转读书(0~2π)、半径
animator = ValueAnimator.ofFloat(0, mRoatationRadius);
//设置线性插值器---弹射效果
animator.setInterpolator(new OvershootInterpolator(10f));
//计算时间
animator.setDuration(mSplashDuration / 2);//++
//设置监听
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//不断修改大圆半径
mCurrentRotationRadius = (Float) animation.getAnimatedValue();
// Log.i("wxh",mCurrentRota);
//提醒view重新绘制onDraw
postInvalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//开启下一个动画
mState = new ExpandingState();
}
});
//反向计算
animator.reverse();
}
@Override
public void drawState(Canvas canvas) {
//绘制背景(还原纯色)
drawBackground(canvas);
//绘制小圆
drawCircle(canvas);
}
private void drawCircle(Canvas canvas) {
//绘制小圆(坐标、自身半径)核心算法哦
//得到每个小圆中间的间隔角度
float rotationAngle = (float) (2 * Math.PI / mCircleColors.length);
for (int i = 0; i < mCircleColors.length; i++) {
/**
* x=r*cos(a)
* y=r*sin(a)
*/
double angle = i * rotationAngle + mCurrentRotationAngle;
float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
mPaint.setColor(mCircleColors[i]);
canvas.drawCircle(cx, cy, mCircleRadius, mPaint);
}
}
private void drawBackground(Canvas canvas) {
//擦黑板
canvas.drawColor(mSplashBgColor);
}
}
/**
* 水波纹的而空心扩散动画
*/
private class ExpandingState extends SplashState {
private ValueAnimator animator;
public ExpandingState() {
//>计算某个时刻空心圆的半径(0~w*w+h*h开方除二)、半径
animator = ValueAnimator.ofFloat(0, mDiagonalDist);
//设置线性插值器---加速器
animator.setInterpolator(new AccelerateInterpolator());
//计算时间
animator.setDuration(mSplashDuration / 2);//++
//设置监听
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//空心圆当前的半径
mHoleRadius = (Float) animation.getAnimatedValue();
// Log.i("wxh",mCurrentRota);
//提醒view重新绘制onDraw
postInvalidate();
}
});
//反向计算
animator.start();
}
@Override
public void drawState(Canvas canvas) {
//绘制背景(绘制空心圆背景)
drawBackground(canvas);
}
private void drawBackground(Canvas canvas) {
if (mHoleRadius > 0f) {
//画笔的宽度=对角线/2-空心部分的半径
float strokeWidth = mDiagonalDist - mHoleRadius;
//绘制空心圆(半径,画笔宽度)
float radius = mHoleRadius + strokeWidth / 2;
mPaintBackground.setStrokeWidth(strokeWidth);
canvas.drawCircle(mCenterX, mCenterY, radius, mPaintBackground);
} else {
//擦黑板
canvas.drawColor(mSplashBgColor);
}
}
}
}