listRelce, double newWidth, double newHeight) {
40 | SpannableStringBuilder spannableString = new SpannableStringBuilder(content);
41 | return spannableString;
42 | }
43 |
44 |
45 | public static SpannableStringBuilder getEditImg(Context context, SpannableStringBuilder txt, String path) {
46 | SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(txt);
47 | Pattern pattern = Pattern.compile("\\" + FONT_NAME_HEAD + "(\\S+?)\\" + FONT_NAME_TAIL + "");//匹配[xx]的字符串
48 | Matcher matcher = pattern.matcher(txt);
49 | while (matcher.find()) {
50 | int start = matcher.start();
51 | int end = matcher.end();
52 | String group = matcher.group();
53 | group = group.substring(FONT_NAME_HEAD.length(), group.length() - FONT_NAME_TAIL.length());
54 | Bitmap bitmap = getSdBitmap(path + group);
55 | ImageSpan imageSpan = new ImageSpan(context, bitmap);
56 | spannableStringBuilder.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
57 | }
58 | return spannableStringBuilder;
59 | }
60 |
61 | /***
62 | * 获得SD卡bitmap
63 | */
64 | public static Bitmap getSdBitmap(String pathname) {
65 | FileInputStream fis = null;
66 | try {
67 | fis = new FileInputStream(pathname);
68 | return BitmapFactory.decodeStream(fis);
69 | } catch (FileNotFoundException e) {
70 | e.printStackTrace();
71 | }
72 | return null;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/field_character/SystemUtils.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.field_character;
2 |
3 | import android.app.Instrumentation;
4 | import android.text.InputType;
5 | import android.widget.EditText;
6 |
7 | import java.lang.reflect.InvocationTargetException;
8 | import java.lang.reflect.Method;
9 |
10 | /**
11 | * 调用系统的一些工具方法
12 | */
13 |
14 | public class SystemUtils {
15 | /**
16 | *
17 | * 使用Instrumentation接口:对于非自行编译的安卓系统,无法获取系统签名,只能在前台模拟按键,不能后台模拟
18 | * 注意:调用Instrumentation的sendKeyDownUpSync方法必须另起一个线程,否则无效
19 | * @param keyCode
20 | * 按键事件(KeyEvent)的按键值
21 | *
22 | */
23 | public static void sendKeyCode(final int keyCode) {
24 | new Thread(new Runnable() {
25 | @Override
26 | public void run() {
27 | try {
28 | // 创建一个Instrumentation对象
29 | Instrumentation inst = new Instrumentation();
30 | // 调用inst对象的按键模拟方法
31 | inst.sendKeyDownUpSync(keyCode);
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | }
35 | }
36 | }).start();
37 | }
38 |
39 |
40 | /**
41 | * 隐藏系统键盘
42 | */
43 | public static void hideSoftInputMethod(EditText editText) {
44 | int currentVersion = android.os.Build.VERSION.SDK_INT;
45 | String methodName = null;
46 | if (currentVersion >= 16) {
47 | // 4.2
48 | methodName = "setShowSoftInputOnFocus";
49 | } else if (currentVersion >= 14) {
50 | // 4.0
51 | methodName = "setSoftInputShownOnFocus";
52 | }
53 |
54 | if (methodName == null) {
55 | editText.setInputType(InputType.TYPE_NULL);
56 | } else {
57 | Class cls = EditText.class;
58 | Method setShowSoftInputOnFocus;
59 | try {
60 | setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class);
61 | setShowSoftInputOnFocus.setAccessible(true);
62 | setShowSoftInputOnFocus.invoke(editText, false);
63 | } catch (NoSuchMethodException e) {
64 | editText.setInputType(InputType.TYPE_NULL);
65 | e.printStackTrace();
66 | } catch (InvocationTargetException e) {
67 | e.printStackTrace();
68 | } catch (IllegalAccessException e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/field_character/WordSandPictures.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.field_character;
2 |
3 | import java.io.Serializable;
4 |
5 | public class WordSandPictures implements Serializable {
6 | public int start;
7 | public int end;
8 | public String path = "";
9 | public String allPath = "";
10 | public int type = -1;
11 | public int faceIndex;
12 |
13 | @Override
14 | public String toString() {
15 | return "WordSandPictures{" +
16 | "allPath='" + allPath + '\'' +
17 | ", start=" + start +
18 | ", end=" + end +
19 | ", path='" + path + '\'' +
20 | ", type=" + type +
21 | ", faceIndex=" + faceIndex +
22 | '}';
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/BasePen.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.graphics.Canvas;
4 | import android.view.MotionEvent;
5 |
6 | /**
7 | * @author shiming
8 | * @version v1.0 create at 2017/10/17
9 | * @des 处理draw和touch事件的基类
10 | */
11 | public abstract class BasePen {
12 |
13 | /**
14 | * 绘制
15 | *
16 | * @param canvas
17 | */
18 | public abstract void draw(Canvas canvas);
19 |
20 | /**
21 | * 接受并处理onTouchEvent
22 | *
23 | * @param event
24 | * @return
25 | */
26 | public boolean onTouchEvent(MotionEvent event, Canvas canvas) {
27 | return false;
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/BasePenExtend.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.view.MotionEvent;
7 |
8 | import com.shiming.pen.Bezier;
9 | import com.shiming.pen.old_code.ControllerPoint;
10 |
11 | import java.util.ArrayList;
12 |
13 | /**
14 | * @author shiming
15 | * @version v1.0 create at 2017/10/10
16 | * @des
17 | */
18 | public abstract class BasePenExtend extends BasePen {
19 |
20 | public ArrayList mHWPointList = new ArrayList<>();
21 |
22 | public ArrayList mPointList = new ArrayList();
23 |
24 | public ControllerPoint mLastPoint = new ControllerPoint(0, 0);
25 |
26 | public Paint mPaint;
27 | //笔的宽度信息
28 | public double mBaseWidth;
29 |
30 | public double mLastVel;
31 |
32 | public double mLastWidth;
33 |
34 | public Bezier mBezier = new Bezier();
35 |
36 | protected ControllerPoint mCurPoint;
37 | protected Context mContext;
38 |
39 | public BasePenExtend(Context context) {
40 | mContext = context;
41 | }
42 |
43 | public void setPaint(Paint paint) {
44 | mPaint = paint;
45 | mBaseWidth = paint.getStrokeWidth();
46 | }
47 |
48 | @Override
49 | public void draw(Canvas canvas) {
50 | mPaint.setStyle(Paint.Style.FILL);
51 | //点的集合少 不去绘制
52 | if (mHWPointList == null || mHWPointList.size() < 1)
53 | return;
54 | //当控制点的集合很少的时候,需要画个小圆,但是需要算法
55 | if (mHWPointList.size() < 2) {
56 | ControllerPoint point = mHWPointList.get(0);
57 | //由于此问题在算法上还没有实现,所以暂时不给他画圆圈
58 | //canvas.drawCircle(point.x, point.y, point.width, mPaint);
59 | } else {
60 | mCurPoint = mHWPointList.get(0);
61 | drawNeetToDo(canvas);
62 | }
63 | }
64 |
65 |
66 | @Override
67 | public boolean onTouchEvent(MotionEvent event, Canvas canvas) {
68 | // event会被下一次事件重用,这里必须生成新的,否则会有问题
69 | MotionEvent event2 = MotionEvent.obtain(event);
70 | switch (event.getActionMasked()) {
71 | case MotionEvent.ACTION_DOWN:
72 | onDown(createMotionElement(event2));
73 | return true;
74 | case MotionEvent.ACTION_MOVE:
75 | onMove(createMotionElement(event2));
76 | return true;
77 | case MotionEvent.ACTION_UP:
78 | onUp(createMotionElement(event2), canvas);
79 | return true;
80 | default:
81 | break;
82 | }
83 | return super.onTouchEvent(event, canvas);
84 | }
85 |
86 | /**
87 | * 按下的事件
88 | *
89 | * @param mElement
90 | */
91 | public void onDown(MotionElement mElement) {
92 | if (mPaint == null) {
93 | throw new NullPointerException("paint 笔不可能为null哦");
94 | }
95 | if (getNewPaint(mPaint) != null) {
96 | Paint paint = getNewPaint(mPaint);
97 | mPaint = paint;
98 | //当然了,不要因为担心内存泄漏,在每个变量使用完成后都添加xxx=null,
99 | // 对于消除过期引用的最好方法,就是让包含该引用的变量结束生命周期,而不是显示的清空
100 | paint = null;
101 | System.out.println("shiming 当绘制的时候是否为新的paint" + mPaint + "原来的对象是否销毁了paint==" + paint);
102 | }
103 | mPointList.clear();
104 | //如果在brush字体这里接受到down的事件,把下面的这个集合清空的话,那么绘制的内容会发生改变
105 | //不清空的话,也不可能
106 | mHWPointList.clear();
107 | //记录down的控制点的信息
108 | ControllerPoint curPoint = new ControllerPoint(mElement.x, mElement.y);
109 | //如果用笔画的画我的屏幕,记录他宽度的和压力值的乘,但是哇,
110 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
111 | mLastWidth = mElement.pressure * mBaseWidth;
112 | } else {
113 | //如果是手指画的,我们取他的0.8
114 | mLastWidth = 0.8 * mBaseWidth;
115 | }
116 | //down下的点的宽度
117 | curPoint.width = (float) mLastWidth;
118 | mLastVel = 0;
119 | mPointList.add(curPoint);
120 | //记录当前的点
121 | mLastPoint = curPoint;
122 | }
123 |
124 | protected Paint getNewPaint(Paint paint) {
125 | return null;
126 | }
127 |
128 | /**
129 | * 手指移动的事件
130 | *
131 | * @param mElement
132 | */
133 | public void onMove(MotionElement mElement) {
134 |
135 | ControllerPoint curPoint = new ControllerPoint(mElement.x, mElement.y);
136 | double deltaX = curPoint.x - mLastPoint.x;
137 | double deltaY = curPoint.y - mLastPoint.y;
138 | //deltaX和deltay平方和的二次方根 想象一个例子 1+1的平方根为1.4 (x²+y²)开根号
139 | //同理,当滑动的越快的话,deltaX+deltaY的值越大,这个越大的话,curDis也越大
140 | double curDis = Math.hypot(deltaX, deltaY);
141 | //我们求出的这个值越小,画的点或者是绘制椭圆形越多,这个值越大的话,绘制的越少,笔就越细,宽度越小
142 | double curVel = curDis * IPenConfig.DIS_VEL_CAL_FACTOR;
143 | double curWidth;
144 | //点的集合少,我们得必须改变宽度,每次点击的down的时候,这个事件
145 | if (mPointList.size() < 2) {
146 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
147 | curWidth = mElement.pressure * mBaseWidth;
148 | } else {
149 | curWidth = calcNewWidth(curVel, mLastVel, curDis, 1.5,
150 | mLastWidth);
151 | }
152 | curPoint.width = (float) curWidth;
153 | mBezier.init(mLastPoint, curPoint);
154 | } else {
155 | mLastVel = curVel;
156 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
157 | curWidth = mElement.pressure * mBaseWidth;
158 | } else {
159 | //由于我们手机是触屏的手机,滑动的速度也不慢,所以,一般会走到这里来
160 | //阐明一点,当滑动的速度很快的时候,这个值就越小,越慢就越大,依靠着mlastWidth不断的变换
161 | curWidth = calcNewWidth(curVel, mLastVel, curDis, 1.5,
162 | mLastWidth);
163 | }
164 | curPoint.width = (float) curWidth;
165 | mBezier.addNode(curPoint);
166 | }
167 | //每次移动的话,这里赋值新的值
168 | mLastWidth = curWidth;
169 | mPointList.add(curPoint);
170 | moveNeetToDo(curDis);
171 | mLastPoint = curPoint;
172 | }
173 |
174 |
175 | /**
176 | * 手指抬起来的事件
177 | *
178 | * @param mElement
179 | * @param canvas
180 | */
181 | public void onUp(MotionElement mElement, Canvas canvas) {
182 |
183 | mCurPoint = new ControllerPoint(mElement.x, mElement.y);
184 | double deltaX = mCurPoint.x - mLastPoint.x;
185 | double deltaY = mCurPoint.y - mLastPoint.y;
186 | double curDis = Math.hypot(deltaX, deltaY);
187 | //如果用笔画的画我的屏幕,记录他宽度的和压力值的乘,但是哇,这个是不会变的
188 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
189 | mCurPoint.width = (float) (mElement.pressure * mBaseWidth);
190 | } else {
191 | mCurPoint.width = 0;
192 | }
193 |
194 | mPointList.add(mCurPoint);
195 |
196 | mBezier.addNode(mCurPoint);
197 |
198 | int steps = 1 + (int) curDis / IPenConfig.STEPFACTOR;
199 | double step = 1.0 / steps;
200 | for (double t = 0; t < 1.0; t += step) {
201 | ControllerPoint point = mBezier.getPoint(t);
202 | mHWPointList.add(point);
203 | }
204 | //
205 | mBezier.end();
206 | for (double t = 0; t < 1.0; t += step) {
207 | ControllerPoint point = mBezier.getPoint(t);
208 | mHWPointList.add(point);
209 | }
210 |
211 | // 手指up 我画到纸上上
212 | draw(canvas);
213 | //每次抬起手来,就把集合清空,在水彩笔的那个地方,如果啊,我说如果不清空的话,每次抬起手来,
214 | // 在onDown下去的话,最近画的线的透明度有改变,所以这里clear下线的集合
215 | clear();
216 | }
217 |
218 | /**
219 | * @param curVel
220 | * @param lastVel
221 | * @param curDis
222 | * @param factor
223 | * @param lastWidth
224 | * @return
225 | */
226 | public double calcNewWidth(double curVel, double lastVel, double curDis,
227 | double factor, double lastWidth) {
228 | double calVel = curVel * 0.6 + lastVel * (1 - 0.6);
229 | //返回指定数字的自然对数
230 | //手指滑动的越快,这个值越小,为负数
231 | double vfac = Math.log(factor * 2.0f) * (-calVel);
232 | //此方法返回值e,其中e是自然对数的基数。
233 | //Math.exp(vfac) 变化范围为0 到1 当手指没有滑动的时候 这个值为1 当滑动很快的时候无线趋近于0
234 | //在次说明下,当手指抬起来,这个值会变大,这也就说明,抬起手太慢的话,笔锋效果不太明显
235 | //这就说明为什么笔锋的效果不太明显
236 | double calWidth = mBaseWidth * Math.exp(vfac);
237 |
238 | //滑动的速度越快的话,mMoveThres也越大
239 | double mMoveThres = curDis * 0.01f;
240 | //对之值最大的地方进行控制
241 | if (mMoveThres > IPenConfig.WIDTH_THRES_MAX) {
242 | mMoveThres = IPenConfig.WIDTH_THRES_MAX;
243 | }
244 | // TODO: 2018/2/24 以下的方法 可以删除掉 原因是抽取了一下 ,本来不应该在这里的出现的 不好意思
245 | // //滑动越慢的情况下,得到的calWidth 和上面的calwidth 相差的值不一样
246 | //
247 | // //滑动的越快的话,第一个判断会走
248 | // if (Math.abs(calWidth - mBaseWidth) / mBaseWidth > mMoveThres) {
249 | // if (calWidth > mBaseWidth) {
250 | // calWidth = mBaseWidth * (1 + mMoveThres);
251 | // } else {
252 | // calWidth = mBaseWidth * (1 - mMoveThres);
253 | // }
254 | // //滑动的越慢的话,第二个判断会走 基本上在屏幕上手指基本上没有走动的时候 ,就会走这个方法
255 | // } else if (Math.abs(calWidth - lastWidth) / lastWidth > mMoveThres) {
256 | // if (calWidth > lastWidth) {
257 | // calWidth = lastWidth * (1 + mMoveThres);
258 | // } else {
259 | // calWidth = lastWidth * (1 - mMoveThres);
260 | // }
261 | // }
262 | return calWidth;
263 | }
264 |
265 | /**
266 | * event.getPressure(); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的,我的手机上为1
267 | *
268 | * @param motionEvent
269 | * @return
270 | */
271 | public MotionElement createMotionElement(MotionEvent motionEvent) {
272 | MotionElement motionElement = new MotionElement(motionEvent.getX(), motionEvent.getY(),
273 | motionEvent.getPressure(), motionEvent.getToolType(0));
274 | return motionElement;
275 | }
276 |
277 | public void clear() {
278 | mPointList.clear();
279 | mHWPointList.clear();
280 | }
281 |
282 | /**
283 | * 当现在的点和触摸点的位置在一起的时候不用去绘制
284 | * 但是这里也可以优化,当一直处于onDown事件的时候,其实这个方法一只在走
285 | *
286 | * @param canvas
287 | * @param point
288 | * @param paint
289 | */
290 | // TODO: 2017/10/18 这里可以优化 当一直处于onDown事件的时候,其实这个方法一直在走,优化的点是,处于down事件,这里不需要走
291 | protected void drawToPoint(Canvas canvas, ControllerPoint point, Paint paint) {
292 | if ((mCurPoint.x == point.x) && (mCurPoint.y == point.y)) {
293 | return;
294 | }
295 | //水彩笔的效果和钢笔的不太一样,交给自己去实现
296 | doNeetToDo(canvas, point, paint);
297 | }
298 |
299 | /**
300 | * 判断笔是否为空 节约性能,每次切换笔的时候就不用重复设置了
301 | *
302 | * @return
303 | */
304 | public boolean isNull() {
305 | return mPaint == null;
306 | }
307 |
308 | /**
309 | * 移动的时候,这里由于需要透明度的处理,交给子类
310 | *
311 | * @param
312 | */
313 | protected abstract void moveNeetToDo(double f);
314 |
315 | /**
316 | * 这里交给子类,一个是绘制椭圆,一个是绘制bitmap
317 | *
318 | * @param canvas
319 | * @param point
320 | * @param paint
321 | */
322 | protected abstract void doNeetToDo(Canvas canvas, ControllerPoint point, Paint paint);
323 |
324 | /**
325 | * 这里由于在设置笔的透明度,会导致整个线,或者说整个画布的的颜透明度随着整个笔的透明度而变化,
326 | * 所以在这里考虑是不是说,绘制毛笔的时候,每次都给它new 一个paint ,但是这里我还没有找到更好的办法
327 | *
328 | * @param canvas
329 | */
330 | // TODO: 2017/10/17 这个问题 待解决
331 | protected abstract void drawNeetToDo(Canvas canvas);
332 |
333 |
334 | }
335 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/BrushPen.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.PorterDuff;
10 | import android.graphics.PorterDuffXfermode;
11 | import android.graphics.Rect;
12 | import android.graphics.RectF;
13 |
14 | import com.shiming.pen.R;
15 | import com.shiming.pen.old_code.ControllerPoint;
16 |
17 |
18 | /**
19 | * @author shiming
20 | * @version v1.0 create at 2017/10/10
21 | * @des 水彩笔
22 | */
23 | public class BrushPen extends BasePenExtend {
24 |
25 | private Bitmap mBitmap;
26 | //第一个Rect 代表要绘制的bitmap 区域,
27 | protected Rect mOldRect = new Rect();
28 | //第二个 Rect 代表的是要将bitmap 绘制在屏幕的什么地方
29 | protected RectF mNeedDrawRect = new RectF();
30 | protected Bitmap mOriginBitmap;
31 |
32 | public BrushPen(Context context) {
33 | super(context);
34 | initTexture();
35 | }
36 |
37 | /**
38 | * 由于需要画笔piant中的一些信息,就不能让paint为null,所以setBitmap需要有paint的时候设置
39 | *
40 | * @param paint
41 | */
42 | @Override
43 | public void setPaint(Paint paint) {
44 | super.setPaint(paint);
45 | setBitmap(mOriginBitmap);
46 | }
47 |
48 | /**
49 | * 感谢公司的ui大哥 小伍哥 免费给的切图
50 | * R.mipmap.tranglie 设置的时候有点像三角形的笔锋
51 | * R.mipmap.cicrle 圆形的笔锋效果
52 | * R.mipmap.six 六边形有点怪怪的,可以测试一下
53 | * R.drawable.brush 这个才是用起来比较舒服,如果你的笔锋要很尖的话,叫ui爸爸给你裁剪这种图 越尖越好
54 | */
55 | private void initTexture() {
56 | //通过资源文件生成的原始的bitmap区域 后面的资源图有些更加有意识的东西
57 | mOriginBitmap = BitmapFactory.decodeResource(
58 | mContext.getResources(), R.mipmap.brush);
59 | }
60 |
61 | /**
62 | * 主要是得到需要绘制的rect的区域
63 | *
64 | * @param bitmap
65 | */
66 | private void setBitmap(Bitmap bitmap) {
67 | Canvas canvas = new Canvas();
68 | mBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
69 | Bitmap.Config.ARGB_8888);
70 | //用指定的方式填充位图的像素。
71 | mBitmap.eraseColor(Color.rgb(Color.red(mPaint.getColor()),
72 | Color.green(mPaint.getColor()), Color.blue(mPaint.getColor())));
73 | //用画布制定位图绘制
74 | canvas.setBitmap(mBitmap);
75 | Paint paint = new Paint();
76 | // 设置混合模式 (只在源图像和目标图像相交的地方绘制目标图像)
77 | //最常见的应用就是蒙板绘制,利用源图作为蒙板“抠出”目标图上的图像。
78 | //如果把这行代码注释掉这里生成的东西更加有意思
79 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
80 | canvas.drawBitmap(bitmap, 0, 0, paint);
81 |
82 | //src 代表需要绘制的区域
83 | mOldRect.set(0, 0, mBitmap.getWidth() / 4, mBitmap.getHeight() / 4);
84 | }
85 |
86 |
87 | /**
88 | * 更具笔的宽度的变化,笔的透明度要和发生变化
89 | *
90 | * @param point
91 | * @return
92 | */
93 | private ControllerPoint getWithPointAlphaPoint(ControllerPoint point) {
94 | ControllerPoint nPoint = new ControllerPoint();
95 | nPoint.x = point.x;
96 | nPoint.y = point.y;
97 | nPoint.width = point.width;
98 | int alpha = (int) (255 * point.width / mBaseWidth / 2);
99 | if (alpha < 10) {
100 | alpha = 10;
101 | } else if (alpha > 255) {
102 | alpha = 255;
103 | }
104 | nPoint.alpha = alpha;
105 | return nPoint;
106 | }
107 |
108 |
109 | @Override
110 | protected void doNeetToDo(Canvas canvas, ControllerPoint point, Paint paint) {
111 | drawLine(canvas, mCurPoint.x, mCurPoint.y, mCurPoint.width,
112 | mCurPoint.alpha, point.x, point.y, point.width, point.alpha,
113 | paint);
114 | }
115 |
116 | /**
117 | * 感谢作者,请教下怎么实时获取笔锋的宽度?
118 | *
119 | * @param canvas
120 | * @param x0
121 | * @param y0
122 | * @param w0
123 | * @param a0
124 | * @param x1
125 | * @param y1
126 | * @param w1
127 | * @param a1
128 | * @param paint
129 | */
130 | protected void drawLine(Canvas canvas, double x0, double y0, double w0,
131 | int a0, double x1, double y1, double w1, int a1, Paint paint) {
132 | double curDis = Math.hypot(x0 - x1, y0 - y1);
133 | int factor = 2;
134 | if (paint.getStrokeWidth() < 6) {
135 | factor = 1;
136 | } else if (paint.getStrokeWidth() > 60) {
137 | factor = 3;
138 | }
139 | int steps = 1 + (int) (curDis / factor);
140 | double deltaX = (x1 - x0) / steps;
141 | double deltaY = (y1 - y0) / steps;
142 | double deltaW = (w1 - w0) / steps;
143 | double deltaA = (a1 - a0) / steps;
144 | double x = x0;
145 | double y = y0;
146 | double w = w0;
147 | double a = a0;
148 |
149 | for (int i = 0; i < steps; i++) {
150 | if (w < 1.5)
151 | w = 1.5;
152 | //根据点的信息计算出需要把bitmap绘制在什么地方
153 | mNeedDrawRect.set((float) (x - w / 2.0f), (float) (y - w / 2.0f),
154 | (float) (x + w / 2.0f), (float) (y + w / 2.0f));
155 | //每次到这里来的话,这个笔的透明度就会发生改变,但是呢,这个笔不用同一个的话,有点麻烦
156 | //我在这里做了个不是办法的办法,每次呢?我都从新new了一个新的笔,每次循环就new一个,内存就有很多的笔了
157 | //这里new 新的笔 我放到外面去做了
158 | //Paint newPaint = new Paint(paint);
159 | //当这里很小的时候,透明度就会很小,个人测试在3.0左右比较靠谱
160 | paint.setAlpha((int) (a / 3.0f));
161 | //第一个Rect 代表要绘制的bitmap 区域,第二个 Rect 代表的是要将bitmap 绘制在屏幕的什么地方
162 | canvas.drawBitmap(mBitmap, mOldRect, mNeedDrawRect, paint);
163 | x += deltaX;
164 | y += deltaY;
165 | w += deltaW;
166 | a += deltaA;
167 | }
168 | }
169 |
170 |
171 | @Override
172 | protected void drawNeetToDo(Canvas canvas) {
173 | for (int i = 1; i < mHWPointList.size(); i++) {
174 | ControllerPoint point = mHWPointList.get(i);
175 | drawToPoint(canvas, point, mPaint);
176 | mCurPoint = point;
177 | }
178 | }
179 |
180 | @Override
181 | protected void moveNeetToDo(double curDis) {
182 | //水彩笔的效果
183 | int steps = 1 + (int) curDis / IPenConfig.STEPFACTOR;
184 | double step = 1.0 / steps;
185 | for (double t = 0; t < 1.0; t += step) {
186 | ControllerPoint point = mBezier.getPoint(t);
187 | point = getWithPointAlphaPoint(point);
188 | mHWPointList.add(point);
189 | }
190 |
191 | }
192 |
193 | //对每个笔设置了透明度 如果这里不设置一个新的笔的话,每次down事件发生了,就会把一起的绘制完成的东西,透明度也发生改变,
194 | //这里还有想到更好的方法,
195 | // TODO: 2017/10/18
196 | //虽然这样设置了,但是还是有问题,每次down的时候,虽然是一根新的笔,但是原来的笔始终有点小小的问题
197 | @Override
198 | protected Paint getNewPaint(Paint paint) {
199 | return new Paint(paint);
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/IPenConfig.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.graphics.Color;
4 |
5 | /**
6 | * @author shiming
7 | * @version v1.0 create at 2017/10/10
8 | * @des 笔的设置,但是有些笔的设置最好不要放在这里,不要笔的颜色和宽度
9 | */
10 | public interface IPenConfig {
11 |
12 | /**
13 | * 清除画布
14 | */
15 | int STROKE_TYPE_ERASER = 0;
16 |
17 | /**
18 | * 钢笔
19 | */
20 | int STROKE_TYPE_PEN = 1;// 钢笔
21 | /**
22 | * 毛笔
23 | */
24 | int STROKE_TYPE_BRUSH = 2;// 毛笔
25 |
26 | //设置笔的宽度
27 | int PEN_WIDTH = 60;
28 | //笔的颜色
29 | int PEN_CORLOUR = Color.parseColor("#FF4081");
30 |
31 | //这个控制笔锋的控制值
32 | float DIS_VEL_CAL_FACTOR = 0.02f;
33 | //手指在移动的控制笔的变化率 这个值越大,线条的粗细越加明显
34 | //float WIDTH_THRES_MAX = 0.6f;
35 | float WIDTH_THRES_MAX = 10f;
36 | //绘制计算的次数,数值越小计算的次数越多,需要折中
37 | int STEPFACTOR = 10;
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/MotionElement.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | /**
4 | * @author shiming
5 | * @version v1.0 create at 2017/10/10
6 | * @des
7 | */
8 | public class MotionElement {
9 |
10 | public float x;
11 | public float y;
12 | //压力值 物理设备决定的,和设计的设备有关系,在此Demo中没有用到 ,但是这个坑 记录下
13 | public float pressure;
14 | //绘制的工具是否是手指或者是笔(触摸笔)
15 | public int tooltype;
16 |
17 | public MotionElement(float mx, float my, float mp, int ttype) {
18 | x = mx;
19 | y = my;
20 | pressure = mp;
21 | tooltype = ttype;
22 | }
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/NewDrawPenView.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.PorterDuff;
10 | import android.graphics.PorterDuffXfermode;
11 | import android.util.AttributeSet;
12 | import android.util.DisplayMetrics;
13 | import android.util.Log;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 |
17 | import com.shiming.pen.field_character.DrawPenView;
18 |
19 | import static com.shiming.pen.new_code.IPenConfig.PEN_WIDTH;
20 |
21 |
22 | /**
23 | * @author shiming
24 | * @version v1.0 create at 2017/8/24
25 | * @des DrawPenView实现手写关键类,目前只提供了,手绘的功能和清除画布,后期根据业务逻辑可以动态的设置方法
26 | */
27 | public class NewDrawPenView extends View {
28 | private static final String TAG = "DrawPenView";
29 | private Paint mPaint;//画笔
30 | private Canvas mCanvas;//画布
31 | private Bitmap mBitmap;
32 | private Context mContext;
33 | public static int mCanvasCode = IPenConfig.STROKE_TYPE_PEN;
34 | private BasePenExtend mStokeBrushPen;
35 | private boolean mIsCanvasDraw;
36 | private int mPenconfig;
37 |
38 | public NewDrawPenView(Context context) {
39 | super(context);
40 | initParameter(context);
41 | }
42 |
43 | public NewDrawPenView(Context context, AttributeSet attrs) {
44 | super(context, attrs);
45 | initParameter(context);
46 | }
47 |
48 | public NewDrawPenView(Context context, AttributeSet attrs, int defStyleAttr) {
49 | super(context, attrs, defStyleAttr);
50 | initParameter(context);
51 | }
52 |
53 | private void initParameter(Context context) {
54 | mContext = context;
55 | DisplayMetrics dm = new DisplayMetrics();
56 | ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
57 | mBitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Bitmap.Config.ARGB_8888);
58 | mStokeBrushPen = new SteelPen(context);
59 | initPaint();
60 | initCanvas();
61 | }
62 |
63 |
64 | private void initPaint() {
65 | mPaint = new Paint();
66 | mPaint.setColor(IPenConfig.PEN_CORLOUR);
67 | mPaint.setStrokeWidth(PEN_WIDTH);
68 | mPaint.setStyle(Paint.Style.STROKE);
69 | mPaint.setStrokeCap(Paint.Cap.ROUND);//结束的笔画为圆心
70 | mPaint.setStrokeJoin(Paint.Join.ROUND);//连接处元
71 | mPaint.setAlpha(0xFF);
72 | mPaint.setAntiAlias(true);
73 | mPaint.setStrokeMiter(1.0f);
74 | mStokeBrushPen.setPaint(mPaint);
75 | }
76 |
77 | private void initCanvas() {
78 | mCanvas = new Canvas(mBitmap);
79 | //设置画布的颜色的问题
80 | mCanvas.drawColor(Color.TRANSPARENT);
81 | }
82 |
83 | @Override
84 | protected void onDraw(Canvas canvas) {
85 | canvas.drawBitmap(mBitmap, 0, 0, mPaint);
86 | switch (mCanvasCode) {
87 | case IPenConfig.STROKE_TYPE_PEN:
88 | case IPenConfig.STROKE_TYPE_BRUSH:
89 | mStokeBrushPen.draw(canvas);
90 | break;
91 | case IPenConfig.STROKE_TYPE_ERASER:
92 | reset();
93 | break;
94 | default:
95 | Log.e(TAG, "onDraw" + Integer.toString(mCanvasCode));
96 | break;
97 | }
98 | super.onDraw(canvas);
99 | }
100 |
101 |
102 | public void setCanvasCode(int canvasCode) {
103 | mCanvasCode = canvasCode;
104 | switch (mCanvasCode) {
105 | case IPenConfig.STROKE_TYPE_PEN:
106 | mStokeBrushPen = new SteelPen(mContext);
107 | break;
108 | case IPenConfig.STROKE_TYPE_BRUSH:
109 | mStokeBrushPen = new BrushPen(mContext);
110 | break;
111 |
112 | }
113 | //设置
114 | if (mStokeBrushPen.isNull()) {
115 | mStokeBrushPen.setPaint(mPaint);
116 | }
117 | invalidate();
118 | }
119 |
120 | /**
121 | * event.getAction() //获取触控动作比如ACTION_DOWN
122 | * event.getPointerCount(); //获取触控点的数量,比如2则可能是两个手指同时按压屏幕
123 | * event.getPointerId(nID); //对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引
124 | * event.getX(nID); //获取第nID个触控点的x位置,记录的第一个点为getX,getY
125 | * event.getY(nID); //获取第nID个点触控的y位置
126 | * event.getPressure(nID); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的
127 | * event.getDownTime() //按下开始时间
128 | * event.getEventTime() // 事件结束时间
129 | * event.getEventTime()-event.getDownTime()); //总共按下时花费时间
130 | *
131 | * @param event
132 | * @return
133 | */
134 | @Override
135 | public boolean onTouchEvent(MotionEvent event) {
136 | mIsCanvasDraw = true;
137 | MotionEvent event2 = MotionEvent.obtain(event);
138 | mStokeBrushPen.onTouchEvent(event2, mCanvas);
139 | //event会被下一次事件重用,这里必须生成新的,否则会有问题
140 | //getActionMask:触摸的动作,按下,抬起,滑动,多点按下,多点抬起
141 | switch (event2.getActionMasked()) {
142 | case MotionEvent.ACTION_DOWN:
143 | if (mGetTimeListner != null)
144 | mGetTimeListner.stopTime();
145 | break;
146 | case MotionEvent.ACTION_MOVE:
147 | if (mGetTimeListner != null)
148 | mGetTimeListner.stopTime();
149 | break;
150 | case MotionEvent.ACTION_UP:
151 | long time = System.currentTimeMillis();
152 | if (mGetTimeListner != null)
153 | mGetTimeListner.getTime(time);
154 | break;
155 | default:
156 | break;
157 | }
158 | invalidate();
159 | return true;
160 | }
161 |
162 | /**
163 | * @return 判断是否有绘制内容在画布上
164 | */
165 | public boolean getHasDraw() {
166 | return mIsCanvasDraw;
167 | }
168 |
169 | /**
170 | * 清除画布,记得清除点的集合
171 | */
172 | public void reset() {
173 | mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
174 | mCanvas.drawPaint(mPaint);
175 | mPaint.setXfermode(null);
176 | mIsCanvasDraw = false;
177 | mStokeBrushPen.clear();
178 | //这里处理的不太好 需要优化
179 | mCanvasCode = mPenconfig;
180 |
181 | }
182 |
183 | public TimeListener mGetTimeListner;
184 |
185 | public void setGetTimeListener(TimeListener l) {
186 | mGetTimeListner = l;
187 | }
188 |
189 | public Bitmap getBitmap() {
190 | return mBitmap;
191 | }
192 |
193 | public void setPenconfig(int penconfig) {
194 | mPenconfig = penconfig;
195 |
196 | }
197 |
198 | public interface TimeListener {
199 | void getTime(long l);
200 |
201 | void stopTime();
202 | }
203 |
204 | private int mBackColor = Color.TRANSPARENT;
205 |
206 | /**
207 | * 逐行扫描 清楚边界空白。功能是生成一张bitmap位于正中间,不是位于顶部,此关键的是我们画布需要
208 | * 成透明色才能生效
209 | *
210 | * @param blank 边距留多少个像素
211 | * @return tks github E-signature
212 | */
213 | public Bitmap clearBlank(int blank) {
214 | if (mBitmap != null) {
215 | int HEIGHT = mBitmap.getHeight();//1794
216 | int WIDTH = mBitmap.getWidth();//1080
217 | int top = 0, left = 0, right = 0, bottom = 0;
218 | int[] pixs = new int[WIDTH];
219 | boolean isStop;
220 | for (int y = 0; y < HEIGHT; y++) {
221 | mBitmap.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
222 | isStop = false;
223 | for (int pix : pixs) {
224 | if (pix != mBackColor) {
225 |
226 | top = y;
227 | isStop = true;
228 | break;
229 | }
230 | }
231 | if (isStop) {
232 | break;
233 | }
234 | }
235 | for (int y = HEIGHT - 1; y >= 0; y--) {
236 | mBitmap.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
237 | isStop = false;
238 | for (int pix : pixs) {
239 | if (pix != mBackColor) {
240 | bottom = y;
241 | isStop = true;
242 | break;
243 | }
244 | }
245 | if (isStop) {
246 | break;
247 | }
248 | }
249 | pixs = new int[HEIGHT];
250 | for (int x = 0; x < WIDTH; x++) {
251 | mBitmap.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
252 | isStop = false;
253 | for (int pix : pixs) {
254 | if (pix != mBackColor) {
255 | left = x;
256 | isStop = true;
257 | break;
258 | }
259 | }
260 | if (isStop) {
261 | break;
262 | }
263 | }
264 | for (int x = WIDTH - 1; x > 0; x--) {
265 | mBitmap.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
266 | isStop = false;
267 | for (int pix : pixs) {
268 | if (pix != mBackColor) {
269 | right = x;
270 | isStop = true;
271 | break;
272 | }
273 | }
274 | if (isStop) {
275 | break;
276 | }
277 | }
278 | if (blank < 0) {
279 | blank = 0;
280 | }
281 | left = left - blank > 0 ? left - blank : 0;
282 | top = top - blank > 0 ? top - blank : 0;
283 | right = right + blank > WIDTH - 1 ? WIDTH - 1 : right + blank;
284 | bottom = bottom + blank > HEIGHT - 1 ? HEIGHT - 1 : bottom + blank;
285 | return Bitmap.createBitmap(mBitmap, left, top, right - left, bottom - top);
286 | } else {
287 | return null;
288 | }
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/PenUtils.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Color;
5 |
6 | /**
7 | * @author shiming
8 | * @version v1.0 create at 2017/10/10
9 | * @des
10 | */
11 | public class PenUtils {
12 |
13 | private int mBackColor = Color.TRANSPARENT;
14 |
15 | /**
16 | * 逐行扫描 清楚边界空白。功能是生成一张bitmap位于正中间,不是位于顶部,此关键的是我们画布需要
17 | * 成透明色才能生效
18 | *
19 | * @param blank 边距留多少个像素
20 | * @return tks github E-signature
21 | */
22 | public Bitmap clearBlank(Bitmap mBitmap, int blank) {
23 | if (mBitmap != null) {
24 | int HEIGHT = mBitmap.getHeight();
25 | int WIDTH = mBitmap.getWidth();
26 | int top = 0, left = 0, right = 0, bottom = 0;
27 | int[] pixs = new int[WIDTH];
28 | boolean isStop;
29 | for (int y = 0; y < HEIGHT; y++) {
30 | mBitmap.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
31 | isStop = false;
32 | for (int pix : pixs) {
33 | if (pix != mBackColor) {
34 |
35 | top = y;
36 | isStop = true;
37 | break;
38 | }
39 | }
40 | if (isStop) {
41 | break;
42 | }
43 | }
44 | for (int y = HEIGHT - 1; y >= 0; y--) {
45 | mBitmap.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
46 | isStop = false;
47 | for (int pix : pixs) {
48 | if (pix != mBackColor) {
49 | bottom = y;
50 | isStop = true;
51 | break;
52 | }
53 | }
54 | if (isStop) {
55 | break;
56 | }
57 | }
58 | pixs = new int[HEIGHT];
59 | for (int x = 0; x < WIDTH; x++) {
60 | mBitmap.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
61 | isStop = false;
62 | for (int pix : pixs) {
63 | if (pix != mBackColor) {
64 | left = x;
65 | isStop = true;
66 | break;
67 | }
68 | }
69 | if (isStop) {
70 | break;
71 | }
72 | }
73 | for (int x = WIDTH - 1; x > 0; x--) {
74 | mBitmap.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
75 | isStop = false;
76 | for (int pix : pixs) {
77 | if (pix != mBackColor) {
78 | right = x;
79 | isStop = true;
80 | break;
81 | }
82 | }
83 | if (isStop) {
84 | break;
85 | }
86 | }
87 | if (blank < 0) {
88 | blank = 0;
89 | }
90 | left = left - blank > 0 ? left - blank : 0;
91 | top = top - blank > 0 ? top - blank : 0;
92 | right = right + blank > WIDTH - 1 ? WIDTH - 1 : right + blank;
93 | bottom = bottom + blank > HEIGHT - 1 ? HEIGHT - 1 : bottom + blank;
94 | return Bitmap.createBitmap(mBitmap, left, top, right - left, bottom - top);
95 | } else {
96 | return null;
97 | }
98 | }
99 |
100 | //**将rgb色彩值转成16进制代码**
101 | public String convertRGBToHex(int r, int g, int b) {
102 | String rFString, rSString, gFString, gSString,
103 | bFString, bSString, result;
104 | int red, green, blue;
105 | int rred, rgreen, rblue;
106 | red = r / 16;
107 | rred = r % 16;
108 | if (red == 10)
109 | rFString = "A";
110 | else if (red == 11)
111 | rFString = "B";
112 | else if (red == 12)
113 | rFString = "C";
114 | else if (red == 13)
115 | rFString = "D";
116 | else if (red == 14)
117 | rFString = "E";
118 | else if (red == 15)
119 | rFString = "F";
120 | else
121 | rFString = String.valueOf(red);
122 |
123 | if (rred == 10)
124 | rSString = "A";
125 | else if (rred == 11)
126 | rSString = "B";
127 | else if (rred == 12)
128 | rSString = "C";
129 | else if (rred == 13)
130 | rSString = "D";
131 | else if (rred == 14)
132 | rSString = "E";
133 | else if (rred == 15)
134 | rSString = "F";
135 | else
136 | rSString = String.valueOf(rred);
137 |
138 | rFString = rFString + rSString;
139 |
140 | green = g / 16;
141 | rgreen = g % 16;
142 |
143 | if (green == 10)
144 | gFString = "A";
145 | else if (green == 11)
146 | gFString = "B";
147 | else if (green == 12)
148 | gFString = "C";
149 | else if (green == 13)
150 | gFString = "D";
151 | else if (green == 14)
152 | gFString = "E";
153 | else if (green == 15)
154 | gFString = "F";
155 | else
156 | gFString = String.valueOf(green);
157 |
158 | if (rgreen == 10)
159 | gSString = "A";
160 | else if (rgreen == 11)
161 | gSString = "B";
162 | else if (rgreen == 12)
163 | gSString = "C";
164 | else if (rgreen == 13)
165 | gSString = "D";
166 | else if (rgreen == 14)
167 | gSString = "E";
168 | else if (rgreen == 15)
169 | gSString = "F";
170 | else
171 | gSString = String.valueOf(rgreen);
172 |
173 | gFString = gFString + gSString;
174 |
175 | blue = b / 16;
176 | rblue = b % 16;
177 |
178 | if (blue == 10)
179 | bFString = "A";
180 | else if (blue == 11)
181 | bFString = "B";
182 | else if (blue == 12)
183 | bFString = "C";
184 | else if (blue == 13)
185 | bFString = "D";
186 | else if (blue == 14)
187 | bFString = "E";
188 | else if (blue == 15)
189 | bFString = "F";
190 | else
191 | bFString = String.valueOf(blue);
192 |
193 | if (rblue == 10)
194 | bSString = "A";
195 | else if (rblue == 11)
196 | bSString = "B";
197 | else if (rblue == 12)
198 | bSString = "C";
199 | else if (rblue == 13)
200 | bSString = "D";
201 | else if (rblue == 14)
202 | bSString = "E";
203 | else if (rblue == 15)
204 | bSString = "F";
205 | else
206 | bSString = String.valueOf(rblue);
207 | bFString = bFString + bSString;
208 | result = "#" + rFString + gFString + bFString;
209 | return result;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/new_code/SteelPen.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.new_code;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.RectF;
7 |
8 | import com.shiming.pen.old_code.ControllerPoint;
9 |
10 | import static com.shiming.pen.new_code.IPenConfig.STEPFACTOR;
11 |
12 | /**
13 | * @author shiming
14 | * @version v1.0 create at 2017/10/17
15 | * @des 钢笔
16 | */
17 | public class SteelPen extends BasePenExtend {
18 |
19 | public SteelPen(Context context) {
20 | super(context);
21 | }
22 |
23 | @Override
24 | protected void drawNeetToDo(Canvas canvas) {
25 | for (int i = 1; i < mHWPointList.size(); i++) {
26 | ControllerPoint point = mHWPointList.get(i);
27 | drawToPoint(canvas, point, mPaint);
28 | mCurPoint = point;
29 | }
30 | }
31 |
32 | @Override
33 | protected void moveNeetToDo(double curDis) {
34 | int steps = 1 + (int) curDis / STEPFACTOR;
35 | double step = 1.0 / steps;
36 | for (double t = 0; t < 1.0; t += step) {
37 | ControllerPoint point = mBezier.getPoint(t);
38 | mHWPointList.add(point);
39 | }
40 | }
41 |
42 | @Override
43 | protected void doNeetToDo(Canvas canvas, ControllerPoint point, Paint paint) {
44 | drawLine(canvas, mCurPoint.x, mCurPoint.y, mCurPoint.width, point.x,
45 | point.y, point.width, paint);
46 | }
47 |
48 | /**
49 | * 其实这里才是关键的地方,通过画布画椭圆,每一个点都是一个椭圆,这个椭圆的所有细节,逐渐构建出一个完美的笔尖
50 | * 和笔锋的效果,我觉得在这里需要大量的测试,其实就对低端手机进行排查,看我们绘制的笔的宽度是多少,绘制多少个椭圆
51 | * 然后在低端手机上不会那么卡,当然你哪一个N年前的手机给我,那也的卡,只不过需要适中的范围里面
52 | *
53 | * @param canvas
54 | * @param x0
55 | * @param y0
56 | * @param w0
57 | * @param x1
58 | * @param y1
59 | * @param w1
60 | * @param paint
61 | */
62 | private void drawLine(Canvas canvas, double x0, double y0, double w0, double x1, double y1, double w1, Paint paint) {
63 | //求两个数字的平方根 x的平方+y的平方在开方记得X的平方+y的平方=1,这就是一个园
64 | double curDis = Math.hypot(x0 - x1, y0 - y1);
65 | int steps = 1;
66 | if (paint.getStrokeWidth() < 6) {
67 | steps = 1 + (int) (curDis / 2);
68 | } else if (paint.getStrokeWidth() > 60) {
69 | steps = 1 + (int) (curDis / 4);
70 | } else {
71 | steps = 1 + (int) (curDis / 3);
72 | }
73 | double deltaX = (x1 - x0) / steps;
74 | double deltaY = (y1 - y0) / steps;
75 | double deltaW = (w1 - w0) / steps;
76 | double x = x0;
77 | double y = y0;
78 | double w = w0;
79 |
80 | for (int i = 0; i < steps; i++) {
81 | //都是用于表示坐标系中的一块矩形区域,并可以对其做一些简单操作
82 | //精度不一样。Rect是使用int类型作为数值,RectF是使用float类型作为数值。
83 | // Rect rect = new Rect();
84 | RectF oval = new RectF();
85 | oval.set((float) (x - w / 4.0f), (float) (y - w / 2.0f), (float) (x + w / 4.0f), (float) (y + w / 2.0f));
86 | // oval.set((float)(x+w/4.0f), (float)(y+w/4.0f), (float)(x-w/4.0f), (float)(y-w/4.0f));
87 | //最基本的实现,通过点控制线,绘制椭圆
88 | canvas.drawOval(oval, paint);
89 | x += deltaX;
90 | y += deltaY;
91 | w += deltaW;
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/old_code/ControllerPoint.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.old_code;
2 |
3 |
4 | /**
5 | * @author shiming
6 | * @version v1.0 create at 2017/8/24
7 | * @des 每个点的控制,关心三个因素:笔的宽度,坐标,透明数值
8 | */
9 | public class ControllerPoint {
10 | public float x;
11 | public float y;
12 |
13 | public float width;
14 | public int alpha = 255;
15 |
16 | public ControllerPoint() {
17 | }
18 |
19 | public ControllerPoint(float x, float y) {
20 | this.x = x;
21 | this.y = y;
22 | }
23 |
24 |
25 | public void set(float x, float y, float w) {
26 | this.x = x;
27 | this.y = y;
28 | this.width = w;
29 | }
30 |
31 |
32 | public void set(ControllerPoint point) {
33 | this.x = point.x;
34 | this.y = point.y;
35 | this.width = point.width;
36 | }
37 |
38 |
39 | public String toString() {
40 | String str = "X = " + x + "; Y = " + y + "; W = " + width;
41 | return str;
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/old_code/OldDrawPenView.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.old_code;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.PorterDuff;
10 | import android.graphics.PorterDuffXfermode;
11 | import android.util.AttributeSet;
12 | import android.util.DisplayMetrics;
13 | import android.util.Log;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 |
17 | import com.shiming.pen.new_code.IPenConfig;
18 | import com.shiming.pen.new_code.BrushPen;
19 |
20 | import static com.shiming.pen.new_code.IPenConfig.PEN_WIDTH;
21 |
22 |
23 | /**
24 | * @author shiming
25 | * @version v1.0 create at 2017/8/24
26 | * @des DrawPenView实现手写关键类,目前只提供了,手绘的功能和清除画布,后期根据业务逻辑可以动态的设置方法
27 | */
28 | public class OldDrawPenView extends View {
29 | private static final String TAG = "DrawPenView";
30 | private Paint mPaint;//画笔
31 | private Canvas mCanvas;//画布
32 | private Bitmap mBitmap;
33 | private StrokePen mVisualStrokePen;
34 | private Context mContext;
35 | public static int mCanvasCode = IPenConfig.STROKE_TYPE_PEN;
36 | private BrushPen mStokeBrushPen;
37 |
38 | public OldDrawPenView(Context context) {
39 | super(context);
40 | initParameter(context);
41 | }
42 |
43 | public OldDrawPenView(Context context, AttributeSet attrs) {
44 | super(context, attrs);
45 | initParameter(context);
46 | }
47 |
48 | public OldDrawPenView(Context context, AttributeSet attrs, int defStyleAttr) {
49 | super(context, attrs, defStyleAttr);
50 | initParameter(context);
51 | }
52 |
53 | public void setCanvasCode(int canvasCode) {
54 | mCanvasCode = canvasCode;
55 | invalidate();
56 | }
57 |
58 | private void initParameter(Context context) {
59 | mContext = context;
60 | DisplayMetrics dm = new DisplayMetrics();
61 | ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
62 | mBitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Bitmap.Config.ARGB_8888);
63 | //笔的控制类
64 | mVisualStrokePen = new StrokePen(mContext);
65 | initPaint(mContext);
66 | initCanvas();
67 | }
68 |
69 |
70 | private void initPaint(Context context) {
71 | mPaint = new Paint();
72 | mPaint.setColor(IPenConfig.PEN_CORLOUR);
73 | mPaint.setStrokeWidth(PEN_WIDTH);
74 | mPaint.setStyle(Paint.Style.STROKE);
75 | mPaint.setStrokeCap(Paint.Cap.ROUND);//结束的笔画为圆心
76 | mPaint.setStrokeJoin(Paint.Join.ROUND);//连接处元
77 | mPaint.setAlpha(0xFF);
78 | mPaint.setAntiAlias(true);
79 | mPaint.setStrokeMiter(1.0f);
80 | mStokeBrushPen.setPaint(mPaint);
81 | mVisualStrokePen.setPaint(mPaint);
82 |
83 |
84 | }
85 |
86 | private void initCanvas() {
87 | mCanvas = new Canvas(mBitmap);
88 | //设置画布的颜色的问题
89 | mCanvas.drawColor(Color.TRANSPARENT);
90 | }
91 |
92 | public void changePaintColor(int color) {
93 | mPaint.setColor(color);
94 | }
95 |
96 | public void changePaintSize(float width) {
97 | mPaint.setStrokeWidth(width);
98 | }
99 |
100 |
101 | @Override
102 | protected void onDraw(Canvas canvas) {
103 | canvas.drawBitmap(mBitmap, 0, 0, mPaint);
104 | switch (mCanvasCode) {
105 | case IPenConfig.STROKE_TYPE_PEN:
106 | mVisualStrokePen.draw(canvas);
107 | break;
108 | case IPenConfig.STROKE_TYPE_ERASER:
109 | reset();
110 | break;
111 | case IPenConfig.STROKE_TYPE_BRUSH:
112 | mStokeBrushPen.draw(canvas);
113 | break;
114 | default:
115 | Log.e(TAG, "onDraw" + Integer.toString(mCanvasCode));
116 | break;
117 | }
118 | super.onDraw(canvas);
119 | }
120 |
121 | /**
122 | * event.getAction() //获取触控动作比如ACTION_DOWN
123 | * event.getPointerCount(); //获取触控点的数量,比如2则可能是两个手指同时按压屏幕
124 | * event.getPointerId(nID); //对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引
125 | * event.getX(nID); //获取第nID个触控点的x位置,记录的第一个点为getX,getY
126 | * event.getY(nID); //获取第nID个点触控的y位置
127 | * event.getPressure(nID); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的
128 | * event.getDownTime() //按下开始时间
129 | * event.getEventTime() // 事件结束时间
130 | * event.getEventTime()-event.getDownTime()); //总共按下时花费时间
131 | *
132 | * @param event
133 | * @return
134 | */
135 | @Override
136 | public boolean onTouchEvent(MotionEvent event) {
137 | //event会被下一次事件重用,这里必须生成新的,否则会有问题
138 | MotionEvent event2 = MotionEvent.obtain(event);
139 | //getActionMask:触摸的动作,按下,抬起,滑动,多点按下,多点抬起
140 | switch (event2.getActionMasked()) {
141 | case MotionEvent.ACTION_DOWN:
142 | setCanvasCode(IPenConfig.STROKE_TYPE_PEN);
143 | mVisualStrokePen.onDown(mVisualStrokePen.createMotionElement(event2));
144 | break;
145 | case MotionEvent.ACTION_MOVE:
146 | mVisualStrokePen.onMove(mVisualStrokePen.createMotionElement(event2));
147 | break;
148 | case MotionEvent.ACTION_UP:
149 | mVisualStrokePen.onUp(mVisualStrokePen.createMotionElement(event2), mCanvas);
150 | break;
151 | default:
152 | break;
153 | }
154 | invalidate();
155 | return true;
156 | }
157 |
158 | /**
159 | * 清除画布,记得清除点的集合
160 | */
161 | public void reset() {
162 | mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
163 | mCanvas.drawPaint(mPaint);
164 | mPaint.setXfermode(null);
165 | mVisualStrokePen.clear();
166 | }
167 |
168 | public void setCurrentState(int currentState) {
169 | mCanvasCode = currentState;
170 | }
171 |
172 |
173 | public Bitmap getBitmap() {
174 | return mBitmap;
175 | }
176 |
177 | public void onResume() {
178 |
179 | }
180 |
181 | public TimeListener mGetTimeListner;
182 |
183 | public void setGetTimeListener(TimeListener l) {
184 | mGetTimeListner = l;
185 | }
186 |
187 | public interface TimeListener {
188 | void getTime(long l);
189 |
190 | void stopTime();
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/old_code/StrokePen.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.old_code;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.RectF;
7 | import android.view.MotionEvent;
8 |
9 | import com.shiming.pen.Bezier;
10 | import com.shiming.pen.new_code.MotionElement;
11 |
12 | import java.util.ArrayList;
13 |
14 |
15 | /**
16 | * @author shiming
17 | * @version v1.0 create at 2017/8/24
18 | * @des 画笔的类()
19 | */
20 | public class StrokePen {
21 | //这个控制笔锋的控制值
22 | protected float DIS_VEL_CAL_FACTOR = 0.02f;
23 | // protected float DIS_VEL_CAL_FACTOR =2000f;
24 | //手指在移动的控制笔的变化率
25 | // protected float WIDTH_THRES_MAX = 0.6f;
26 | //线的粗细的,这个值越大,线的粗细越加明显
27 | protected float WIDTH_THRES_MAX = 10f;
28 | //绘制计算的次数,数值越小计算的次数越多,需要折中
29 | protected int STEPFACTOR = 10;
30 |
31 | private ArrayList mPointList;
32 | private ArrayList mHWPointList;
33 | private Bezier mBezier;
34 | private ControllerPoint mLastPoint;
35 | //笔的宽度信息
36 | private double mBaseWidth;
37 | private double mLastVel;
38 | private double mLastWidth;
39 | private ControllerPoint curPoint;
40 | private Paint mPaint;
41 |
42 | public void clear() {
43 | mPointList.clear();
44 | mHWPointList.clear();
45 |
46 | }
47 |
48 | public StrokePen(Context context) {
49 | mPointList = new ArrayList();
50 | mHWPointList = new ArrayList();
51 | mBezier = new Bezier();
52 | mLastPoint = new ControllerPoint(0, 0);
53 | }
54 |
55 | /**
56 | * 早onDraw需要调用
57 | *
58 | * @param canvas 画布
59 | */
60 | public void draw(Canvas canvas) {
61 | mPaint.setStyle(Paint.Style.FILL);
62 | //点的集合少 不去绘制
63 | if (mHWPointList == null || mHWPointList.size() < 1)
64 | return;
65 | //当控制点的集合很少的时候,需要画个小圆,但是需要算法
66 | if (mHWPointList.size() < 2) {
67 | ControllerPoint point = mHWPointList.get(0);
68 | //由于此问题在算法上还没有实现,所以暂时不给他画圆圈
69 | //canvas.drawCircle(point.x, point.y, point.width, mPaint);
70 | } else {
71 | curPoint = mHWPointList.get(0);
72 | for (int i = 1; i < mHWPointList.size(); i++) {
73 | ControllerPoint point = mHWPointList.get(i);
74 | drawToPoint(canvas, point, mPaint);
75 | curPoint = point;
76 | }
77 | }
78 | }
79 |
80 |
81 | /**
82 | * event.getPressure(); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的,我的手机上为1
83 | *
84 | * @param motionEvent
85 | * @return
86 | */
87 | public MotionElement createMotionElement(MotionEvent motionEvent) {
88 | System.out.println("shiming== 0000==" + motionEvent.getToolType(0));
89 | System.out.println("shiming==" + motionEvent.getPressure());
90 | System.out.println("shiming==" + motionEvent.getEventTime());
91 | MotionElement motionElement = new MotionElement(motionEvent.getX(), motionEvent.getY(),
92 | motionEvent.getPressure(), motionEvent.getToolType(0));
93 | return motionElement;
94 | }
95 |
96 | /**
97 | * 手指的down事件
98 | *
99 | * @param mElement
100 | */
101 | public void onDown(MotionElement mElement) {
102 | mPaint.setXfermode(null);
103 | mPointList.clear();
104 | mHWPointList.clear();
105 | //记录down的控制点的信息
106 | ControllerPoint curPoint = new ControllerPoint(mElement.x, mElement.y);
107 | //如果用笔画的画我的屏幕,记录他宽度的和压力值的乘,但是哇,
108 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
109 | mLastWidth = mElement.pressure * mBaseWidth;
110 | } else {
111 | //如果是手指画的,我们取他的0.8
112 | mLastWidth = 0.8 * mBaseWidth;
113 | }
114 | //down下的点的宽度
115 | curPoint.width = (float) mLastWidth;
116 | mLastVel = 0;
117 |
118 | mPointList.add(curPoint);
119 | //记录当前的点
120 | mLastPoint = curPoint;
121 | }
122 |
123 | public void onMove(MotionElement mElement) {
124 | ControllerPoint curPoint = new ControllerPoint(mElement.x, mElement.y);
125 | double deltaX = curPoint.x - mLastPoint.x;
126 | double deltaY = curPoint.y - mLastPoint.y;
127 | //deltaX和deltay平方和的二次方根 想象一个例子 1+1的平方根为1.4 (x²+y²)开根号
128 | double curDis = Math.hypot(deltaX, deltaY);
129 | //我们求出的这个值越小,画的点或者是绘制椭圆形越多,这个值越大的话,绘制的越少,笔就越细,宽度越小
130 | double curVel = curDis * DIS_VEL_CAL_FACTOR;
131 | System.out.println("shiming===" + curDis + " " + curVel + " " + deltaX + " " + deltaY);
132 | double curWidth;
133 | //点的集合少,我们得必须改变宽度,每次点击的down的时候,这个事件
134 | if (mPointList.size() < 2) {
135 | System.out.println("shiming==dian shao");
136 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
137 | curWidth = mElement.pressure * mBaseWidth;
138 | } else {
139 | curWidth = calcNewWidth(curVel, mLastVel, curDis, 1.5,
140 | mLastWidth);
141 | }
142 | curPoint.width = (float) curWidth;
143 | mBezier.init(mLastPoint, curPoint);
144 | } else {
145 | System.out.println("shiming==dian duo");
146 | mLastVel = curVel;
147 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
148 | curWidth = mElement.pressure * mBaseWidth;
149 | } else {
150 | //由于我们手机是触屏的手机,滑动的速度也不慢,所以,一般会走到这里来
151 | //阐明一点,当滑动的速度很快的时候,这个值就越小,越慢就越大,依靠着mlastWidth不断的变换
152 | curWidth = calcNewWidth(curVel, mLastVel, curDis, 1.5,
153 | mLastWidth);
154 | System.out.println("shiming==" + curVel + " " + mLastVel + " " + curDis + " " + mLastWidth);
155 | System.out.println("shiming==dian duo" + curWidth);
156 | }
157 | curPoint.width = (float) curWidth;
158 | mBezier.addNode(curPoint);
159 | }
160 | //每次移动的话,这里赋值新的值
161 | mLastWidth = curWidth;
162 |
163 | mPointList.add(curPoint);
164 |
165 | int steps = 1 + (int) curDis / STEPFACTOR;
166 | System.out.println("shiming-- steps" + steps);
167 | double step = 1.0 / steps;
168 | for (double t = 0; t < 1.0; t += step) {
169 | ControllerPoint point = mBezier.getPoint(t);
170 | mHWPointList.add(point);
171 | }
172 |
173 | mLastPoint = curPoint;
174 | }
175 |
176 | public void onUp(MotionElement mElement, Canvas canvas) {
177 | ControllerPoint curPoint = new ControllerPoint(mElement.x, mElement.y);
178 | double deltaX = curPoint.x - mLastPoint.x;
179 | double deltaY = curPoint.y - mLastPoint.y;
180 | double curDis = Math.hypot(deltaX, deltaY);
181 |
182 | if (mElement.tooltype == MotionEvent.TOOL_TYPE_STYLUS) {
183 | curPoint.width = (float) (mElement.pressure * mBaseWidth);
184 | } else {
185 | curPoint.width = 0;
186 | }
187 |
188 | mPointList.add(curPoint);
189 |
190 | mBezier.addNode(curPoint);
191 |
192 | int steps = 1 + (int) curDis / STEPFACTOR;
193 | double step = 1.0 / steps;
194 | for (double t = 0; t < 1.0; t += step) {
195 | ControllerPoint point = mBezier.getPoint(t);
196 | mHWPointList.add(point);
197 | }
198 | //
199 | mBezier.end();
200 | for (double t = 0; t < 1.0; t += step) {
201 | ControllerPoint point = mBezier.getPoint(t);
202 | mHWPointList.add(point);
203 | }
204 |
205 | // 手指up 我画到纸上上
206 | draw(canvas);
207 |
208 | }
209 |
210 | /**
211 | * 通过点去绘制一条线,当现在的点和触摸点的位置在一起的时候不用去绘制
212 | *
213 | * @param canvas
214 | * @param point
215 | * @param paint
216 | */
217 | private void drawToPoint(Canvas canvas, ControllerPoint point, Paint paint) {
218 | if ((curPoint.x == point.x) && (curPoint.y == point.y)) {
219 | return;
220 | }
221 | drawLine(canvas, curPoint.x, curPoint.y, curPoint.width, point.x,
222 | point.y, point.width, paint);
223 | }
224 |
225 | /**
226 | * @param curVel
227 | * @param lastVel
228 | * @param curDis
229 | * @param factor
230 | * @param lastWidth
231 | * @return
232 | */
233 | private double calcNewWidth(double curVel, double lastVel, double curDis,
234 | double factor, double lastWidth) {
235 | double calVel = curVel * 0.6 + lastVel * (1 - 0.6);
236 | //返回指定数字的自然对数
237 | double vfac = Math.log(factor * 2.0f) * (-calVel);
238 | //此方法返回值e,其中e是自然对数的基数。
239 | double calWidth = mBaseWidth * Math.exp(vfac);
240 |
241 | double mMoveThres = curDis * 0.01f;
242 | if (mMoveThres > WIDTH_THRES_MAX) {
243 | mMoveThres = WIDTH_THRES_MAX;
244 | }
245 | if (Math.abs(calWidth - mBaseWidth) / mBaseWidth > mMoveThres) {
246 | if (calWidth > mBaseWidth) {
247 | calWidth = mBaseWidth * (1 + mMoveThres);
248 | } else {
249 | calWidth = mBaseWidth * (1 - mMoveThres);
250 | }
251 | } else if (Math.abs(calWidth - lastWidth) / lastWidth > mMoveThres) {
252 | if (calWidth > lastWidth) {
253 | calWidth = lastWidth * (1 + mMoveThres);
254 | } else {
255 | calWidth = lastWidth * (1 - mMoveThres);
256 | }
257 | }
258 | return calWidth;
259 | }
260 |
261 | /**
262 | * 其实这里才是关键的地方,通过画布画椭圆,每一个点都是一个椭圆,这个椭圆的所有细节,逐渐构建出一个完美的笔尖
263 | * 和笔锋的效果,我觉得在这里需要大量的测试,其实就对低端手机进行排查,看我们绘制的笔的宽度是多少,绘制多少个椭圆
264 | * 然后在低端手机上不会那么卡,当然你哪一个N年前的手机给我,那也的卡,只不过需要适中的范围里面
265 | *
266 | * @param canvas
267 | * @param x0
268 | * @param y0
269 | * @param w0
270 | * @param x1
271 | * @param y1
272 | * @param w1
273 | * @param paint
274 | */
275 | private void drawLine(Canvas canvas, double x0, double y0, double w0, double x1, double y1, double w1, Paint paint) {
276 | //求两个数字的平方根 x的平方+y的平方在开方记得X的平方+y的平方=1,这就是一个园
277 | double curDis = Math.hypot(x0 - x1, y0 - y1);
278 | int steps = 1;
279 | if (paint.getStrokeWidth() < 6) {
280 | steps = 1 + (int) (curDis / 2);
281 | } else if (paint.getStrokeWidth() > 60) {
282 | steps = 1 + (int) (curDis / 4);
283 | } else {
284 | steps = 1 + (int) (curDis / 3);
285 | }
286 | double deltaX = (x1 - x0) / steps;
287 | double deltaY = (y1 - y0) / steps;
288 | double deltaW = (w1 - w0) / steps;
289 | double x = x0;
290 | double y = y0;
291 | double w = w0;
292 |
293 | for (int i = 0; i < steps; i++) {
294 | //都是用于表示坐标系中的一块矩形区域,并可以对其做一些简单操作
295 | //精度不一样。Rect是使用int类型作为数值,RectF是使用float类型作为数值。
296 | // Rect rect = new Rect();
297 | RectF oval = new RectF();
298 | oval.set((float) (x - w / 4.0f), (float) (y - w / 2.0f), (float) (x + w / 4.0f), (float) (y + w / 2.0f));
299 | // oval.set((float)(x+w/4.0f), (float)(y+w/4.0f), (float)(x-w/4.0f), (float)(y-w/4.0f));
300 | //最基本的实现,通过点控制线,绘制椭圆
301 | canvas.drawOval(oval, paint);
302 | x += deltaX;
303 | y += deltaY;
304 | w += deltaW;
305 | }
306 | }
307 |
308 | public void setPaint(Paint paint) {
309 | mPaint = paint;
310 | mBaseWidth = paint.getStrokeWidth();
311 | }
312 |
313 | }
314 |
315 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shiming/pen/view/OldDemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen.view;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 | import android.widget.Button;
6 |
7 | import androidx.annotation.Nullable;
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.shiming.pen.R;
11 | import com.shiming.pen.new_code.IPenConfig;
12 | import com.shiming.pen.new_code.NewDrawPenView;
13 |
14 | /**
15 | * author: Created by shiming on 2018/1/20 16:20
16 | * mailbox:lamshiming@sina.com
17 | */
18 |
19 | public class OldDemoActivity extends AppCompatActivity implements View.OnClickListener {
20 |
21 | private Button mBtnStrokePen;
22 | private Button mBtnClearCanvas;
23 | private NewDrawPenView mDrawPenView;
24 | private Button mBrushPen;
25 |
26 | @Override
27 | protected void onCreate(@Nullable Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_old_demo_layout);
30 | findViews();
31 | doSomeThing();
32 | }
33 |
34 | private void doSomeThing() {
35 | mBtnStrokePen.setOnClickListener(this);
36 | mBtnClearCanvas.setOnClickListener(this);
37 | mBrushPen.setOnClickListener(this);
38 | }
39 |
40 | private void findViews() {
41 | mBtnStrokePen = (Button) findViewById(R.id.btn_stroke_pen);
42 | mDrawPenView = (NewDrawPenView) findViewById(R.id.draw_pen_view);
43 | mBtnClearCanvas = (Button) findViewById(R.id.btn_clear_canvas);
44 | mBrushPen = (Button) findViewById(R.id.btn_brush_pen);
45 |
46 | }
47 |
48 | @Override
49 | public void onClick(View v) {
50 | switch (v.getId()) {
51 | case R.id.btn_stroke_pen:
52 | mDrawPenView.setCanvasCode(IPenConfig.STROKE_TYPE_PEN);
53 | break;
54 | case R.id.btn_clear_canvas:
55 | mDrawPenView.setCanvasCode(IPenConfig.STROKE_TYPE_ERASER);
56 | break;
57 | case R.id.btn_brush_pen:
58 | mDrawPenView.setCanvasCode(IPenConfig.STROKE_TYPE_BRUSH);
59 | break;
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hand_draw_delete_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hand_draw_kb_show_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hand_draw_new_line_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hand_draw_space_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_delete_no_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/icon_delete_no_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_delete_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/icon_delete_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_pen_new_line_no_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/icon_pen_new_line_no_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_pen_new_line_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/icon_pen_new_line_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_pen_space_no_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/icon_pen_space_no_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_pen_space_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/icon_pen_space_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/letter_key.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/letter_key_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/letter_key_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/letter_key_nor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/letter_key_nor_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/letter_key_nor_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/letter_key_nor_prs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/letter_key_nor_prs.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/letter_key_prs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/drawable/letter_key_prs.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_field_character_shape_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
20 |
21 |
29 |
30 |
31 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
22 |
23 |
30 |
31 |
32 |
36 |
37 |
42 |
43 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_old_demo_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
37 |
38 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/brush_weight_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
25 |
26 |
31 |
32 |
33 |
39 |
40 |
44 |
45 |
46 |
52 |
53 |
57 |
58 |
59 |
65 |
66 |
70 |
71 |
72 |
73 |
77 |
78 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/draw_view_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/hand_rich_edittext.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/icon_demo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxhdpi/icon_demo.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/icon_draw_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxhdpi/icon_draw_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/brush.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/brush.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/cicrle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/cicrle.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/san.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/san.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/six.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/six.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/timg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/timg.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/tranglie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/app/src/main/res/mipmap-xxxhdpi/tranglie.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #cccccc
7 | #f5f4f3
8 | #ff0000
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 40dp
4 | 28dp
5 | 280dp
6 | 10dp
7 | 180dp
8 | 5dp
9 | 25sp
10 | 55dp
11 | 80dp
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WritingPen
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/shiming/pen/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.shiming.pen;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
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 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:4.1.0'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | }
22 |
23 | // repositories {
24 | // jcenter()
25 | // google()
26 | // mavenLocal()
27 | //// mavenCentral()
28 | //// maven {
29 | //// url 'https://maven.google.com'
30 | //// }
31 | ////
32 | // }
33 | }
34 |
35 | task clean(type: Delete) {
36 | delete rootProject.buildDir
37 | }
38 |
--------------------------------------------------------------------------------
/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/code.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 | android.useAndroidX=true
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shimingli/WritingPen/9625404b44b563419ff3e3833204953d4a70a1e7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu May 27 10:14:24 CST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------