android 路径动画制作

1、前言

             今天项目要用到一个类似微信发送么么哒,那种屏幕飘表情的功能,所以分析研究了一下,用到的技术应该是路径动画,不知道这样就正不正确,反正就是画一个路径线,然后对象根据这个路径去运动。所以就叫他路径动画了。

路径动画要首先要解决的问题就是怎么画这个路径?然后路径画出来后怎么取路径上的所有点的坐标值?

       这里解决这两个问题就看一个类PathMeasure 这个类接收一个path对象,然后可以根据pathMeasure.getPosTan()可以得到长度比例的坐标值。这两个问题就直接搞定了。用path画一个路径然后取点,动态移动对象,就变成了路径动画了。是不是很简单。


2、看效果




3、核心代码


[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 撒花 
  3.  *  
  4.  * @author yd 
  5.  * 
  6.   
  7.  用到的知识点: 
  8.     1、android属性动画 
  9.     2、Path路径绘制 
  10.     3、贝塞尔曲线 
  11.  *  
  12.  *  
  13.  * 
  14.  * 
  15.  * 
  16.  * 
  17.  * 
  18.  * 
  19.  */  
  20. public class FllowerAnimation extends View implements AnimatorUpdateListener {  
  21.   
  22.     /** 
  23.      * 动画改变的属性值 
  24.      */  
  25.     private float phase1 = 0f;  
  26.     private float phase2 = 0f;  
  27.     private float phase3 = 0f;  
  28.   
  29.     /** 
  30.      * 小球集合 
  31.      */  
  32.     private List<Fllower> fllowers1 = new ArrayList<Fllower>();  
  33.     private List<Fllower> fllowers2 = new ArrayList<Fllower>();  
  34.     private List<Fllower> fllowers3 = new ArrayList<Fllower>();  
  35.   
  36.     /** 
  37.      * 动画播放的时间 
  38.      */  
  39.     private int time = 4000;  
  40.     /** 
  41.      * 动画间隔 
  42.      */  
  43.     private int delay = 500;  
  44.   
  45.     /** 
  46.      * 资源ID 
  47.      */  
  48. //  private int resId = R.drawable.fllower_love;  
  49.   
  50.     public FllowerAnimation(Context context) {  
  51.         super(context);  
  52.         init(context);  
  53. //      this.resId = resId;  
  54.     }  
  55.   
  56.     @SuppressWarnings("deprecation")  
  57.     private void init(Context context) {  
  58.         WindowManager wm = (WindowManager) context  
  59.                 .getSystemService(Context.WINDOW_SERVICE);  
  60.         width = wm.getDefaultDisplay().getWidth();  
  61.         height = (int) (wm.getDefaultDisplay().getHeight() * 3 / 2f);  
  62.   
  63.         mPaint = new Paint();  
  64.         mPaint.setAntiAlias(true);  
  65.         mPaint.setStrokeWidth(2);  
  66.         mPaint.setColor(Color.BLUE);  
  67.         mPaint.setStyle(Style.STROKE);  
  68.   
  69.         pathMeasure = new PathMeasure();  
  70.   
  71.         builderFollower(fllowerCount, fllowers1);  
  72.         builderFollower(fllowerCount , fllowers2);  
  73.         builderFollower(fllowerCount , fllowers3);  
  74.   
  75.     }  
  76.   
  77.     /** 
  78.      * 宽度 
  79.      */  
  80.     private int width = 0;  
  81.     /** 
  82.      * 高度 
  83.      */  
  84.     private int height = 0;  
  85.   
  86.     /** 
  87.      * 曲线高度个数分割 
  88.      */  
  89.     private int quadCount = 10;  
  90.     /** 
  91.      * 曲度 
  92.      */  
  93.     private float intensity = 0.2f;  
  94.   
  95.     /** 
  96.      * 第一批个数 
  97.      */  
  98.     private int fllowerCount = 4;  
  99.   
  100.     /** 
  101.      * 创建花 
  102.      */  
  103.     private void builderFollower(int count, List<Fllower> fllowers) {  
  104.   
  105.         int max = (int) (width * 3 / 4f);  
  106.         int min = (int) (width / 4f);  
  107.         Random random = new Random();  
  108.         for (int i = 0; i < count; i++) {  
  109.             int s = random.nextInt(max) % (max - min + 1) + min;  
  110.             Path path = new Path();  
  111.             CPoint CPoint = new CPoint(s, 0);  
  112.             List<CPoint> points = builderPath(CPoint);  
  113.             drawFllowerPath(path, points);  
  114.             Fllower fllower = new Fllower();  
  115.             fllower.setPath(path);  
  116.             fllowers.add(fllower);  
  117.         }  
  118.   
  119.     }  
  120.   
  121.     /** 
  122.      * 画曲线 
  123.      * @param path 
  124.      * @param points 
  125.      */  
  126.     private void drawFllowerPath(Path path, List<CPoint> points) {  
  127.         if (points.size() > 1) {  
  128.             for (int j = 0; j < points.size(); j++) {  
  129.   
  130.                 CPoint point = points.get(j);  
  131.   
  132.                 if (j == 0) {  
  133.                     CPoint next = points.get(j + 1);  
  134.                     point.dx = ((next.x - point.x) * intensity);  
  135.                     point.dy = ((next.y - point.y) * intensity);  
  136.                 } else if (j == points.size() - 1) {  
  137.                     CPoint prev = points.get(j - 1);  
  138.                     point.dx = ((point.x - prev.x) * intensity);  
  139.                     point.dy = ((point.y - prev.y) * intensity);  
  140.                 } else {  
  141.                     CPoint next = points.get(j + 1);  
  142.                     CPoint prev = points.get(j - 1);  
  143.                     point.dx = ((next.x - prev.x) * intensity);  
  144.                     point.dy = ((next.y - prev.y) * intensity);  
  145.                 }  
  146.   
  147.                 // create the cubic-spline path  
  148.                 if (j == 0) {  
  149.                     path.moveTo(point.x, point.y);  
  150.                 } else {  
  151.                     CPoint prev = points.get(j - 1);  
  152.                     path.cubicTo(prev.x + prev.dx, (prev.y + prev.dy),  
  153.                             point.x - point.dx, (point.y - point.dy),  
  154.                             point.x, point.y);  
  155.                 }  
  156.             }  
  157.         }  
  158.     }  
  159.   
  160.     /** 
  161.      * 曲线摇摆的幅度 
  162.      */  
  163.     private int range = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70, getResources().getDisplayMetrics());  
  164.   
  165.     /** 
  166.      * 画路径 
  167.      *  
  168.      * @param point 
  169.      * @return 
  170.      */  
  171.     private List<CPoint> builderPath(CPoint point) {  
  172.         List<CPoint> points = new ArrayList<CPoint>();  
  173.         Random random = new Random();  
  174.         for (int i = 0; i < quadCount; i++) {  
  175.             if (i == 0) {  
  176.                 points.add(point);  
  177.             } else {  
  178.                 CPoint tmp = new CPoint(00);  
  179.                 if (random.nextInt(100) % 2 == 0) {  
  180.                     tmp.x = point.x + random.nextInt(range);  
  181.                 } else {  
  182.                     tmp.x = point.x - random.nextInt(range);  
  183.                 }  
  184.                 tmp.y = (int) (height / (float) quadCount * i);  
  185.                 points.add(tmp);  
  186.             }  
  187.         }  
  188.         return points;  
  189.     }  
  190.   
  191.     /** 
  192.      * 画笔 
  193.      */  
  194.     private Paint mPaint;  
  195.   
  196.     /** 
  197.      * 测量路径的坐标位置 
  198.      */  
  199.     private PathMeasure pathMeasure = null;  
  200.   
  201.     @Override  
  202.     protected void onDraw(Canvas canvas) {  
  203.         super.onDraw(canvas);  
  204.   
  205.         drawFllower(canvas, fllowers1);  
  206.         drawFllower(canvas, fllowers2);  
  207.         drawFllower(canvas, fllowers3);  
  208.   
  209.     }  
  210.   
  211.     /** 
  212.      * 高度往上偏移量,把开始点移出屏幕顶部 
  213.      */  
  214.     private float dy = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40, getResources().getDisplayMetrics());  
  215.       
  216.     /** 
  217.      *  
  218.      * @param canvas 
  219.      * @param fllowers 
  220.      */  
  221.     private void drawFllower(Canvas canvas, List<Fllower> fllowers) {  
  222.         for (Fllower fllower : fllowers) {  
  223.             float[] pos = new float[2];  
  224.             canvas.drawPath(fllower.getPath(),mPaint);  
  225.             pathMeasure.setPath(fllower.getPath(), false);  
  226.             pathMeasure.getPosTan(height * fllower.getValue(), pos, null);  
  227.             canvas.drawCircle(pos[0], pos[1], 10, mPaint);  
  228. //          Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);  
  229. //          canvas.drawBitmap(bitmap, pos[0], pos[1] - dy, null);  
  230. //          bitmap.recycle();  
  231.         }  
  232.     }  
  233.   
  234.     public void startAnimation() {  
  235.         ObjectAnimator mAnimator1 = ObjectAnimator.ofFloat(this"phase1", 0f,  
  236.                 1f);  
  237.         mAnimator1.setDuration(time);  
  238.         mAnimator1.addUpdateListener(this);  
  239.         mAnimator1.start();  
  240.         mAnimator1.setInterpolator(new AccelerateInterpolator(1f));  
  241.   
  242.         ObjectAnimator mAnimator2 = ObjectAnimator.ofFloat(this"phase2", 0f,  
  243.                 1f);  
  244.         mAnimator2.setDuration(time);  
  245.         mAnimator2.addUpdateListener(this);  
  246.         mAnimator2.start();  
  247.         mAnimator2.setInterpolator(new AccelerateInterpolator(1f));  
  248.         mAnimator2.setStartDelay(delay);  
  249.   
  250.         ObjectAnimator mAnimator3 = ObjectAnimator.ofFloat(this"phase3", 0f,  
  251.                 1f);  
  252.         mAnimator3.setDuration(time);  
  253.         mAnimator3.addUpdateListener(this);  
  254.         mAnimator3.start();  
  255.         mAnimator3.setInterpolator(new AccelerateInterpolator(1f));  
  256.         mAnimator3.setStartDelay(delay * 2);  
  257.     }  
  258.   
  259.     /** 
  260.      * 跟新小球的位置 
  261.      *  
  262.      * @param value 
  263.      * @param fllowers 
  264.      */  
  265.     private void updateValue(float value, List<Fllower> fllowers) {  
  266.         for (Fllower fllower : fllowers) {  
  267.             fllower.setValue(value);  
  268.         }  
  269.     }  
  270.   
  271.     /** 
  272.      * 动画改变回调 
  273.      */  
  274.     @Override  
  275.     public void onAnimationUpdate(ValueAnimator arg0) {  
  276.   
  277.         updateValue(getPhase1(), fllowers1);  
  278.         updateValue(getPhase2(), fllowers2);  
  279.         updateValue(getPhase3(), fllowers3);  
  280.         Log.i(tag, getPhase1() + "");  
  281.         invalidate();  
  282.     }  
  283.   
  284.     public float getPhase1() {  
  285.         return phase1;  
  286.     }  
  287.   
  288.     public void setPhase1(float phase1) {  
  289.         this.phase1 = phase1;  
  290.     }  
  291.   
  292.     public float getPhase2() {  
  293.         return phase2;  
  294.     }  
  295.   
  296.     public void setPhase2(float phase2) {  
  297.         this.phase2 = phase2;  
  298.     }  
  299.   
  300.     public float getPhase3() {  
  301.         return phase3;  
  302.     }  
  303.   
  304.     public void setPhase3(float phase3) {  
  305.         this.phase3 = phase3;  
  306.     }  
  307.   
  308.     private String tag = this.getClass().getSimpleName();  
  309.   
  310.     private class CPoint {  
  311.   
  312.         public float x = 0f;  
  313.         public float y = 0f;  
  314.   
  315.         /** x-axis distance */  
  316.         public float dx = 0f;  
  317.   
  318.         /** y-axis distance */  
  319.         public float dy = 0f;  
  320.   
  321.         public CPoint(float x, float y) {  
  322.             this.x = x;  
  323.             this.y = y;  
  324.         }  
  325.     }  
  326.   
  327. }  

4、项目地址

http://download.csdn.net/detail/hxc2008q/8473053

转自:http://blog.csdn.net/spring_he/article/details/44064607

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值