国际惯例,先看一下效果:屏幕上手写一些文字,然后让手机按照你的笔画顺序在屏幕上画出来一模一样的文字。
分析下实现原理:写一个类复写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给她看。
恩。。。效率是什么东西?
以上,纯玩。
时间: 2024-10-06 16:08:03