├── .gitignore
├── README.md
├── SVGView
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zjf
│ │ └── svgview
│ │ ├── PathBean.java
│ │ ├── SVGHelpImpl.java
│ │ ├── SVGHelpInterface.java
│ │ └── SVGView.java
│ └── res
│ └── values
│ └── attr.xml
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── zjf
│ │ └── svgdemo
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── zjf
│ │ │ └── svgdemo
│ │ │ └── MainActivity.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── raw
│ │ └── ic_square.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── zjf
│ └── svgdemo
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── images
└── demonstration.gif
├── publish.gradle
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | /bulid
5 | .gradle
6 | .idea
7 | /local.properties
8 |
9 | /gradle
10 |
11 | # Log file
12 | *.log
13 |
14 | # BlueJ files
15 | *.ctxt
16 |
17 | # Mobile Tools for Java (J2ME)
18 | .mtj.tmp/
19 |
20 | # Package Files #
21 | *.jar
22 | *.war
23 | *.nar
24 | *.ear
25 | *.zip
26 | *.tar.gz
27 | *.rar
28 |
29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
30 | hs_err_pid*
31 | replay_pid*
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SVGView
2 |
3 | 一款处理复杂不规则图形的View,支付缩放,点击,变色操作,保留扩展功能,后续有时间会根据反馈进行迭代
4 |
5 | ### 引入
6 |
7 | ```groovy
8 | implementation 'io.github.zhaojfGithub.SVGView:SVGView:0.0.3'
9 | ```
10 |
11 | ### 效果图
12 | 
13 |
14 | ### XML属性
15 |
16 | | Attributes | format | describe |
17 | |:-------------:|---------|--------------|
18 | | SVGId | integer | 使用svg的文件id |
19 | | SVGScale | float | 设置初始缩放倍数 |
20 | | SVGBackground | color | 设置控件背景 |
21 | | SVGColor | color | 设置区域默认颜色 |
22 | | SVGLineColor | color | 设置分割线默认颜色 |
23 | | SVGIsMove | boolean | 是否启用滑动动能 |
24 | | SVGMoveSpeed | float | 设置滑动的速度,约小越快 |
25 | | SVGIsZoom | boolean | 是否启用缩放功能 |
26 | | SVGZoomSpeed | float | 设置缩放的速度,约小越快 |
27 |
28 | ### 简单使用
29 |
30 | 1. 给UI要一份SVG图
31 | 2. 通过Android studio 转成xml
32 | 3. 创建一个raw文件夹,如果没有就创建一个,和res同级目录
33 | 4. xml引入,当然也可以通过Java引入,其中SVGId是必须的
34 | 5. 也支持File引入,通过Java调用setSVGFile方法
35 |
36 | ```xml
37 |
38 |
45 | ```
46 | 处理点击区域
47 | ```kotlin
48 | val svgView = findViewById(R.id.SVGView)
49 | svgView.zoomSpeed = 1F
50 | svgView.moveSpeed = 3F
51 | svgView.setOnClickListener(SVGView.OnSVGClickListener {
52 | if (it.select) {
53 | it.color = Color.RED
54 | } else {
55 | it.color = Color.BLUE
56 | }
57 | })
58 | ```
59 |
60 | 至此设置完毕了
61 |
62 | ### 点击额外设置
63 |
64 | 因为SVG转化XML是由一个一个path组成的,假如我想要知道我点击的区域是那一部分,那么就需要加一个TAG,用来标识所点击的区域,例如:
65 |
66 | ```xml
67 |
68 |
75 | ```
76 |
77 | 其中 android:tag="这是一个标识"是必须的,如果想使用其他标识可以重写SVGHelpImpl的deCodeSVG方法,
78 |
79 | ### 点击回调处理
80 |
81 | 回调默认返回的是PathBean,如果需要添加自定义字段,请继承PathBean,然后重写SVGHelpImpl的getPathBean方法
82 |
83 | 关于更多可以查看源码,代码是最好的老师
--------------------------------------------------------------------------------
/SVGView/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | .gradle
--------------------------------------------------------------------------------
/SVGView/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | ext {
6 | PUBLISH_ARTIFACT_ID = "SVGView"
7 | }
8 |
9 | apply from: '../publish.gradle'
10 |
11 | android {
12 | namespace 'com.zjf.svgview'
13 | compileSdk 33
14 |
15 | defaultConfig {
16 | //applicationId "com.zjf.svgview"
17 | minSdk 16
18 | targetSdk 33
19 | versionCode 1
20 | versionName "1.0"
21 |
22 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation 'androidx.appcompat:appcompat:1.6.1'
39 | }
40 |
--------------------------------------------------------------------------------
/SVGView/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/SVGView/src/main/java/com/zjf/svgview/PathBean.java:
--------------------------------------------------------------------------------
1 | package com.zjf.svgview;
2 |
3 | import android.graphics.Path;
4 | import android.graphics.Rect;
5 | import android.graphics.RectF;
6 | import android.graphics.Region;
7 |
8 | import androidx.annotation.ColorInt;
9 |
10 | /**
11 | * @author zjf
12 | * @date 2023/5/29
13 | */
14 | public class PathBean {
15 | private Integer id;
16 | private String tag;
17 |
18 | private Path path;
19 | private RectF rectF;
20 | private Region region;
21 | @ColorInt
22 | private Integer color;
23 |
24 | private Boolean isSelect;
25 |
26 | public PathBean(Integer id, String tag, Path path, @ColorInt Integer color, Boolean isSelect) {
27 | RectF rectF = new RectF();
28 | path.computeBounds(rectF, true);
29 | Region region = new Region();
30 | Rect rect = new Rect((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom);
31 | region.setPath(path, new Region(rect));
32 |
33 | this.id = id;
34 | this.tag = tag;
35 | this.path = path;
36 | this.rectF = rectF;
37 | this.region = region;
38 | this.color = color;
39 | this.isSelect = isSelect;
40 | }
41 |
42 | @Override
43 | public String toString() {
44 | return "PathBean{" +
45 | "id=" + id +
46 | ", tag='" + tag + '\'' +
47 | ", path=" + path +
48 | ", rectF=" + rectF +
49 | ", region=" + region +
50 | ", color=" + color +
51 | ", isSelect=" + isSelect +
52 | '}';
53 | }
54 |
55 | public Integer getId() {
56 | return id;
57 | }
58 |
59 | public void setId(Integer id) {
60 | this.id = id;
61 | }
62 |
63 | public String getTag() {
64 | return tag;
65 | }
66 |
67 | public void setTag(String tag) {
68 | this.tag = tag;
69 | }
70 |
71 | public Path getPath() {
72 | return path;
73 | }
74 |
75 | public void setPath(Path path) {
76 | this.path = path;
77 | }
78 |
79 | public Boolean getSelect() {
80 | return isSelect;
81 | }
82 |
83 | public void setSelect(Boolean select) {
84 | isSelect = select;
85 | }
86 |
87 | public RectF getRectF() {
88 | return rectF;
89 | }
90 |
91 | public void setRectF(RectF rectF) {
92 | this.rectF = rectF;
93 | }
94 |
95 | public Region getRegion() {
96 | return region;
97 | }
98 |
99 | public void setRegion(Region region) {
100 | this.region = region;
101 | }
102 |
103 | public Integer getColor() {
104 | return color;
105 | }
106 |
107 | public void setColor(@ColorInt Integer color) {
108 | this.color = color;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/SVGView/src/main/java/com/zjf/svgview/SVGHelpImpl.java:
--------------------------------------------------------------------------------
1 | package com.zjf.svgview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.RectF;
8 | import android.os.Build;
9 |
10 | import androidx.annotation.ColorInt;
11 | import androidx.core.graphics.PathParser;
12 |
13 | import org.w3c.dom.Document;
14 | import org.w3c.dom.Element;
15 | import org.w3c.dom.NodeList;
16 |
17 | import java.io.File;
18 | import java.io.FileInputStream;
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.nio.file.Files;
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | import javax.xml.parsers.DocumentBuilder;
26 | import javax.xml.parsers.DocumentBuilderFactory;
27 |
28 | /**
29 | * @author zjf
30 | * @date 2023/5/29
31 | * 处理SVG图片相关的类,支持继承重写,然后重新赋值给SVGView
32 | */
33 | public class SVGHelpImpl implements SVGHelpInterface {
34 |
35 | /**
36 | * 解析SVG文件,如果标注Path不为android:tag或者自定义了实体类 需要重写此方法
37 | * @param context 上下文
38 | * @param SVGId RAW文件夹的图片ID,可为null
39 | * @param file 图片路径 可为null,
40 | * @param color 住背景颜色
41 | * @return 如果SVGId与file都为null,return null,否则return正常图片解析结果
42 | */
43 | @Override
44 | public List deCodeSVG(Context context, Integer SVGId, File file, @ColorInt Integer color) throws IOException {
45 | InputStream inputStream = null;
46 | List pathList = new ArrayList<>();
47 | try {
48 | if (SVGId != null) {
49 | inputStream = context.getResources().openRawResource(SVGId);
50 | } else if (file != null && file.exists()) {
51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
52 | inputStream = Files.newInputStream(file.toPath());
53 | }else {
54 | inputStream = new FileInputStream(file);
55 | }
56 | } else {
57 | return null;
58 | }
59 | DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
60 | DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
61 | Document parse = documentBuilder.parse(inputStream);
62 | NodeList paths = parse.getDocumentElement().getElementsByTagName("path");
63 | for (int i = 0; i < paths.getLength(); i++) {
64 | Element item = (Element) paths.item(i);
65 | if (item == null) {
66 | continue;
67 | }
68 | String pathStr = item.getAttribute("android:pathData");
69 | String pathTag = item.getAttribute("android:tag");
70 | Path pathData = PathParser.createPathFromPathData(pathStr);
71 | PathBean pathBean = getPathBean(i, pathTag, pathData, color);
72 | pathList.add(pathBean);
73 | }
74 | return pathList;
75 | } catch (Exception exception) {
76 | exception.printStackTrace();
77 | } finally {
78 | assert inputStream != null;
79 | inputStream.close();
80 | }
81 | return null;
82 | }
83 |
84 | /**
85 | * 计算原本图片占位大小,不一定是svg本身所标识的大小
86 | * @param list 解析文件
87 | * @return 图片的RecF对象
88 | */
89 | @Override
90 | public RectF getSVGRecF(List list) {
91 | if (list == null){
92 | return null;
93 | }
94 | float left = -1F, top = -1F, right = -1F, bottom = -1F;
95 | for (int i = 0; i < list.size(); i++) {
96 | RectF bounds = new RectF();
97 | list.get(i).getPath().computeBounds(bounds, true);
98 | left = left == -1 ? bounds.left : Math.min(left, bounds.left);
99 | top = top == -1 ? bounds.top : Math.min(top, bounds.top);
100 | right = right == -1 ? bounds.right : Math.max(right, bounds.right);
101 | bottom = bottom == -1 ? bounds.bottom : Math.max(bottom, bounds.bottom);
102 | }
103 | return new RectF(left, top, right, bottom);
104 | }
105 |
106 | /**
107 | * 获取一个实体类,如果有自定义的实体,可以不用此方法,但是需要重写deCodeSVG
108 | */
109 | @Override
110 | public PathBean getPathBean(Integer id, String tag, Path path, Integer color) {
111 | return new PathBean(id, tag, path, color, false);
112 | }
113 |
114 | /**
115 | * @param pathBean 数据
116 | * @param canvas 画布
117 | * @param paint 画笔
118 | * @param LineColor 分割线颜色
119 | */
120 | @Override
121 | public void onDraw(PathBean pathBean, Canvas canvas, Paint paint, Integer LineColor) {
122 | paint.setColor(pathBean.getColor());
123 | paint.setStyle(Paint.Style.FILL);
124 | canvas.drawPath(pathBean.getPath(), paint);
125 | //交割线
126 | paint.setStrokeWidth(1);
127 | paint.setColor(LineColor);
128 | paint.setStyle(Paint.Style.STROKE);
129 | canvas.drawPath(pathBean.getPath(), paint);
130 | }
131 |
132 | /**
133 | * 判断点击区域是是否在Path内
134 | * @param pathBean 数据
135 | * @param x X轴坐标
136 | * @param y Y轴坐标
137 | * @return true false
138 | */
139 | @Override
140 | public Boolean isClick(PathBean pathBean, Float x, Float y) {
141 | return pathBean.getRegion().contains(x.intValue(), y.intValue());
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/SVGView/src/main/java/com/zjf/svgview/SVGHelpInterface.java:
--------------------------------------------------------------------------------
1 | package com.zjf.svgview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.RectF;
8 |
9 | import androidx.annotation.ColorInt;
10 | import androidx.annotation.ColorRes;
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 | import java.util.List;
15 |
16 | /**
17 | * @author zjf
18 | * @date 2023/5/29
19 | */
20 | public interface SVGHelpInterface {
21 | List deCodeSVG(Context context, Integer SVGId, File file, @ColorInt Integer color) throws IOException;
22 |
23 | RectF getSVGRecF(List list);
24 |
25 | PathBean getPathBean(Integer id, String tag, Path path, Integer color);
26 |
27 | void onDraw(PathBean pathBean, Canvas canvas, Paint paint, @ColorInt Integer LineColor);
28 |
29 | Boolean isClick(PathBean pathBean, Float x, Float y);
30 | }
31 |
--------------------------------------------------------------------------------
/SVGView/src/main/java/com/zjf/svgview/SVGView.java:
--------------------------------------------------------------------------------
1 | package com.zjf.svgview;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.Configuration;
6 | import android.content.res.TypedArray;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.graphics.RectF;
11 | import android.util.AttributeSet;
12 | import android.util.Log;
13 | import android.view.GestureDetector;
14 | import android.view.MotionEvent;
15 | import android.view.ScaleGestureDetector;
16 | import android.view.View;
17 |
18 | import androidx.annotation.ColorInt;
19 | import androidx.annotation.NonNull;
20 | import androidx.annotation.Nullable;
21 | import androidx.annotation.RawRes;
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * @author zjf
30 | * @date 2023/5/29
31 | */
32 | public class SVGView extends View {
33 |
34 | /**
35 | * 默认阈值,一般不做修改,太少了会不好控制滑动和缩放
36 | */
37 | private static final int MAX_MOVE_NUMBER = 5;
38 |
39 | /**
40 | * 默认移动速度
41 | */
42 | private static final float MOVE_INIT_SPEED = 2;
43 |
44 | /**
45 | * 默认缩放速度
46 | */
47 | private static final float ZOOM_INIT_SPEED = 3;
48 |
49 | private OnSVGClickListener onClickListener;
50 |
51 | private SVGHelpInterface svgHelp;
52 |
53 | private Integer svgId;
54 |
55 | private File file;
56 |
57 | /**
58 | * 整体背景
59 | */
60 | private int svgBackground;
61 |
62 | /**
63 | * 分割线颜色
64 | */
65 | private int lineColor;
66 |
67 | private List PathList;
68 |
69 | /**
70 | * 当前缩放倍数
71 | */
72 | private Float scale;
73 |
74 | /**
75 | * 图像的默认大小
76 | */
77 | private RectF originRecF;
78 |
79 | private Paint paint;
80 |
81 | /**
82 | * 处理区域点击
83 | */
84 | private GestureDetector gestureClick;
85 |
86 | /**
87 | * 处理手势移动
88 | */
89 | private GestureDetector gestureMove;
90 |
91 | /**
92 | * 处理手势缩放
93 | */
94 | private ScaleGestureDetector gestureZoom;
95 |
96 | /**
97 | * 区分缩放与滑动的阈值
98 | */
99 | private int moveNumber = 0;
100 |
101 | /**
102 | * 当前位移的X轴距离
103 | */
104 | private Float moveX = 0F;
105 |
106 | /**
107 | * 当前位移的Y轴距离
108 | */
109 | private Float moveY = 0F;
110 |
111 | /**
112 | * 之前滑动的X轴距离(因为可能经历了多次滑动,所以需要记录一下)
113 | */
114 | private Float lastMoveX = 0F;
115 |
116 | /**
117 | * 之前滑动的Y轴距离
118 | */
119 | private Float lastMoveY = 0F;
120 |
121 | /**
122 | * 是否可以触发滑动
123 | */
124 | private boolean isMove;
125 | /**
126 | * 移动的速度
127 | */
128 | private float moveSpeed;
129 |
130 | /**
131 | * 是否可以触发缩放
132 | */
133 | private boolean isZoom;
134 |
135 | /**
136 | * 缩放的速度
137 | */
138 | private float zoomSpeed;
139 |
140 | /**
141 | * 主区域的颜色
142 | */
143 | @ColorInt
144 | private Integer color;
145 |
146 |
147 | public SVGView(Context context) {
148 | this(context, null);
149 | }
150 |
151 | public SVGView(Context context, @Nullable AttributeSet attrs) {
152 | this(context, attrs, 0);
153 | }
154 |
155 | public SVGView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
156 | super(context, attrs, defStyleAttr);
157 | TypedArray typedArray = null;
158 | try {
159 | typedArray = context.obtainStyledAttributes(attrs, R.styleable.SVGView);
160 | svgId = typedArray.getResourceId(R.styleable.SVGView_SVGId, -1);
161 | scale = typedArray.getFloat(R.styleable.SVGView_SVGScale, 1);
162 | svgBackground = typedArray.getColor(R.styleable.SVGView_SVGBackground, Color.WHITE);
163 | color = typedArray.getColor(R.styleable.SVGView_SVGColor, Color.BLACK);
164 | lineColor = typedArray.getColor(R.styleable.SVGView_SVGLineColor, Color.BLACK);
165 | isMove = typedArray.getBoolean(R.styleable.SVGView_SVGIsMove, false);
166 | isZoom = typedArray.getBoolean(R.styleable.SVGView_SVGIsZoom, false);
167 | moveSpeed = typedArray.getFloat(R.styleable.SVGView_SVGMoveSpeed, MOVE_INIT_SPEED);
168 | zoomSpeed = typedArray.getFloat(R.styleable.SVGView_SVGZoomSpeed, ZOOM_INIT_SPEED);
169 | } catch (Exception e) {
170 | e.printStackTrace();
171 | } finally {
172 | assert typedArray != null;
173 | typedArray.recycle();
174 | }
175 | init();
176 | }
177 |
178 | @Override
179 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
180 | if (originRecF == null) {
181 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
182 | return;
183 | }
184 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
185 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
186 | int heightMode = MeasureSpec.getSize(heightMeasureSpec);
187 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
188 |
189 | int desiredWidth = (int) originRecF.width() + getPaddingLeft() + getPaddingRight();
190 | int desiredHeight = (int) originRecF.height() + getPaddingTop() + getPaddingBottom();
191 | int measuredWidth;
192 | int measuredHeight = desiredHeight;
193 | switch (widthMode) {
194 | case MeasureSpec.EXACTLY:
195 | measuredWidth = widthSize;
196 | break;
197 | case MeasureSpec.AT_MOST:
198 | measuredWidth = Math.min(desiredWidth, widthSize);
199 | break;
200 | default:
201 | measuredWidth = desiredWidth;
202 | }
203 | if (heightMode == MeasureSpec.EXACTLY) {
204 | measuredHeight = heightSize;
205 | }
206 | setMeasuredDimension(measuredWidth, measuredHeight);
207 | }
208 |
209 | private void init() {
210 | paint = new Paint();
211 | paint.setAntiAlias(true);
212 | PathList = new ArrayList<>();
213 | gestureClick = new GestureDetector(getContext(), getOnClickGesture());
214 | gestureMove = new GestureDetector(getContext(), getOnMoveGesture());
215 | gestureZoom = new ScaleGestureDetector(getContext(), getOnZoomGesture());
216 | if (svgHelp == null) {
217 | svgHelp = new SVGHelpImpl();
218 | }
219 | if (svgId == null || svgId == -1) {
220 | return;
221 | }
222 | deCodeSVG();
223 | }
224 |
225 | private void deCodeSVG() {
226 | new Thread(() -> {
227 | try {
228 | List list = svgHelp.deCodeSVG(getContext(), svgId, file, color);
229 | PathList.clear();
230 | PathList.addAll(list);
231 | originRecF = svgHelp.getSVGRecF(PathList);
232 | post(this::requestLayout);
233 | post(this::invalidate);
234 | } catch (IOException e) {
235 | e.printStackTrace();
236 | }
237 | }).start();
238 | }
239 |
240 | private GestureDetector.OnGestureListener getOnClickGesture() {
241 | return new GestureDetector.OnGestureListener() {
242 | @Override
243 | public boolean onDown(@NonNull MotionEvent e) {
244 | return true;
245 | }
246 |
247 | @Override
248 | public void onShowPress(@NonNull MotionEvent e) {
249 |
250 | }
251 |
252 | @Override
253 | public boolean onSingleTapUp(@NonNull MotionEvent e) {
254 | boolean result = false;
255 | for (PathBean pathBean : PathList) {
256 | float x = (e.getX() - (getWidth() - originRecF.width() * scale) / 2 - lastMoveX) / scale;
257 | float y = (e.getY() - (getHeight() - originRecF.height() * scale) / 2 - lastMoveY) / scale;
258 | if (svgHelp.isClick(pathBean, x, y)) {
259 | pathBean.setSelect(!pathBean.getSelect());
260 | if (onClickListener != null) {
261 | onClickListener.onClick(pathBean);
262 | }
263 | result = true;
264 | invalidate();
265 | }
266 | }
267 | return result;
268 | }
269 |
270 | @Override
271 | public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float distanceX, float distanceY) {
272 | return false;
273 | }
274 |
275 | @Override
276 | public void onLongPress(@NonNull MotionEvent e) {
277 |
278 | }
279 |
280 | @Override
281 | public boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float velocityX, float velocityY) {
282 | return false;
283 | }
284 | };
285 | }
286 |
287 | private GestureDetector.SimpleOnGestureListener getOnMoveGesture() {
288 | return new GestureDetector.SimpleOnGestureListener() {
289 |
290 | @Override
291 | public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float distanceX, float distanceY) {
292 | if (!isMove) {
293 | return false;
294 | }
295 | if (moveNumber <= MAX_MOVE_NUMBER) {
296 | moveNumber++;
297 | return true;
298 | }
299 | float deltaX = (e2.getX() - e1.getX()) / moveSpeed;
300 | float deltaY = (e2.getY() - e1.getY()) / moveSpeed;
301 | moveX = deltaX;
302 | moveY = deltaY;
303 | invalidate();
304 | return true;
305 | }
306 | };
307 | }
308 |
309 | private ScaleGestureDetector.SimpleOnScaleGestureListener getOnZoomGesture() {
310 | return new ScaleGestureDetector.SimpleOnScaleGestureListener() {
311 | Float lastScale;
312 |
313 | @Override
314 | public boolean onScaleBegin(@NonNull ScaleGestureDetector detector) {
315 | lastScale = 1F;
316 | return super.onScaleBegin(detector);
317 | }
318 |
319 | @Override
320 | public boolean onScale(@NonNull ScaleGestureDetector detector) {
321 | if (!isZoom) {
322 | return false;
323 | }
324 | float scaleGap = (detector.getScaleFactor() - lastScale) / zoomSpeed;
325 | //因为如果scale为负数,会造成图像倒转,到0会看不到,故设置为0.1
326 | if (scale + scaleGap > 0.1) {
327 | scale += scaleGap;
328 | }
329 | invalidate();
330 | return true;
331 | }
332 |
333 | @Override
334 | public void onScaleEnd(@NonNull ScaleGestureDetector detector) {
335 | super.onScaleEnd(detector);
336 | }
337 | };
338 | }
339 |
340 | @Override
341 | protected void onDraw(Canvas canvas) {
342 | super.onDraw(canvas);
343 | if (PathList.isEmpty() || canvas == null || originRecF == null) {
344 | return;
345 | }
346 | canvas.save();
347 | canvas.drawColor(svgBackground);
348 | //默认先移动到中间
349 | canvas.translate((getWidth() - originRecF.width() * scale) / 2, (getHeight() - originRecF.height() * scale) / 2);
350 | canvas.translate(lastMoveX, lastMoveY);
351 | //处理手势位移
352 | canvas.translate(moveX, moveY);
353 | canvas.scale(scale, scale);
354 | for (int i = 0; i < PathList.size(); i++) {
355 | svgHelp.onDraw(PathList.get(i), canvas, paint, lineColor);
356 | }
357 | canvas.restore();
358 | }
359 |
360 | @SuppressLint("ClickableViewAccessibility")
361 | @Override
362 | public boolean onTouchEvent(MotionEvent event) {
363 | gestureClick.onTouchEvent(event);
364 | int pointerCount = event.getPointerCount();
365 | if (pointerCount == 1) {
366 | gestureMove.onTouchEvent(event);
367 | } else {
368 | gestureZoom.onTouchEvent(event);
369 | }
370 | if (event.getAction() == MotionEvent.ACTION_UP) {
371 | if (moveNumber > MAX_MOVE_NUMBER) {
372 | //只有经历了滑动才记录
373 | lastMoveX += moveX;
374 | lastMoveY += moveY;
375 | moveX = 0F;
376 | moveY = 0F;
377 | }
378 | moveNumber = 0;
379 | }
380 | return true;
381 | }
382 |
383 | @Override
384 | protected void onConfigurationChanged(Configuration newConfig) {
385 | super.onConfigurationChanged(newConfig);
386 | requestLayout();
387 | }
388 |
389 | public void setSVGId(@RawRes int svgId) {
390 | this.file = null;
391 | this.svgId = svgId;
392 | deCodeSVG();
393 | }
394 |
395 | public void setSVGFile(File file) {
396 | if (!file.exists()) {
397 | return;
398 | }
399 | this.svgId = null;
400 | this.file = file;
401 | deCodeSVG();
402 | }
403 |
404 | public boolean isMove() {
405 | return isMove;
406 | }
407 |
408 | public void setMove(boolean move) {
409 | isMove = move;
410 | }
411 |
412 | public float getMoveSpeed() {
413 | return moveSpeed;
414 | }
415 |
416 | public void setMoveSpeed(float moveSpeed) {
417 | this.moveSpeed = moveSpeed;
418 | }
419 |
420 | public boolean isZoom() {
421 | return isZoom;
422 | }
423 |
424 | public void setZoom(boolean zoom) {
425 | isZoom = zoom;
426 | }
427 |
428 | public float getZoomSpeed() {
429 | return zoomSpeed;
430 | }
431 |
432 | public void setZoomSpeed(float zoomSpeed) {
433 | this.zoomSpeed = zoomSpeed;
434 | }
435 |
436 | public Integer getSVGId() {
437 | return svgId;
438 | }
439 |
440 | public Float getSVGScale() {
441 | return scale;
442 | }
443 |
444 | /**
445 | * 设置SVG提取辅助类
446 | *
447 | * @param svgHelp SVG提取
448 | */
449 | public void setSVGHelp(SVGHelpInterface svgHelp) {
450 | this.svgHelp = svgHelp;
451 | }
452 |
453 | /**
454 | * 设置点击事件
455 | *
456 | * @param onClickListener 点击回调
457 | */
458 | public void setOnClickListener(OnSVGClickListener onClickListener) {
459 | this.onClickListener = onClickListener;
460 | }
461 |
462 | public interface OnSVGClickListener {
463 | void onClick(PathBean pathBean);
464 | }
465 |
466 | }
467 |
--------------------------------------------------------------------------------
/SVGView/src/main/res/values/attr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.zjf.svgdemo'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | applicationId "com.zjf.svgdemo"
12 | minSdk 24
13 | targetSdk 33
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation 'androidx.core:core-ktx:1.8.0'
38 | implementation 'androidx.appcompat:appcompat:1.6.1'
39 | implementation 'com.google.android.material:material:1.5.0'
40 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
41 | implementation project(path: ':SVGView')
42 | testImplementation 'junit:junit:4.13.2'
43 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
44 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
45 |
46 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/zjf/svgdemo/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.zjf.svgdemo
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.zjf.svgdemo", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zjf/svgdemo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.zjf.svgdemo
2 |
3 | import android.graphics.Color
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AppCompatActivity
6 | import com.zjf.svgview.SVGView
7 |
8 | class MainActivity : AppCompatActivity() {
9 |
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContentView(R.layout.activity_main)
13 | val svgView = findViewById(R.id.SVGView)
14 | svgView.zoomSpeed = 1F
15 | svgView.moveSpeed = 3F
16 | svgView.setOnClickListener(SVGView.OnSVGClickListener {
17 | if (it.select) {
18 | it.color = Color.RED
19 | } else {
20 | it.color = Color.BLUE;
21 | }
22 | })
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/raw/ic_square.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
21 |
26 |
31 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SVGDemo
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zjf/svgdemo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.zjf.svgdemo
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '7.2.2' apply false
4 | id 'com.android.library' version '7.2.2' apply false
5 | id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
6 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/images/demonstration.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaojfGithub/SVGView/18cc74503aba3266a67d80495935fc76a659d6d6/images/demonstration.gif
--------------------------------------------------------------------------------
/publish.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'signing'
3 |
4 | task androidSourcesJar(type: Jar) {
5 | archiveClassifier.set('sources')
6 | from android.sourceSets.main.java.srcDirs
7 |
8 | exclude "**/R.class"
9 | exclude "**/BuildConfig.class"
10 | }
11 |
12 |
13 | ext {
14 | PUBLISH_GROUP_ID = 'io.github.zhaojfGithub.SVGView'
15 | PUBLISH_VERSION = '0.0.3'
16 | }
17 |
18 | ext["signing.keyId"] = ''
19 | ext["signing.password"] = ''
20 | ext["signing.secretKeyRingFile"] = ''
21 | ext["ossrhUsername"] = ''
22 | ext["ossrhPassword"] = ''
23 |
24 | File secretPropsFile = project.rootProject.file('local.properties')
25 | if (secretPropsFile.exists()) {
26 | println "Found secret props file, loading props"
27 | Properties p = new Properties()
28 | p.load(new FileInputStream(secretPropsFile))
29 | p.each { name, value ->
30 | ext[name] = value
31 | }
32 | } else {
33 | println "No props file, loading env vars"
34 | }
35 | publishing {
36 | publications {
37 | release(MavenPublication) {
38 | // The coordinates of the library, being set from variables that
39 | // we'll set up in a moment
40 | groupId PUBLISH_GROUP_ID
41 | artifactId PUBLISH_ARTIFACT_ID
42 | version PUBLISH_VERSION
43 |
44 | // Two artifacts, the `aar` and the sources
45 | artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
46 | artifact androidSourcesJar
47 |
48 | // Self-explanatory metadata for the most part
49 | pom {
50 | name = PUBLISH_ARTIFACT_ID
51 | description = 'SVGView'
52 | // If your project has a dedicated site, use its URL here
53 | url = 'https://github.com/zhaojfGithub/SVGView'
54 | licenses {
55 | license {
56 | //协议类型,一般默认Apache License2.0的话不用改:
57 | name = 'The Apache License, Version 2.0'
58 | url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
59 | }
60 | }
61 | developers {
62 | developer {
63 | id = 'zhaojf'
64 | name = 'zhaojf'
65 | email = 'zhaojfGithub@163.com'
66 | }
67 | }
68 | // Version control info, if you're using GitHub, follow the format as seen here
69 | scm {
70 | //修改成你的Git地址:
71 | connection = 'scm:git:github.com/zhaojfGithub/SVGView.git'
72 | developerConnection = 'scm:git:ssh://github.com/zhaojfGithub/SVGView.git'
73 | //分支地址:
74 | url = 'https://github.com/zhaojfGithub/SVGView/tree/main'
75 | }
76 | // A slightly hacky fix so that your POM will include any transitive dependencies
77 | // that your library builds upon
78 | withXml {
79 | def dependenciesNode = asNode().appendNode('dependencies')
80 |
81 | project.configurations.implementation.allDependencies.each {
82 | def dependencyNode = dependenciesNode.appendNode('dependency')
83 | dependencyNode.appendNode('groupId', it.group)
84 | dependencyNode.appendNode('artifactId', it.name)
85 | dependencyNode.appendNode('version', it.version)
86 | }
87 | }
88 | }
89 | }
90 | }
91 | repositories {
92 | // The repository to publish to, Sonatype/MavenCentral
93 | maven {
94 | // This is an arbitrary name, you may also use "mavencentral" or
95 | // any other name that's descriptive for you
96 | name = "mavenCentral"
97 |
98 | def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
99 | def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
100 | // You only need this if you want to publish snapshots, otherwise just set the URL
101 | // to the release repo directly
102 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
103 |
104 | // The username and password we've fetched earlier
105 | credentials {
106 | username ossrhUsername
107 | password ossrhPassword
108 | }
109 | }
110 | }
111 | }
112 | signing {
113 | sign publishing.publications
114 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "SVGDemo"
16 | include ':app'
17 | include ':SVGView'
18 |
--------------------------------------------------------------------------------