Android实现炫酷SVG动画效果

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


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


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

                                        


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

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


   
   
  1. <svg xmlns=“http://www.w3.org/2000/svg” id=“svg” class=“svg” viewBox=“0 0 960 480” preserveAspectRatio=“xMinYMin meet”>
  2. <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>
  3. <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>
  4. <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>
  5. <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>
  6. <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>
  7. </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. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3. xmlns:android= "http://schemas.android.com/apk/res/android"
  4. android:orientation= "vertical"
  5. android:background= "#ff0000"
  6. android:layout_width= "fill_parent"
  7. android:layout_height= "fill_parent">
  8. <com.example.kaiyicky.myapplication.PathView
  9. xmlns:app= "http://schemas.android.com/apk/res-auto"
  10. android:id= "@+id/pathView"
  11. android:layout_width= "match_parent"
  12. android:layout_height= "match_parent"
  13. app:pathColor= "@android:color/white"
  14. app:svg= "@raw/ironman_white"
  15. app:pathWidth= "5"/>
  16. </LinearLayout>

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


然后来看Activity里面:


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

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

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



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


最后是源码下载地址:http://download.csdn.net/detail/kangaroo835127729/9016349


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


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

一个是SVG控件类:


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


转自:https://blog.csdn.net/crazy__chen/article/details/47728241

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值