Android实现炫酷SVG动画效果



(2)Android实现炫酷SVG动画效果



原文出处:http://blog.csdn.net/crazy__chen/article/details/47728241 

svg是目前十分流行的图像文件格式了,svg严格来说应该是一种开放标准的矢量图形语言,使用svg格式我们可以直接用代码来描绘图像,可以用任何文字处理工具打开svg图像,通过改变部分代码来使图像具有交互功能,并可以随时插入到HTML中通过浏览器(如火狐浏览器)来观看。使用svg格式可让你设计激动人心的、高分辨率的Web图形页面。


svg格式具备目前网络流行的jpg和png等格式无法具备的优势:可以任意放大图形显示,但绝不会以牺牲图像质量为代价;可在svg图像中保留可编辑和可搜寻的状态;平均来讲,svg文件比其它格式的图像文件要小很多,因而下载也很快。


我们先来看几张Android上使用SVG的效果图:


从上面的图片看到,如果我们自己来实现这样的特效,非常的麻烦,不过接下来给大家介绍一个开源控件,就可以配合SVG实现这些效果。

首先我们来了解SVG文件的格式,举个例子:

1
2
3
4
5
6
7
8
9
10
11
<svg xmlns= "http://www.w3.org/2000/svg"  id= "svg"  class= "svg"  viewBox= "0 0 960 480"  preserveAspectRatio= "xMinYMin meet" >
         <path fill= "#B4BEC8"  stroke= "#B4BEC8"  stroke-width= "2px"  stroke-miterlimit= "10"  d= "M570.14 440.2l-29.165-28.99c-7.103-8.5-6.152-36.718-6.02-40.665H425.048c.133 3.947 1.082 32.164-6.018 40.666l-29.166 28.99c-1.237 1.404-1.712 2.505-1.623 3.37h-.054c.76 7.727 6.664 6.332 13.607 6.332H558.01c6.696 0 12.412 1.27 13.493-5.56.58-.953.274-2.282-1.364-4.14z"  style= "fill-opacity: 1; stroke-opacity: 0; -webkit-transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; stroke-dasharray: 474.095184326172px, 474.095184326172px; stroke-dashoffset: 0px;" ></path>
 
         <path fill= "#C8D2DC"  stroke= "#C8D2DC"  stroke-width= "2px"  stroke-miterlimit= "10"  d= "M727.488 355.125c0 8.514-6.597 15.42-14.738 15.42h-465.5c-8.14 0-14.74-6.906-14.74-15.42V45.42c0-8.517 6.6-15.42 14.74-15.42h465.5c8.142 0 14.738 6.903 14.738 15.42v309.705z"  style= "fill-opacity: 1; stroke-opacity: 0; -webkit-transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; stroke-dasharray: 1645.18310546875px, 1645.18310546875px; stroke-dashoffset: 0px;" ></path>
 
         <path fill= "#fff"  stroke= "#C8D2DC"  stroke-width= "2px"  stroke-miterlimit= "10"  d= "M489.01 343.713c-.042-4.223 3.447-6.254 3.605-6.352-1.963-2.866-5.018-3.263-6.102-3.31-2.602-.26-5.074 1.53-6.39 1.53s-3.356-1.49-5.506-1.448c-2.836.04-5.445 1.645-6.907 4.182-2.942 5.11-.75 12.672 2.116 16.814 1.4 2.02 3.072 4.305 5.268 4.22 2.114-.08 2.913-1.362 5.467-1.362 2.556 0 3.274 1.363 5.51 1.322 2.273-.04 3.716-2.064 5.105-4.098 1.61-2.35 2.273-4.63 2.313-4.748-.05-.02-4.434-1.7-4.48-6.75M484.807 331.31c1.168-1.41 1.953-3.37 1.738-5.327-1.68.068-3.713 1.12-4.916 2.53-1.08 1.247-2.027 3.245-1.77 5.16 1.87.143 3.784-.95 4.947-2.362"  style= "fill-opacity: 1; stroke-opacity: 0; -webkit-transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; stroke-dasharray: 115.244583129883px, 115.244583129883px; stroke-dashoffset: 0px;" ></path>
 
         <path fill= "#3C4650"  stroke= "#3C4650"  stroke-width= "2px"  stroke-miterlimit= "10"  d= "M727.488 315.527V45.982c0-8.828-6.597-15.982-14.738-15.982h-465.5c-8.14 0-14.74 7.155-14.74 15.982v269.545H727.49z"  style= "fill-opacity: 1; stroke-opacity: 0; -webkit-transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; stroke-dasharray: 1547.85571289063px, 1547.85571289063px; stroke-dashoffset: 0px;" ></path>
 
         <path fill= "#141E28"  stroke= "#141E28"  stroke-width= "2px"  stroke-miterlimit= "10"  d= "M251.2 48.887h457.205v245.52H251.2z"  style= "fill-opacity: 1; stroke-opacity: 0; -webkit-transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; transition: fill-opacity 1s ease-in-out, stroke-opacity 1s ease-in-out; stroke-dasharray: 1405.44995117188px, 1405.44995117188px; stroke-dashoffset: 0px;" ></path>
       </svg>

