国际惯例,先看一下效果:屏幕上手写一些文字,然后让手机按照你的笔画顺序在屏幕上画出来一模一样的文字。
分析下实现原理:写一个类复写View,捕获onTouch事件;→处理这个事件,事件发生的坐标分别存放在一个集合和一个path中,path用于实时绘制,集合用于稍后动画绘制,按下事件path.moveTo,抬起path.lineTo;→手指抬起1s内不再按下则让手机自动绘制我们的文字。
一些实现细节:
1,设置画笔的一些属性,给定颜色,给定笔尖粗细,笔尖形状,抗锯齿等。
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(STROKE_WIDTH);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setColor(PAINT_COLOR);
2,一些变量
public final float STROKE_WIDTH = 10;//笔尖宽度
public final int PAINT_COLOR = Color.GRAY;//画笔颜色
ArrayList<ArrayList<PathPoint>> lines;//存放所有线
Paint paint;
ArrayList<PathPoint> line;//一条线即手指按下到抬起一个完整路径
//ondraw中绘制用的path
Path path;
//触屏最后一次得到的点
private PathPoint point = new PathPoint(0, 0);
private boolean isTouching = false;//是不是正在用手指画
private long upTime;//手指抬起的时刻
private boolean isDrawing;//是不是在自动画
3,封装一个PathPoint类方便管理坐标
class PathPoint {
PathPoint(float x, float y) {
this.x = x;
this.y = y;
}
float x, y;
/**
* 到点p的距离
*
* @param p
* @return
*/
public double lenthToPoint(PathPoint p) {
float f = (p.x - x) * (p.x - x) + (p.y - y) * (p.y - y);
return Math.sqrt(f);
}
}
4,处理onTouch事件:主要是实时画线和储存待会儿自动画线的数据,记录手指抬起的时间,后边会做一个判断什么时候开始自动画线。
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isDrawing) return true;
PathPoint pathPoint;
pathPoint = getEventPoint(event);
if (pathPoint.lenthToPoint(point) < 1) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(pathPoint.x, pathPoint.y);
line = new ArrayList<PathPoint>();
isTouching = true;
break;
case MotionEvent.ACTION_UP:
lines.add(line);
isTouching = false;
upTime = System.currentTimeMillis();
autoDraw();
default:
path.lineTo(pathPoint.x, pathPoint.y);
break;
}
line.add(pathPoint);
invalidate();
return true;
}
5,开始自动画线
@Override
public void run() {
while (System.currentTimeMillis() - upTime < 1000) {//手指抬起够不够1s,不够返回
if (isTouching) return;
}
isDrawing = true;
Log.i("info", "你倒是画啊,线数:" + lines.size());
path = new Path();
for (int i = 0; i < lines.size(); i++) {
ArrayList<PathPoint> l = lines.get(i);
Log.i("info", "点数:" + l.size());
for (int j = 0; j < l.size(); j++) {
PathPoint p = l.get(j);
if (j == 0) path.moveTo(p.x, p.y);
else path.lineTo(p.x, p.y);
postInvalidate();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}<span style="white-space:pre"> </span>//复原
lines.clear();
line.clear();
path = new Path();
isDrawing = false;
}
完整代码:
package com.sovnem.administrator.boxmenu;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
/**
* Created by Sovnem on 2015/1/29.
*/
public class PathAnimationView extends View implements Runnable {
public final float STROKE_WIDTH = 10;//笔尖宽度
public final int PAINT_COLOR = Color.GRAY;//画笔颜色
ArrayList<ArrayList<PathPoint>> lines;//存放所有线
Paint paint;
ArrayList<PathPoint> line;//一条线即手指按下到抬起一个完整路径
//ondraw中绘制用的path
Path path;
//触屏最后一次得到的点
private PathPoint point = new PathPoint(0, 0);
private boolean isTouching = false;//是不是正在用手指画
private long upTime;//手指抬起的时刻
private boolean isDrawing;//是不是在自动画
public PathAnimationView(Context context) {
super(context);
init();
}
public PathAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PathAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void init() {
paint = new Paint();
paint.setStrokeWidth(STROKE_WIDTH);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setColor(PAINT_COLOR);
lines = new ArrayList<>();
path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isDrawing) return true;
PathPoint pathPoint;
pathPoint = getEventPoint(event);
if (pathPoint.lenthToPoint(point) < 1) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(pathPoint.x, pathPoint.y);
line = new ArrayList<PathPoint>();
isTouching = true;
break;
case MotionEvent.ACTION_UP:
lines.add(line);
isTouching = false;
upTime = System.currentTimeMillis();
autoDraw();
default:
path.lineTo(pathPoint.x, pathPoint.y);
break;
}
line.add(pathPoint);
invalidate();
return true;
}
private void autoDraw() {
new Thread(this).start();
}
@Override
public void run() {
while (System.currentTimeMillis() - upTime < 1000) {
if (isTouching) return;
}
isDrawing = true;
Log.i("info", "你倒是画啊,线数:" + lines.size());
path = new Path();
for (int i = 0; i < lines.size(); i++) {
ArrayList<PathPoint> l = lines.get(i);
Log.i("info", "点数:" + l.size());
for (int j = 0; j < l.size(); j++) {
PathPoint p = l.get(j);
if (j == 0) path.moveTo(p.x, p.y);
else path.lineTo(p.x, p.y);
postInvalidate();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
lines.clear();
line.clear();
path = new Path();
isDrawing = false;
}
private PathPoint getEventPoint(MotionEvent event) {
return new PathPoint(event.getX(), event.getY());
}
class PathPoint {
PathPoint(float x, float y) {
this.x = x;
this.y = y;
}
float x, y;
/**
* 到点p的距离
*
* @param p
* @return
*/
public double lenthToPoint(PathPoint p) {
float f = (p.x - x) * (p.x - x) + (p.y - y) * (p.y - y);
return Math.sqrt(f);
}
}
}
那么,说点更水的:
可以自己在手机上给你的手机应用写点关键文字,在上边的代码里加点方法,把得到的坐标保存到本地,数据库、文件随你,在你的引用引导页中加载这些数据,然后在一笔一笔的把字写在手机屏幕上,是不是有种电影高大上的效果。
手机上的svg动画的原理也大概如此吧,svg也是包含了一大堆点坐标,github有很多关于svg动画的项目。淘宝手机app第一次进入开场那个动画想着应该是svg之类吧,不过那个炫酷多了,有兴趣可以研究一下。
也可以把你想对女神说的话以这种方式记录出来,假装给她测试应用,不经意间show给她看。
恩。。。效率是什么东西?
以上,纯玩。
原文地址:http://blog.csdn.net/u012293381/article/details/43272171