Preface
Studying android animation shows that svg vector animation works well. W3c has a complete introduction. Follow the api
What is SVG?
SVG refers to Scalable Vector Graphics. SVG is used to define vector-based graphics for networks SVG defines graphics in XML format The quality of SVG image will not be lost when it is enlarged or changed in size. SVG is the standard of World Wide Web Alliance SVG is integrated with W3C standards such as DOM and XSL
The History and Advantages of SVG
In January 2003, SVG 1.1 was established as the W3C standard.
Organizations involved in defining SVG include Sun Microsystems, Adobe, Apple, IBM and Kodak.
Compared with other image formats, the advantages of using SVG are:
SVG can be read and modified by many tools (such as notepad) Compared with JPEG and GIF images, SVG is smaller in size and more compressible. SVG is scalable SVG images can be printed with high quality at any resolution SVG can be enlarged without degradation of image quality Text in SVG images is optional and searchable (suitable for making maps) SVG can run with Java Technology SVG is an open standard SVG files are pure XML The main competitor of SVG is Flash.
Compared with Flash, the biggest advantage of SVG is compatibility with other standards, such as XSL and DOM. Flash is an open source private technology.
Svg format
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black"
stroke-width="2" fill="red"/>
</svg>
Svg Symbol <svg>,</svg>
<circle cx="100" cy="50" r="40" stroke="black"
stroke-width="2" fill="red"/>
Simple animation control
Here we only discuss the implementation of the client. The main point of svg is the path point of Svg Path. That's the animation point.
Effect:
1. How does path come from?
1. Using specific tools to draw vector maps, PS can also generate paths - export paths for use
2. Use the background of the picture to select the point of the specific rendering path and generate the path, recommend GIMP (ps can also be used)
For example, using GIMP, photoshop needs to download the svg plug-in.
The third problem is how to convert the SVG path to Android. The w3c defines it.
SVG Path
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
width="3.02778in" height="3.16667in"
viewBox="0 0 218 228">
<path id="Constituency"
fill="none" stroke="black" stroke-width="1"
d="M 218.00,0.00
C 218.00,0.00 218.00,228.00 218.00,228.00
218.00,228.00 0.00,228.00 0.00,228.00
0.00,228.00 0.00,0.00 0.00,0.00
0.00,0.00 218.00,0.00 218.00,0.00 Z
M 85.00,49.00
C 74.10,43.40 58.80,29.70 48.00,27.00
47.37,32.11 49.50,33.50 53.00,36.99
56.74,40.70 69.43,51.00 70.91,55.00
72.37,58.95 66.69,71.89 61.00,73.75
58.27,74.64 54.63,72.09 52.00,71.00
...
...
...
C 171.48,178.95 171.13,180.88 171.76,183.00
172.25,184.63 173.11,185.64 174.00,187.00
171.36,190.02 171.47,190.34 173.00,194.00
162.60,203.60 182.46,205.63 188.77,200.99
193.07,197.84 192.64,192.04 186.98,190.14
185.36,189.97 182.72,190.01 181.00,190.14
181.00,190.14 177.00,190.14 177.00,190.14
177.00,190.14 177.00,188.00 177.00,188.00
184.57,187.98 190.42,187.53 189.00,178.00
189.00,178.00 192.00,175.00 192.00,175.00
185.59,174.69 177.39,170.44 172.74,177.13 Z" />
</svg>
2.SVG paths are converted to points in Android that can be Paint draw s
Format:
M = moveto, Amount to android Li moveTo()
L = lineto, Amount to lineTo()Draw straight lines
H = horizontal lineto, Draw horizontal lines
V = vertical lineto, Draw vertical lines
C = curveto, Amount to android Li cubicTo()
S = smooth curveto
Q = quadratic Belzier curve
T = smooth quadratic Belzier curveto
A = elliptical Arc
Z = closepath
Here we need to convert svg file to Paint brush processing specific value. Here we use a packaged tool class on the Internet to parse path processing.
package com.gaok.ui.svgtrace.utils;
import android.graphics.Path;
import android.graphics.PointF;
public class SvgPathParser {
private static final int TOKEN_ABSOLUTE_COMMAND = 1;
private static final int TOKEN_RELATIVE_COMMAND = 2;
// Specific values or ".""-"
private static final int TOKEN_VALUE = 3;
private static final int TOKEN_EOF = 4;
private int mCurrentToken;
private PointF mCurrentPoint = new PointF();
private int mLength;
private int mIndex;
// The path string to parse
private String mPathString;
private float scale = 4f;
private float xMin;
private float xMax;
private float yMin;
private float yMax;
protected float transformX(float x) {
return x * scale;
}
protected float transformY(float y) {
return y * scale;
}
public Path parsePath(String s) {
try {
mCurrentPoint.set(Float.NaN, Float.NaN);
mPathString = s;
mIndex = 0;
mLength = mPathString.length();
PointF tempPoint1 = new PointF();
PointF tempPoint2 = new PointF();
PointF tempPoint3 = new PointF();
Path p = new Path();
p.setFillType(Path.FillType.WINDING);
boolean firstMove = true;
while (mIndex < mLength) {
char command = consumeCommand();
boolean relative = (mCurrentToken == TOKEN_RELATIVE_COMMAND);
switch (command) {
case 'M':
case 'm': {
// m instruction, equivalent to moveTo() in android
boolean firstPoint = true;
while (advanceToNextToken() == TOKEN_VALUE) {
consumeAndTransformPoint(tempPoint1, relative && mCurrentPoint.x != Float.NaN);
if (firstPoint) {
p.moveTo(tempPoint1.x, tempPoint1.y);
firstPoint = false;
if (firstMove) {
mCurrentPoint.set(tempPoint1);
firstMove = false;
}
} else {
p.lineTo(tempPoint1.x, tempPoint1.y);
}
}
mCurrentPoint.set(tempPoint1);
break;
}
case 'C':
case 'c': {
// c instruction, equivalent to cubicTo() in android
if (mCurrentPoint.x == Float.NaN) {
throw new Exception("Relative commands require current point");
}
while (advanceToNextToken() == TOKEN_VALUE) {
consumeAndTransformPoint(tempPoint1, relative);
consumeAndTransformPoint(tempPoint2, relative);
consumeAndTransformPoint(tempPoint3, relative);
p.cubicTo(tempPoint1.x, tempPoint1.y, tempPoint2.x, tempPoint2.y, tempPoint3.x, tempPoint3.y);
}
mCurrentPoint.set(tempPoint3);
break;
}
case 'L':
case 'l': {
// It is equivalent to lineTo() to draw a straight line.
if (mCurrentPoint.x == Float.NaN) {
throw new Exception("Relative commands require current point");
}
while (advanceToNextToken() == TOKEN_VALUE) {
consumeAndTransformPoint(tempPoint1, relative);
p.lineTo(tempPoint1.x, tempPoint1.y);
}
mCurrentPoint.set(tempPoint1);
break;
}
case 'H':
case 'h': {
// Draw horizontal lines
if (mCurrentPoint.x == Float.NaN) {
throw new Exception("Relative commands require current point");
}
while (advanceToNextToken() == TOKEN_VALUE) {
float x = transformX(consumeValue());
if (relative) {
x += mCurrentPoint.x;
}
p.lineTo(x, mCurrentPoint.y);
}
mCurrentPoint.set(tempPoint1);
break;
}
case 'V':
case 'v': {
// Draw vertical lines
if (mCurrentPoint.x == Float.NaN) {
throw new Exception("Relative commands require current point");
}
while (advanceToNextToken() == TOKEN_VALUE) {
float y = transformY(consumeValue());
if (relative) {
y += mCurrentPoint.y;
}
p.lineTo(mCurrentPoint.x, y);
}
mCurrentPoint.set(tempPoint1);
break;
}
case 'Z':
case 'z': {
// Closed path
p.close();
break;
}
}
}
return p;
} catch (Exception e) {
}
return null;
}
private int advanceToNextToken() {
while (mIndex < mLength) {
char c = mPathString.charAt(mIndex);
if ('a' <= c && c <= 'z') {
return (mCurrentToken = TOKEN_RELATIVE_COMMAND);
} else if ('A' <= c && c <= 'Z') {
return (mCurrentToken = TOKEN_ABSOLUTE_COMMAND);
} else if (('0' <= c && c <= '9') || c == '.' || c == '-') {
return (mCurrentToken = TOKEN_VALUE);
}
++mIndex;
}
return (mCurrentToken = TOKEN_EOF);
}
private char consumeCommand() throws Exception {
advanceToNextToken();
if (mCurrentToken != TOKEN_RELATIVE_COMMAND && mCurrentToken != TOKEN_ABSOLUTE_COMMAND) {
throw new Exception("Expected command");
}
return mPathString.charAt(mIndex++);
}
private void consumeAndTransformPoint(PointF out, boolean relative) throws Exception {
float xValue = consumeValue();
out.x = transformX(xValue);
if (out.x < xMin) {
xMin = out.x;
} else if (out.x > xMax) {
xMax = out.x;
}
float yValue = consumeValue();
out.y = transformY(yValue);
if (out.y < yMin) {
yMin = out.y;
} else if (out.y > yMax) {
yMax = out.y;
}
if (relative) {
out.x += mCurrentPoint.x;
out.y += mCurrentPoint.y;
}
}
private float consumeValue() throws Exception {
advanceToNextToken();
if (mCurrentToken != TOKEN_VALUE) {
throw new Exception("Expected value");
}
boolean start = true;
boolean seenDot = false;
int index = mIndex;
while (index < mLength) {
char c = mPathString.charAt(index);
if (!('0' <= c && c <= '9') && (c != '.' || seenDot) && (c != '-' || !start)) {
break;
}
if (c == '.') {
seenDot = true;
}
start = false;
++index;
}
if (index == mIndex) {
throw new Exception("Expected value");
}
String str = mPathString.substring(mIndex, index);
try {
float value = Float.parseFloat(str);
mIndex = index;
return value;
} catch (NumberFormatException e) {
throw new Exception("Invalid float value '" + str + "'.");
}
}
public float getPathWidth() {
return xMax - xMin;
}
public float getPathHeight() {
return yMax - yMin;
}
}
Go to studio and save the path values in String for later use.
<resources>
<string name="app_name">demo</string>
<string name="path">
M 85.00,34.57
C 90.35,27.78 95.91,20.00 99.32,12.00
100.42,9.42 101.66,3.01 102.93,1.60
...
...
...
M 238.00,387.00
C 238.00,387.00 239.00,388.00 239.00,388.00
239.00,388.00 239.00,387.00 239.00,387.00
239.00,387.00 238.00,387.00 238.00,387.00 Z
</string>
</resources>
Everything's OK but it's just a blueprint.
3. How to draw to the screen?
Call system methods in the custom view onDraw () method
public void drawPath(@NonNull Path path, @NonNull Paint paint) {
if (path.isSimplePath && path.rects != null) {
native_drawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
} else {
native_drawPath(mNativeCanvasWrapper, path.readOnlyNI(), paint.getNativeInstance());
}
}
canvas.drawPath(mSvgPath, mPaint);
As for the animation effect, I'm not going to go deep here. I'm interested in reading and referring to the relevant implementation code by myself.
Quote
Svg Use http://blog.csdn.net/tianjian4592/article/details/44538605
Svg demo https://github.com/unclepizza/SVGTraceDemo.git