最早在git上发现一个很酷眩的动画图标效果:
https://github.com/xuyisheng/tickplusdrawable
不得不说,国外的程序员在细节的考虑上,确实比我们要好很多,ok,今天我们就来模仿下这个:
现来看看我们的效果,别喷我,就写了个把小时,很多细节还没考虑全,代码也还没重构,希望大家能提出修改意见,thx~
gif效果不一定好,大家可以参考github的gif。
代码如下:
首先我们要来了解下原理:
1、我们首先来确定一些关键点的坐标,也就是我们要显示的图形的所有出现的顶点
2、线条的移动效果,我们使用属性动画来控制,不熟悉的朋友可以看看http://blog.csdn.net/eclipsexys/article/details/38401641,通过这个例子大家应该会对属性动画有更深的理解了
3、对于没有提供get、set方法的属性,我们通过重写Property来帮助这个属性增加get、set方法
了解了以上内容,就可以来看具体的代码了:
package com.example.yishengxu.canvas; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.util.AttributeSet; import android.util.Property; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; import java.util.List; /** * Created by yisheng.xu on 10/30/14. */ public class CanvasView extends View { private float mPaddingW; private float mPaddingH; private float mRotation; private List<PointF> mAllPoints = new ArrayList<PointF>(); private PointF mPoint0; private PointF mPoint1; private PointF mPoint2; private PointF mPoint3; private PointF mPoint4; private PointF mPoint5; private PointF mPoint6; private PointF mPoint7; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private int touchFlag = 0; public CanvasView(Context context) { super(context); } public CanvasView(Context context, AttributeSet attrs) { super(context, attrs); } public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mPaddingW = w / 4; mPaddingH = h / 4; mAllPoints.add(new PointF(mPaddingW, mPaddingH)); mAllPoints.add(new PointF(mPaddingW * 3, mPaddingH)); mAllPoints.add(new PointF(mPaddingW, mPaddingH * 2)); mAllPoints.add(new PointF(mPaddingW * 3, mPaddingH * 2)); mAllPoints.add(new PointF(mPaddingW, mPaddingH * 3)); mAllPoints.add(new PointF(mPaddingW * 3, mPaddingH * 3)); mAllPoints.add(new PointF(mPaddingW * 2, mPaddingH)); mAllPoints.add(new PointF(mPaddingW * 2, mPaddingH * 3)); initPoints(); mPaint.setColor(Color.BLUE); mPaint.setStrokeWidth(20); mPaint.setStrokeCap(Paint.Cap.ROUND); super.onSizeChanged(w, h, oldw, oldh); } private void initPoints() { mPoint0 = new PointF(mAllPoints.get(0).x, mAllPoints.get(0).y); mPoint1 = new PointF(mAllPoints.get(1).x, mAllPoints.get(1).y); mPoint2 = new PointF(mAllPoints.get(2).x, mAllPoints.get(2).y); mPoint3 = new PointF(mAllPoints.get(3).x, mAllPoints.get(3).y); mPoint4 = new PointF(mAllPoints.get(4).x, mAllPoints.get(4).y); mPoint5 = new PointF(mAllPoints.get(5).x, mAllPoints.get(5).y); mPoint6 = new PointF(); mPoint7 = new PointF(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.rotate(180 * mRotation, mPaddingW * 2, mPaddingH * 2); drawLine(canvas, mPoint0, mPoint1); drawLine(canvas, mPoint2, mPoint3); drawLine(canvas, mPoint4, mPoint5); drawLine(canvas, mPoint6, mPoint7); canvas.restore(); } private void drawLine(Canvas canvas,PointF start,PointF end) { if (start.x!=0 && end.x !=0) { canvas.drawLine(start.x, start.y, end.x, end.y, mPaint); } } @Override public boolean onTouchEvent(MotionEvent event) { if (touchFlag == 0) { animPoints(mPoint0, mAllPoints.get(2)); animPoints(mPoint4, mAllPoints.get(2)); animPoints(mPoint1, mAllPoints.get(6)); animPoints(mPoint5, mAllPoints.get(7)); touchFlag += 1; }else if (touchFlag == 1) { resetPoints(); touchFlag += 1; }else if (touchFlag == 2) { animPoints(mPoint0, mAllPoints.get(4)); animPoints(mPoint4, mAllPoints.get(0)); mPoint2 = new PointF(0, 0); mPoint3 = new PointF(0, 0); invalidate(); touchFlag += 1; } else if (touchFlag == 3) { resetPoints(); touchFlag += 1; } else { animPoints(mPoint0, mAllPoints.get(6)); animPoints(mPoint1, mAllPoints.get(3)); animPoints(mPoint5, mAllPoints.get(6)); mPoint2 = new PointF(0, 0); mPoint3 = new PointF(0, 0); invalidate(); touchFlag = 1; } return super.onTouchEvent(event); } private void resetPoints() { animPoints(mPoint0, mAllPoints.get(0)); animPoints(mPoint1, mAllPoints.get(1)); animPoints(mPoint2, mAllPoints.get(2)); animPoints(mPoint3, mAllPoints.get(3)); animPoints(mPoint4, mAllPoints.get(4)); animPoints(mPoint5, mAllPoints.get(5)); } private void animPoints(final PointF start, final PointF end) { ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() { @Override public PointF evaluate(float v, PointF o, PointF o2) { start.x = start.x + (end.x - start.x) * v; start.y = start.y + (end.y - start.y) * v; invalidate(); return null; } }, start, end); animator.setDuration(1000); animator.start(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(this, mRotationProperty, 0, 1F); animator1.setDuration(500); animator1.start(); } private Property<CanvasView, Float> mRotationProperty = new Property<CanvasView, Float>(Float.class, "rotation") { @Override public Float get(CanvasView object) { return object.mRotation; } @Override public void set(CanvasView object, Float value) { object.mRotation = value; } }; }
布局文件和主文件很简单:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="50dp" android:paddingRight="50dp" android:paddingTop="150dp" android:paddingBottom="150dp" tools:context=".MainActivity"> <view android:layout_width="wrap_content" android:layout_height="wrap_content" class="com.example.yishengxu.canvas.CanvasView" android:id="@+id/view" android:layout_alignParentStart="true" /> </RelativeLayout>
package com.example.yishengxu.canvas; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
OK,关键还是要有脑子,有idea,在现有知识的基础上,加工、创造。
现在,5.0来了,新增了Vector Drawable,以及对SVG的支持,让我们对实现更复杂的路径轨迹动画效果,有了更强大的工具。
最后,打个广告——友情链接 HZTalk~非常好的,说科技、聊电影、游戏,真独立,非客观,第三方.
以上。