上面的代码很复杂,如果说它们是代码的话,但是我们可以注意到,这种书写方式,有点类似于html,都是使用标签


使用最多的标签是path,也就是路径


有的人也会想到,要实现照片上的动态效果,我们可以使用Android自带的绘图类和函数,复杂的曲线路径,我们可以使用path这个类来制定

那会不会SVG里面的path,其实也是这样,那么我们就可以将SVG中的path,对应到android,然后绘制出来就好了。


SVG里面还有各种标签:

包括line直线,circle圆,rect矩形,eliipse椭圆,polygon多边形,等等


这些只要我们有一个SVG文件,都可以将其转换成java代码

作为一个程序员,我们当然不能手动去做这个工作,那就涉及两个问题,一个是SVG的解析,一个是解析后的绘制


幸运的是,已经有人完成了这个工作,并且在Github上开源 https://github.com/geftimov/android-pathview


这篇文章将作为一个简单的例子,来使用上面的开源控件

为了解析SVG,我们需要将一个androidsvg.jar包含进我们的lib


下面我们来看这个控件的简单使用,作为一个自定义控件,我们只需要在布局文件里面添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version= "1.0"  encoding= "utf-8" ?>
<LinearLayout
     xmlns:android= "http://schemas.android.com/apk/res/android"
     android:orientation= "vertical"
     android:background= "#ff0000"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent" >
 
     <com.example.kaiyicky.myapplication.PathView
         xmlns:app= "http://schemas.android.com/apk/res-auto"
         android:id= "@+id/pathView"
         android:layout_width= "match_parent"
         android:layout_height= "match_parent"
         app:pathColor= "@android:color/white"
         app:svg= "@raw/ironman_white"
         app:pathWidth= "5" />
</LinearLayout>

其实app:svg指定了一个SVG文件,我们可以把这个文章放在raw目录下面

blob.png

然后来看Activity里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MainActivity extends FragmentActivity {
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 
         final PathView pathView = (PathView) findViewById(R.id.pathView);
//        final Path path = makeConvexArrow(50, 100);
//        pathView.setPath(path);
         pathView.setFillAfter( true );
         pathView.useNaturalColors();
         pathView.setOnClickListener( new  View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 pathView.getPathAnimator().
                         delay(100).
                         duration(1500).
                         interpolator( new  AccelerateDecelerateInterpolator()).
                         start();
             }
         });
     }
 
     private Path makeConvexArrow(float length, float height) {
         final Path path =  new  Path();
         path.moveTo(0.0f, 0.0f);
         path.lineTo(length / 4f, 0.0f);
         path.lineTo(length, height / 2.0f);
         path.lineTo(length / 4f, height);
         path.lineTo(0.0f, height);
         path.lineTo(length * 3f / 4f, height / 2f);
         path.lineTo(0.0f, 0.0f);
         path.close();
         return  path;
     }
 
}

看到注释的部分,调用了makeConvexArraw()方法,如果我们没有在xml文件里面指定svg文件,我们也可以在代码中手动指定绘制的路径


让代码跑起来,点击屏幕,于是就实现了以下效果:

20150817175939593.gif

就是这么简单,至于这么制作SVG文件,大家可以找美工帮忙,使用ps和ai,可以将图片转换成SVG




整个过程有两个类,一个是SVG解析工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
  * Util class to init and get paths from svg.
  */
public class SvgUtils {
     /**
      * It is for logging purposes.
      */
     private static final String LOG_TAG =  "SVGUtils" ;
     /**
      * All the paths with their attributes from the svg.
      */
     private final List<SvgPath> mPaths =  new  ArrayList<SvgPath>();
     /**
      * The paint provided from the view.
      */
     private final Paint mSourcePaint;
     /**
      * The init svg.
      */
     private SVG mSvg;
 
