这是我在微博上看到的一个loading动态图, 感觉挺cute的,就拿来做了下,不过还没做完,就剩绳子动画部分了(不会写了,求大神)。
贝塞尔曲线的知识不清楚请亲们自行google,百度,不是很难。
1.先看完成后预期效果
预期效果图:
69b7d63agw1f2zshd218jg20b408cdg6.gif然而理想和现实有差距(模拟器录制比较卡,绳子也也没有实现摆动-_-||):
four.gif2.分析
结构:控件其实很简单,两个空芯圆+贝塞尔曲线+实心圆。
动画:分为小球上升,和小球下落。
3实现
自定义属性:
<resources>
<declare-styleable name="LoadingView">
<attr name="bollUpMaxHeight" format="dimension" />
<attr name="bollDownMaxHeight" format="dimension" />
<attr name="lineWidth" format="dimension" />
<attr name="circleRadius" format="dimension" />
<attr name="OtherCircleRadius" format="dimension" />
</declare-styleable>
</resources>
布局:
<com.example.administrator.myapplication.LoadingView
android:layout_width="300dp"
android:id="@+id/lv"
android:background="#3378d4"
app:bollDownMaxHeight="20dp"
app:bollUpMaxHeight="60dp"
app:circleRadius="7dp"
app:lineWidth="100dp"
app:OtherCircleRadius="3dp"
android:layout_height="300dp"
android:layout_gravity="center" />
代码:
public class LoadingView extends View {
private static final String TAG = "LoadingView";
private Paint mPaint;
private Paint circlePaint;
private int bollDownMaxHeight;
private int boollUpMaxHeight;
private int topOffset;
private int mRadius;
private int oTherRadius;
private int lineWidth = 400;
private Point[] points;
private Point bcrPoint = new Point();
private Path p = new Path();
public LoadingView(Context context) {
super(context);
init(null, 0);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public LoadingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
// Load attributes
final TypedArray a = getContext().obtainStyledAttributes(
attrs, R.styleable.LoadingView, defStyle, 0);
bollDownMaxHeight = a.getDimensionPixelSize(R.styleable.LoadingView_bollDownMaxHeight, 100);
boollUpMaxHeight = a.getDimensionPixelSize(R.styleable.LoadingView_bollUpMaxHeight, 200);
lineWidth = a.getDimensionPixelSize(R.styleable.LoadingView_lineWidth, 400);
mRadius = a.getDimensionPixelSize(R.styleable.LoadingView_circleRadius, 23);
oTherRadius = a.getDimensionPixelSize(R.styleable.LoadingView_OtherCircleRadius,12);
a.recycle();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.WHITE);
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(Color.WHITE);
circlePaint.setStyle(Paint.Style.FILL);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
initPoint();
}
private int lineOffset;
private int circleOffset;
@Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(oTherRadius*2 + lineWidth / 2, topOffset - mRadius + circleOffset / 2, mRadius, circlePaint);
canvas.drawCircle(oTherRadius, topOffset, oTherRadius, mPaint);
//canvas.drawLine(240 + 12, topOffset, 240 + 12 + lineWidth, topOffset, mPaint);
p.reset();
p.moveTo(points[0].x, points[0].y);
p.quadTo(oTherRadius + lineWidth / 2, topOffset + lineOffset, points[1].x, points[1].y);
canvas.drawPath(p, mPaint);
canvas.drawCircle(oTherRadius*2 + lineWidth, topOffset, oTherRadius, mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(oTherRadius*3+lineWidth,bollDownMaxHeight+bollDownMaxHeight+mRadius*4);
}
//初始化贝塞尔曲线中的两个定点
private void initPoint() {
topOffset = bollDownMaxHeight+mRadius+bollDownMaxHeight;
points = new Point[2];
Point p1 = new Point();
p1.set(oTherRadius*2, topOffset);
Point p2 = new Point();
p2.set(oTherRadius*2 + lineWidth, topOffset);
points[0] = p1;
points[1] = p2;
}
private int value2;
public void show() {
final ValueAnimator va = ValueAnimator.ofInt(-boollUpMaxHeight, bollDownMaxHeight);
va.setDuration(700);
va.setInterpolator(new AccelerateDecelerateInterpolator());
//va.setRepeatCount(ValueAnimator.INFINITE);
va.setRepeatCount(100);//这里可以无限循环,注意要自己在写取消动画的方法,否则可能会内存泄漏
va.setRepeatMode(ValueAnimator.REVERSE);
value2 = -boollUpMaxHeight;
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
if (value >= value2) {
//下落
if (value >= -bollDownMaxHeight+10) {
lineOffset = value;
}
} else {
//上升
if (value >= -bollDownMaxHeight+10 && value <= bollDownMaxHeight) {
lineOffset = value;
} else {
//showLineAnim();//是否应该在此显示绳子的动画
}
}
circleOffset = value;
value2 = value;
invalidate();
}
});
va.start();
}
}
先把代码贴出来把 ,看不懂的小伙伴抱歉了,注释和分析图我会以后加上,这几天写论文也是忙里偷闲。另外,求大神指点绳子摆动的逻辑,感觉以后写这种东西要配一个数学大神!。
网友评论