Hello,村长 😊
先看效果
实现方案
1、继承 Drawable 2、实现 Animatable
先贴上完整代码,注释中稍作解释,如有疑惑欢迎评论😊
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.util.Property;
import android.view.animation.CycleInterpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.primer.common.util.LogHelper;
import com.primer.common.util.UiHelper;
import java.util.ArrayList;
import java.util.List;
public class CommonLoginDrawable extends Drawable implements Animatable {
private List<Property<CommonLoginDrawable, Integer>> mPropertyList;
private List<ValueAnimator> mValueAnimatorList;
private static final long POINT_ANIMATION_DURATION = 800;
private Paint mPointPain;
private List<Point> mPointList;
private int mPointRadio = 8;
private int mPointDivideWidth = 30;
private int mDrawTextLeft;
private int mDrawTextBottom;
private String mDrawText = "加载中";
private Paint mTextPain;
private int mTextWidth;
private int mTextHeight;
public CommonLoginDrawable(Activity activity) {
initTextPain(activity);
initPoint();
initAnimator();
}
private void initAnimator() {
mPropertyList = new ArrayList<>();
mPropertyList.add(createProperty(PointPosition.POINT_ONE));
mPropertyList.add(createProperty(PointPosition.POINT_TOW));
mPropertyList.add(createProperty(PointPosition.POINT_THERE));
mValueAnimatorList = new ArrayList<>();
mValueAnimatorList.add(createAnimator(PropertyValuesHolder.ofInt(mPropertyList.get(PointPosition.POINT_ONE),
mDrawTextBottom - (mTextHeight / 10) * 5, mDrawTextBottom - ((mTextHeight / 10) * 3))));
mValueAnimatorList.add(createAnimator(PropertyValuesHolder.ofInt(mPropertyList.get(PointPosition.POINT_TOW),
mDrawTextBottom - (mTextHeight / 10) * 5, mDrawTextBottom - ((mTextHeight / 10) * 3))));
mValueAnimatorList.add(createAnimator(PropertyValuesHolder.ofInt(mPropertyList.get(PointPosition.POINT_THERE),
mDrawTextBottom - (mTextHeight / 10) * 5, mDrawTextBottom - ((mTextHeight / 10) * 3))));
}
private void initPoint() {
mPointList = new ArrayList<>();
mPointList.add(new Point(mDrawTextLeft + mTextWidth + mPointDivideWidth, mDrawTextBottom, mPointRadio));
mPointList.add(new Point(mDrawTextLeft + mTextWidth + mPointDivideWidth * 2, mDrawTextBottom, mPointRadio));
mPointList.add(new Point(mDrawTextLeft + mTextWidth + mPointDivideWidth * 3, mDrawTextBottom, mPointRadio));
mPointPain = new Paint();
mPointPain.setStyle(Paint.Style.FILL_AND_STROKE);
mPointPain.setColor(Color.WHITE);
mPointPain.setAntiAlias(false);
mPointPain.setStrokeCap(Paint.Cap.ROUND);
}
private void initTextPain(Activity activity) {
mTextPain = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPain.setTextSize(70);
mTextPain.setStyle(Paint.Style.FILL);
mTextPain.setColor(Color.WHITE);
mTextPain.setAntiAlias(true);
mTextPain.setStrokeWidth(7);
mTextPain.setStrokeCap(Paint.Cap.ROUND);
measureText(activity);
}
private void measureText(Activity activity) {
Rect rect = new Rect();
mTextPain.getTextBounds(mDrawText, 0, mDrawText.length(), rect);
mTextWidth = rect.width();
mTextHeight = rect.height();
LogHelper.e("mTextWidth = " + mTextWidth + " mTextHeight = " + mTextHeight);
mDrawTextLeft = UiHelper.getScreenWidth(activity) / 2 - (mTextWidth / 2) - 50;
mDrawTextBottom = UiHelper.getScreenHeight(activity) / 2 - (mTextHeight / 2);
}
private void setPointOneY(int pointY, int index) {
if (mPointList != null && mPointList.size() > index) {
mPointList.get(index).setY(pointY);
}
}
private int getPointOneY(int index) {
if (mPointList != null && mPointList.size() > index) {
mPointList.get(index).getY();
}
return 0;
}
@Override
public void draw(@NonNull Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawText(mDrawText, mDrawTextLeft, mDrawTextBottom, mTextPain);
for (Point point : mPointList) {
canvas.drawCircle(point.getX(), point.getY(), point.getRadio(), mPointPain);
}
}
@Override
public void setAlpha(int alpha) {
mTextPain.setAlpha(255);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mTextPain.setColorFilter(colorFilter);
}
@SuppressLint("WrongConstant")
@Override
public int getOpacity() {
return PixelFormat.RGBA_8888;
}
@Override
public void start() {
LogHelper.e("animator start");
if (mValueAnimatorList != null) {
for (ValueAnimator animator : mValueAnimatorList) {
animator.start();
}
}
}
@Override
public void stop() {
LogHelper.d("animator end");
if (mValueAnimatorList != null) {
for (ValueAnimator animator : mValueAnimatorList) {
animator.end();
}
}
}
@Override
public boolean isRunning() {
return mValueAnimatorList != null && mValueAnimatorList.get(PointPosition.POINT_ONE).isRunning();
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
LogHelper.e("onBoundsChange");
if (isRunning()) {
stop();
}
startAnimatorValue();
}
private void startAnimatorValue() {
if (mValueAnimatorList != null) {
Handler handler = new Handler(Looper.getMainLooper());
for (int i = 0; i < mValueAnimatorList.size(); ) {
int index = i;
LogHelper.e("index = " + index);
handler.postDelayed(new Runnable() {
@Override
public void run() {
mValueAnimatorList.get(index).start();
}
}, i * 100);
i++;
}
}
}
private ObjectAnimator createAnimator(PropertyValuesHolder pointYHolder) {
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(this, pointYHolder);
animator.setDuration(POINT_ANIMATION_DURATION);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
invalidateSelf();
}
});
animator.setInterpolator(new CycleInterpolator(ValueAnimator.RESTART));
animator.setRepeatCount(ValueAnimator.INFINITE);
start();
return animator;
}
private Property<CommonLoginDrawable, Integer> createProperty(@PointPosition int index) {
Property<CommonLoginDrawable, Integer> mRadiusProperty = new Property<CommonLoginDrawable, Integer>(Integer.class, "radius") {
@Override
public void set(CommonLoginDrawable object, Integer value) {
object.setPointOneY(value, index);
}
@Override
public Integer get(CommonLoginDrawable object) {
return object.getPointOneY(index);
}
};
return mRadiusProperty;
}
private class Point {
private int x;
private int y;
private int radio;
public Point(int x, int y, int radio) {
this.x = x;
this.y = y;
this.radio = radio;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getRadio() {
return radio;
}
public void setRadio(int radio) {
this.radio = radio;
}
}
private @interface PointPosition {
int POINT_ONE = 0;
int POINT_TOW = 1;
int POINT_THERE = 2;
}
}
作者也是初学者,如注释有误,欢迎指出,谢谢🙏
|