前言
简单模仿了下Android的呼吸动画,实现比较简单,很多细节还可以调整,另外如果动画更复杂,建议直接通过lottie实现。
实现
继承FramLayout 创建一个动画类,代码如下
public class AvatarFrame extends FrameLayout {
private float cx;
private float cy;
private float mStartRadius;
private float outsideRadius;
private float middleRadius;
private float insideRadius;
private Paint outsidePaint;
private Paint middlePaint;
private Paint insidePaint;
private Paint strokePaint;
private float layerWidth;
private float strokeWidth;
private float extraWidth;
public AvatarFrame(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public AvatarFrame(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public AvatarFrame(@NonNull Context context) {
this(context,null);
}
private void init(){
setWillNotDraw(false);
strokeWidth = convertDpToPx(3);
strokePaint = new Paint();
strokePaint.setAntiAlias(true);
strokePaint.setStrokeWidth(convertDpToPx(3));
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setColor(Color.BLUE);
outsidePaint = new Paint();
outsidePaint.setAntiAlias(true);
outsidePaint.setColor(Color.parseColor("#FF5B26"));
outsidePaint.setAlpha(76);
middlePaint = new Paint();
middlePaint.setAntiAlias(true);
middlePaint.setColor(Color.RED);
middlePaint.setAlpha(140);
insidePaint = new Paint();
insidePaint.setAntiAlias(true);
insidePaint.setColor(Color.parseColor("#FF5B26"));
insidePaint.setAlpha(76);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
cx = (float) getWidth()/2;
cy = (float)getHeight()/2;
extraWidth = getPaddingLeft() - strokeWidth;
layerWidth = extraWidth / 3;
mStartRadius = (float) getWidth()/2 - extraWidth;
}
@Override
protected void onDraw(Canvas canvas) {
if(!isClear){
canvas.drawCircle(cx,cy,insideRadius,insidePaint);
canvas.drawCircle(cx,cy,middleRadius,middlePaint);
canvas.drawCircle(cx,cy,outsideRadius,outsidePaint);
canvas.drawCircle(cx,cy,mStartRadius - strokeWidth ,strokePaint);
}
super.onDraw(canvas);
}
private void update(float percent){
isClear = false;
outsideRadius = mStartRadius + (extraWidth * percent);
middleRadius = mStartRadius + ((extraWidth - layerWidth) * percent);
insideRadius = mStartRadius + ((extraWidth - layerWidth * 2) * percent);
invalidate();
}
boolean isClear;
private void clear(){
isClear = true;
invalidate();
}
public void stopAnim(){
if(animator != null && animator.isRunning()){
animator.cancel();
}
clear();
}
private ValueAnimator animator;
public void startAnim(){
animator = ValueAnimator.ofFloat(0,1f);
animator.setDuration(500);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setRepeatCount(-1);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float percent = (float) animation.getAnimatedValue();
update(percent);
}
});
animator.start();
}
public float convertDpToPx(float dp){
return (getDefaultDisplayMetrics().density * dp );
}
public DisplayMetrics getDefaultDisplayMetrics(){
return getResources().getDisplayMetrics();
}
使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="play"
android:id="@+id/btnPlay"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="Stop"
android:id="@+id/btnStop"/>
<com.gg.AvatarFrame
android:layout_gravity="center"
android:layout_marginTop="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:id="@+id/fm_avatar">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:background="@drawable/bg_frame"
android:id="@+id/ivImage"
/>
</com.gqs.androidtest.AvatarFrame>
</LinearLayout>
mAvatarFrame = findViewById(R.id.fm_avatar);
Button button = findViewById(R.id.btnPlay);
Button btnStop = findViewById(R.id.btnStop);
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAvatarFrame.stopAnim();
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAvatarFrame.startAnim();
}
});
基本就是这样,代码很简单,就不过多介绍了
网友评论