     /**
      * Init the SVGUtils with a paint for coloring.
      *
      * @param sourcePaint - the paint for the coloring.
      */
     public SvgUtils(final Paint sourcePaint) {
         mSourcePaint = sourcePaint;
     }
 
     /**
      * Loading the svg from the resources.
      *
      * @param context     Context object to get the resources.
      * @param svgResource int resource id of the svg.
      */
     public void load(Context context, int svgResource) {
         if  (mSvg !=  null return ;
         try  {
             mSvg = SVG.getFromResource(context, svgResource);
             mSvg.setDocumentPreserveAspectRatio(PreserveAspectRatio.UNSCALED);
         catch  (SVGParseException e) {
             Log.e(LOG_TAG,  "Could not load specified SVG resource" , e);
         }
     }
 
     /**
      * Draw the svg to the canvas.
      *
      * @param canvas The canvas to be drawn.
      * @param width  The width of the canvas.
      * @param height The height of the canvas.
      */
     public void drawSvgAfter(final Canvas canvas, final int width, final int height) {
         final float strokeWidth = mSourcePaint.getStrokeWidth();
         rescaleCanvas(width, height, strokeWidth, canvas);
     }
 
     /**
      * Render the svg to canvas and catch all the paths while rendering.
      *
      * @param width  - the width to scale down the view to,
      * @param height - the height to scale down the view to,
      * @return All the paths from the svg.
      */
     public List<SvgPath> getPathsForViewport(final int width, final int height) {
         final float strokeWidth = mSourcePaint.getStrokeWidth();
         Canvas canvas =  new  Canvas() {
             private final Matrix mMatrix =  new  Matrix();
 
             @Override
             public int getWidth() {
                 return  width;
             }
 
             @Override
             public int getHeight() {
                 return  height;
             }
 
             @Override
             public void drawPath(Path path, Paint paint) {
                 Path dst =  new  Path();
 
                 //noinspection deprecation
                 getMatrix(mMatrix);
                 path.transform(mMatrix, dst);
                 paint.setAntiAlias( true );
                 paint.setStyle(Paint.Style.STROKE);
                 paint.setStrokeWidth(strokeWidth);
                 mPaths.add( new  SvgPath(dst, paint));
             }
         };
 
         rescaleCanvas(width, height, strokeWidth, canvas);
 
         return  mPaths;
     }
 
     /**
      * Rescale the canvas with specific width and height.
      *
      * @param width       The width of the canvas.
      * @param height      The height of the canvas.
      * @param strokeWidth Width of the path to add to scaling.
      * @param canvas      The canvas to be drawn.
      */
     private void rescaleCanvas(int width, int height, float strokeWidth, Canvas canvas) {
         final RectF viewBox = mSvg.getDocumentViewBox();
 
         final float scale = Math.min(width
                         / (viewBox.width() + strokeWidth),
                 height / (viewBox.height() + strokeWidth));
 
         canvas.translate((width - viewBox.width() * scale) / 2.0f,
                 (height - viewBox.height() * scale) / 2.0f);
         canvas.scale(scale, scale);
 
         mSvg.renderToCanvas(canvas);
     }
 
     /**
      * Path with bounds for scalling , length and paint.
      */
     public static class SvgPath {
         /**
          * Region of the path.
          */
         private static final Region REGION =  new  Region();
         /**
          * This is done for clipping the bounds of the path.
          */
         private static final Region MAX_CLIP =
                 new  Region(Integer.MIN_VALUE, Integer.MIN_VALUE,
                         Integer.MAX_VALUE, Integer.MAX_VALUE);
         /**
          * The path itself.
          */
         final Path path;
         /**
          * The paint to be drawn later.
          */
         final Paint paint;
         /**
          * The length of the path.
          */
         final float length;
         /**
          * The bounds of the path.
          */
         final Rect bounds;
         /**
          * The measure of the path, we can use it later to get segment of it.
          */
         final PathMeasure measure;
 
         /**
          * Constructor to add the path and the paint.
          *
          * @param path  The path that comes from the rendered svg.
          * @param paint The result paint.
          */
         SvgPath(Path path, Paint paint) {
             this .path = path;
             this .paint = paint;
 
             measure =  new  PathMeasure(path,  false );
             this .length = measure.getLength();
 
             REGION.setPath(path, MAX_CLIP);
             bounds = REGION.getBounds();
         }
     }
}

一个是SVG控件类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
/**
  * PathView is an View that animate paths.
  */
public class PathView extends View {
     /**
      * Logging tag.
      */
     public static final String LOG_TAG =  "PathView" ;
     /**
      * The paint for the path.
      */
     private Paint paint =  new  Paint(Paint.ANTI_ALIAS_FLAG);
     /**
      * Utils to catch the paths from the svg.
      */
     private final SvgUtils svgUtils =  new  SvgUtils(paint);
     /**
      * All the paths provided to the view. Both from Path and Svg.
      */
     private List<SvgUtils.SvgPath> paths =  new  ArrayList<SvgUtils.SvgPath>(0);
     /**
      * This is a lock before the view is redrawn
      * or resided it must be synchronized with this object.
      */
     private final Object mSvgLock =  new  Object();
     /**
      * Thread for working with the object above.
      */
     private Thread mLoader;
 
     /**
      * The svg image from the raw directory.
      */
     private int svgResourceId;
     /**
      * Object that build the animation for the path.
      */
     private AnimatorBuilder animatorBuilder;
     /**
      * The progress of the drawing.
      */
     private float progress = 0f;
 
     /**
      * If the used colors are from the svg or from the set color.
      */
     private boolean naturalColors;
     /**
      * If the view is filled with its natural colors after path drawing.
      */
     private boolean fillAfter;
     /**
      * The width of the view.
      */
     private int width;
     /**
      * The height of the view.
      */
     private int height;
 
     /**
      * Default constructor.
      *
      * @param context The Context of the application.
      */
     public PathView(Context context) {
         this (context,  null );
     }
 
     /**
      * Default constructor.
      *
      * @param context The Context of the application.
      * @param attrs   attributes provided from the resources.
      */
     public PathView(Context context, AttributeSet attrs) {
         this (context, attrs, 0);
     }
 
     /**
      * Default constructor.
      *
      * @param context  The Context of the application.
      * @param attrs    attributes provided from the resources.
      * @param defStyle Default style.
      */
     public PathView(Context context, AttributeSet attrs, int defStyle) {
         super (context, attrs, defStyle);
         paint.setStyle(Paint.Style.STROKE);
         getFromAttributes(context, attrs);
     }
 
     /**
      * Get all the fields from the attributes .
      *
      * @param context The Context of the application.
      * @param attrs   attributes provided from the resources.
      */
     private void getFromAttributes(Context context, AttributeSet attrs) {
         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PathView);
         try  {
             if  (a !=  null ) {
                 paint.setColor(a.getColor(R.styleable.PathView_pathColor, 0xff00ff00));
                 paint.setStrokeWidth(a.getFloat(R.styleable.PathView_pathWidth, 8.0f));
                 svgResourceId = a.getResourceId(R.styleable.PathView_svg, 0);
             }
         } finally {
             if  (a !=  null ) {
                 a.recycle();
             }
         }
     }
 
     /**
      * Set paths to be drawn and animated.
      *
      * @param paths - Paths that can be drawn.
      */
     public void setPaths(final List<Path> paths) {
         for  (Path path : paths) {
             this .paths.add( new  SvgUtils.SvgPath(path, paint));
         }
         synchronized (mSvgLock) {
             updatePathsPhaseLocked();
         }
     }
 
     /**
      * Set path to be drawn and animated.
      *
      * @param path - Paths that can be drawn.
      */
     public void setPath(final Path path) {
         paths.add( new  SvgUtils.SvgPath(path, paint));
         synchronized (mSvgLock) {
             updatePathsPhaseLocked();
         }
     }
 
     /**
      * Animate this property. It is the percentage of the path that is drawn.
      * It must be [0,1].
      *
      * @param percentage float the percentage of the path.
      */
     public void setPercentage(float percentage) {
         if  (percentage < 0.0f || percentage > 1.0f) {
             throw  new  IllegalArgumentException( "setPercentage not between 0.0f and 1.0f" );
         }
         progress = percentage;
         synchronized (mSvgLock) {
             updatePathsPhaseLocked();
         }
         invalidate();
     }
 
     /**
      * This refreshes the paths before draw and resize.
      */
     private void updatePathsPhaseLocked() {
         final int count = paths.size();
         for  (int i = 0; i < count; i++) {
             SvgUtils.SvgPath svgPath = paths.get(i);
             svgPath.path.reset();
             svgPath.measure.getSegment(0.0f, svgPath.length * progress, svgPath.path,  true );
             // Required only for Android 4.4 and earlier
             svgPath.path.rLineTo(0.0f, 0.0f);
         }
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super .onDraw(canvas);
 
         synchronized (mSvgLock) {
             canvas.save();
             canvas.translate(getPaddingLeft(), getPaddingTop());
             final int count = paths.size();
             for  (int i = 0; i < count; i++) {
                 final SvgUtils.SvgPath svgPath = paths.get(i);
                 final Path path = svgPath.path;
                 final Paint paint1 = naturalColors ? svgPath.paint : paint;
                 canvas.drawPath(path, paint1);
             }
             fillAfter(canvas);
             canvas.restore();
         }
     }
 
     /**
      * If there is svg , the user called setFillAfter(true) and the progress is finished.
      *
      * @param canvas Draw to this canvas.
      */
     private void fillAfter(final Canvas canvas) {
         if  (svgResourceId != 0 && fillAfter && progress == 1f) {
             svgUtils.drawSvgAfter(canvas, width, height);
         }
     }
 
     @Override
     protected void onSizeChanged(final int w, final int h, int oldw, int oldh) {
         super .onSizeChanged(w, h, oldw, oldh);
 
         if  (mLoader !=  null ) {
             try  {
                 mLoader.join();
             catch  (InterruptedException e) {
                 Log.e(LOG_TAG,  "Unexpected error" , e);
             }
         }
         if  (svgResourceId != 0) {
             mLoader =  new  Thread( new  Runnable() {
                 @Override
                 public void run() {
 
                     svgUtils.load(getContext(), svgResourceId);
 
                     synchronized (mSvgLock) {
                         width = w - getPaddingLeft() - getPaddingRight();
                         height = h - getPaddingTop() - getPaddingBottom();
                         paths = svgUtils.getPathsForViewport(width, height);
                         updatePathsPhaseLocked();
                     }
                 }
             },  "SVG Loader" );
             mLoader.start();
         }
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super .onMeasure(widthMeasureSpec, heightMeasureSpec);
         if  (svgResourceId != 0) {
             int widthSize = MeasureSpec.getSize(widthMeasureSpec);
             int heightSize = MeasureSpec.getSize(heightMeasureSpec);
             setMeasuredDimension(widthSize, heightSize);
             return ;
         }
 
         int desiredWidth = 0;
         int desiredHeight = 0;
         final float strokeWidth = paint.getStrokeWidth() / 2;
         for  (SvgUtils.SvgPath path : paths) {
             desiredWidth += path.bounds.left + path.bounds.width() + strokeWidth;
             desiredHeight += path.bounds.top + path.bounds.height() + strokeWidth;
         }
         int widthSize = MeasureSpec.getSize(widthMeasureSpec);
         int heightSize = MeasureSpec.getSize(heightMeasureSpec);
         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         int heightMode = MeasureSpec.getMode(widthMeasureSpec);
 
         int measuredWidth, measuredHeight;
 
         if  (widthMode == MeasureSpec.AT_MOST) {
             measuredWidth = desiredWidth;
         else  {
             measuredWidth = widthSize;
         }
 
         if  (heightMode == MeasureSpec.AT_MOST) {
             measuredHeight = desiredHeight;
         else  {
             measuredHeight = heightSize;
         }
 
         setMeasuredDimension(measuredWidth, measuredHeight);
     }
 
     /**
      * If the real svg need to be drawn after the path animation.
      *
      * @param fillAfter - boolean if the view needs to be filled after path animation.
      */
     public void setFillAfter(final boolean fillAfter) {
         this .fillAfter = fillAfter;
     }
 
     /**
      * If you want to use the colors from the svg.
      */
     public void useNaturalColors() {
         naturalColors =  true ;
     }
 
     /**
      * Animator for the paths of the view.
      *
      * @return The AnimatorBuilder to build the animation.
      */
     public AnimatorBuilder getPathAnimator() {
         if  (animatorBuilder ==  null ) {
             animatorBuilder =  new  AnimatorBuilder( this );
         }
         return  animatorBuilder;
     }
 
     /**
      * Get the path color.
      *
      * @return The color of the paint.
      */
     public int getPathColor() {
         return  paint.getColor();
     }
 
     /**
      * Set the path color.
      *
      * @param color -The color to set to the paint.
      */
     public void setPathColor(final int color) {
         paint.setColor(color);
     }
 
     /**
      * Get the path width.
      *
      * @return The width of the paint.
      */
     public float getPathWidth() {
         return  paint.getStrokeWidth();
     }
 
     /**
      * Set the path width.
      *
      * @param width - The width of the path.
      */
     public void setPathWidth(final float width) {
         paint.setStrokeWidth(width);
     }
 
     /**
      * Get the svg resource id.
      *
      * @return The svg raw resource id.
      */
     public int getSvgResource() {
         return  svgResourceId;
     }
 
     /**
      * Set the svg resource id.
      *
      * @param svgResource - The resource id of the raw svg.
      */
     public void setSvgResource(int svgResource) {
         svgResourceId = svgResource;
     }
 
     /**
      * Object for building the animation of the path of this view.
      */
     public static class AnimatorBuilder {
         /**
          * Duration of the animation.
          */
         private int duration = 350;
         /**
          * Interpolator for the time of the animation.
          */
         private Interpolator interpolator;
         /**
          * The delay before the animation.
          */
         private int delay = 0;
         /**
          * ObjectAnimator that constructs the animation.
          */
         private final ObjectAnimator anim;
         /**
          * Listener called before the animation.
          */
         private ListenerStart listenerStart;
         /**
          * Listener after the animation.
          */
         private ListenerEnd animationEnd;
         /**
          * Animation listener.
          */
         private PathViewAnimatorListener pathViewAnimatorListener;
 
         /**
          * Default constructor.
          *
          * @param pathView The view that must be animated.
          */
         public AnimatorBuilder(final PathView pathView) {
             anim = ObjectAnimator.ofFloat(pathView,  "percentage" , 0.0f, 1.0f);
         }
 
         /**
          * Set the duration of the animation.
          *
          * @param duration - The duration of the animation.
          * @return AnimatorBuilder.
          */
         public AnimatorBuilder duration(final int duration) {
             this .duration = duration;
             return  this ;
         }
 
         /**
          * Set the Interpolator.
          *
          * @param interpolator - Interpolator.
          * @return AnimatorBuilder.
          */
         public AnimatorBuilder interpolator(final Interpolator interpolator) {
             this .interpolator = interpolator;
             return  this ;
         }
 
         /**
          * The delay before the animation.
          *
          * @param delay - int the delay
          * @return AnimatorBuilder.
          */
         public AnimatorBuilder delay(final int delay) {
             this .delay = delay;
             return  this ;
         }
 
         /**
          * Set a listener before the start of the animation.
          *
          * @param listenerStart an interface called before the animation
          * @return AnimatorBuilder.
          */
         public AnimatorBuilder listenerStart(final ListenerStart listenerStart) {
             this .listenerStart = listenerStart;
             if  (pathViewAnimatorListener ==  null ) {
                 pathViewAnimatorListener =  new  PathViewAnimatorListener();
                 anim.addListener(pathViewAnimatorListener);
             }
             return  this ;
         }
 
         /**
          * Set a listener after of the animation.
          *
          * @param animationEnd an interface called after the animation
          * @return AnimatorBuilder.
          */
         public AnimatorBuilder listenerEnd(final ListenerEnd animationEnd) {
             this .animationEnd = animationEnd;
             if  (pathViewAnimatorListener ==  null ) {
                 pathViewAnimatorListener =  new  PathViewAnimatorListener();
                 anim.addListener(pathViewAnimatorListener);
             }
             return  this ;
         }
 
         /**
          * Starts the animation.
          */
         public void start() {
             anim.setDuration(duration);
             anim.setInterpolator(interpolator);
             anim.setStartDelay(delay);
             anim.start();
         }
 
         /**
          * Animation listener to be able to provide callbacks for the caller.
          */
         private class PathViewAnimatorListener implements Animator.AnimatorListener {
 
             @Override
             public void onAnimationStart(Animator animation) {
                 if  (listenerStart !=  null ) listenerStart.onAnimationStart();
             }
 
             @Override
             public void onAnimationEnd(Animator animation) {
                 if  (animationEnd !=  null ) animationEnd.onAnimationEnd();
             }
 
             @Override
             public void onAnimationCancel(Animator animation) {
 
             }
 
             @Override
             public void onAnimationRepeat(Animator animation) {
 
             }
         }
 
         /**
          * Called when the animation start.
          */
         public interface ListenerStart {
             /**
              * Called when the path animation start.
              */
             void onAnimationStart();
         }
 
         /**
          * Called when the animation end.
          */
         public interface ListenerEnd {
             /**
              * Called when the path animation end.
              */
             void onAnimationEnd();
         }
     }
}


源码下载:http://download.csdn.net/detail/a1961613299/9402810


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值