這是我在微博上看到的一個(gè)loading動(dòng)態(tài)圖勘究, 感覺(jué)挺cute的龟劲,就拿來(lái)做了下截歉,不過(guò)還沒(méi)做完葫盼,就剩繩子動(dòng)畫(huà)部分了(不會(huì)寫(xiě)了向族,求大神)状土。
貝塞爾曲線的知識(shí)不清楚請(qǐng)親們自行g(shù)oogle汽抚,百度易结,不是很難精算。
1.先看完成后預(yù)期效果
預(yù)期效果圖:
然而理想和現(xiàn)實(shí)有差距(模擬器錄制比較卡瓢宦,繩子也也沒(méi)有實(shí)現(xiàn)擺動(dòng)-_-||):
2.分析
結(jié)構(gòu):控件其實(shí)很簡(jiǎn)單,兩個(gè)空芯圓+貝塞爾曲線+實(shí)心圓灰羽。
動(dòng)畫(huà):分為小球上升驮履,和小球下落。
3實(shí)現(xiàn)
自定義屬性:
<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);
}
//初始化貝塞爾曲線中的兩個(gè)定點(diǎn)
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);//這里可以無(wú)限循環(huán)廉嚼,注意要自己在寫(xiě)取消動(dòng)畫(huà)的方法玫镐,否則可能會(huì)內(nèi)存泄漏
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();//是否應(yīng)該在此顯示繩子的動(dòng)畫(huà)
}
}
circleOffset = value;
value2 = value;
invalidate();
}
});
va.start();
}
}
先把代碼貼出來(lái)把 ,看不懂的小伙伴抱歉了前鹅,注釋和分析圖我會(huì)以后加上摘悴,這幾天寫(xiě)論文也是忙里偷閑。另外舰绘,求大神指點(diǎn)繩子擺動(dòng)的邏輯蹂喻,感覺(jué)以后寫(xiě)這種東西要配一個(gè)數(shù)學(xué)大神!捂寿。