没图我说个球:

1.箭头

2.折线

3.直线

以上只能看到画出来的部分,平移的部分我没移植到这个demo下面(因为遇到了一些bug,懒得搞了),

但是下面会讲到平移部分。

简介:

该文章将涉及以下知识点:

1.path的绘制与平移(直线、箭头、可弯折直线);

2.path上每个点坐标的获取;

3.使用region获取填充型path(圆、椭圆、实心矩形等)的区域,得到该region后可判断你的path是否被点击;

PS:第3点我特地强调了“填充型path”,因为线条是无法用region获取区域的,获取到的区域永远是空(含泪实测证明)

正文:

1.绘制与平移

在主类中重写onTouchEvent方法,根据flag的值判断画哪种类型的view,然后调用该view的setPath方法进行绘制

@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mLastX = (int) event.getRawX();mLastY = (int) event.getRawY();break;case MotionEvent.ACTION_UP:mX = (int) event.getX();mY = (int) event.getY();rawX = (int) event.getRawX();rawY = (int) event.getRawY();if(!isEnd){switch (flag){case FLAG_DRAW_ARROW:arrowView.setSetTouchArea(true);break;case FLAG_DRAW_LINE:customLine.setSetTouchArea(true);break;case FLAG_DRAW_BENDABLE_LINE://do nothingbreak;}flag = FLAG_DRAW_NOTHING;isEnd = true;}break;case MotionEvent.ACTION_MOVE:mMoveX = (int) event.getRawX();mMoveY = (int) event.getRawY();if(!isEnd){switch (flag){case FLAG_DRAW_ARROW:arrowView.clear();arrowView.setPath(mLastX,mLastY,mMoveX,mMoveY);break;case FLAG_DRAW_LINE:customLine.setPath(mLastX,mLastY,mMoveX,mMoveY);break;case FLAG_DRAW_BENDABLE_LINE:bendableLine.setPath(mLastX,mLastY,mMoveX,mMoveY);break;}}break;}return true;}

直线的setPath方法以及onDraw实现:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawPath(mPath, mPaint);}public void setPath(float startX, float startY, float endX, float endY) {mPath.reset();mPath.moveTo(startX, startY);mPath.lineTo(endX, endY);invalidate();}

箭头的:

@Overrideprotected void onDraw(Canvas canvas) {if(hasOffset){canvas.drawPath(path,paint);canvas.drawPath(arrowPath,arrowPaint);return;}setArrowPath();canvas.drawPath(path, paint);canvas.drawPath(arrowPath, arrowPaint);}/*** 画箭头*/public void setArrowPath() {double H = 18; // 箭头高度double L = 13.5; // 底边的一半double angle = Math.atan(L / H); // 箭头角度double arrowLength = Math.sqrt(L * L + H * H); // 箭头的长度//箭头就是个三角形,我们已经有一个点了,根据箭头的角度和长度,确定另外2个点的位置double[] point1 = rotateVec(endX - startX, endY - startY, angle, arrowLength);double[] point2 = rotateVec(endX - startX, endY - startY, -angle, arrowLength);double point1_x = endX - point1[0];double point1_y = endY - point1[1];double point2_x = endX - point2[0];double point2_y = endY - point2[1];int x3 = (int) point1_x;int y3 = (int) point1_y;int x4 = (int) point2_x;int y4 = (int) point2_y;// 画线arrowPath.moveTo(endX, endY);arrowPath.lineTo(x3, y3);arrowPath.lineTo(x4, y4);arrowPath.close();}// 计算/*** @param diffX  X的差值* @param diffY  Y的差值* @param angle  箭头的角度(箭头三角形的线与直线的角度)* @param arrowLength 箭头的长度*/public double[] rotateVec(float diffX, float diffY, double angle, double arrowLength) {double arr[] = new double[2];// 下面的是公式,得出的是以滑动出的线段末点为中心点旋转angle角度后,线段起点的坐标,这个旋转后的线段也就是“变长了的箭头的三角形的一条边”//推导见注释1double x = diffX * Math.cos(angle) - diffY * Math.sin(angle);double y = diffX * Math.sin(angle) + diffY * Math.cos(angle);double d = Math.sqrt(x * x + y * y);//根据相似三角形,得出真正的箭头三角形顶点坐标,这里见注释2x = x / d * arrowLength;y = y / d * arrowLength;arr[0] = x;arr[1] = y;return arr;}public void setPath(float startX, float startY, float endX, float endY) {path.moveTo(startX,startY);path.lineTo(endX,endY);this.startX = startX;this.startY = startY;this.endX = endX;this.endY = endY;invalidate();}public void clear() {path.reset();arrowPath.reset();}

折线的:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawPaths(canvas);}public void setPath(float startX, float startY, final float endX, final float endY) {if (pathList.size() <= 0) {Path path = new Path();path.moveTo(startX, startY);path.lineTo(endX, endY);lastStartX = startX;lastStartY = startY;lastEndX = endX;lastEndY = endY;pathList.add(path);currentPath = path;} else {LogUtil.d(TAG+" lastEndx = "+lastEndX+" , lastEndY = "+lastEndY+" , endX = "+endX+" , endY = "+endY);if (Math.abs(lastEndX-endX) <=2 && Math.abs(lastEndY-endY) <= 2) {if(isTimerRunning){return;}//开启悬停计时if (mTimer == null) {mTimer = new Timer();}mTimer.schedule(new TimerTask() {@Overridepublic void run() {LogUtil.d(TAG+" do timerTask");Path path = new Path();path.moveTo(lastEndX, lastEndY);path.lineTo(endX, endY);lastStartX = lastEndX;lastStartY = lastEndY;lastEndX = endX;lastEndY = endY;pathList.add(path);currentPath = path;currentPathIndex++;LogUtil.d(TAG + " 生成新直线 : size = " + pathList.size() + " , currentIndex = " + currentPathIndex+" end timer");mHandler.sendEmptyMessage(0);isTimerRunning = false;}}, STANDBY_SECONDS);isTimerRunning = true;LogUtil.d(TAG+" run timer");} else {currentPath.reset();currentPath.moveTo(lastStartX, lastStartY);currentPath.lineTo(endX, endY);LogUtil.d(TAG + " 更新直线 line to " + endX + ", " + endY);lastEndX = endX;lastEndY = endY;pathList.set(currentPathIndex, currentPath);}}invalidate();}

平移:

平移用到的是path自带方法offset(dx,dy),参数就是x轴与y轴的偏移量。

@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (isContains(event.getRawX(),event.getRawY())) {LogUtil.i(TAG + " touch down id = " + identity);if (onLineTouchListener != null) {onLineTouchListener.onLineTouch(this);}lastX = (int) event.getRawX();lastY = (int) event.getRawY();canMove = true;}else{canMove = false;return false;}break;case MotionEvent.ACTION_MOVE:if(canMove){int tempRawX = (int) event.getRawX();int tempRawY = (int) event.getRawY();int dx = tempRawX - lastX;int dy = tempRawY - lastY;lastX = tempRawX;lastY = tempRawY;dxTemp += dx;dyTemp += dy;dxTotal += dx;dyTotal += dy;
//                        this.setTranslationX(dxTotal);
//                        this.setTranslationY(dyTotal);mPath.offset(dx,dy);invalidate();}break;case MotionEvent.ACTION_UP:if(dxTemp != 0 || dyTemp != 0){setSetTouchArea(true);dxTemp = 0;dyTemp = 0;}break;}return super.onTouchEvent(event);}

2.path上点坐标的获取

这里我用直线举个栗子,其他path的获取都是一样的方式。

先讲讲原理:

这里用到一个官方提供的类,叫PathMeasure,通过将它与path绑定,能够获取到path的长度,以及path上距离起点distance的点的坐标,然后我们可以写一个循环,获取path上所有点的坐标。

            //用list存放path上的点坐标private List<float[]> pathPosList = new ArrayList<>;//绑定pathmPathMeasure.setPath(mPath, false);/*这里我每次循环完不是i++,而是i+=10,因为如果用i++会得到上千个点坐标,我不需要那么高的精度,这里根据自己需求调整*/for (int i = 0; i < mPathMeasure.getLength(); i+=10) {float[] pos = new float[2];float[] tan = new float[2];mPathMeasure.getPosTan(i, pos, tan);pathPosList.add(pos);}

3.使用Region获取path所占用的区域(对线条无用)

private void getPathRegion(){Region globalRegion = new Region(0,0,ScreenUtil.screenWidth,ScreenUtil.screenHeight);Region mPathRegion = new Region();mPathRegion.setPath(mPath,globalRegion);}

代码很简单,解释下原理,region.setPath方法,获取的是传入的path与传入的region的交集。

总结:

用path基本想画啥都能画出来,尤其是典型的几何图形,官方都封装好了相应的方法。如果想要做path画出来的非规则图形的点击,填充图形用Region,线条用点坐标来判断。

源码下载地址:https://download.csdn.net/download/yonghuming_jesse/11164357

以上。

如果有我说的不够详细,你没看懂的地方,请在下方留言,博主会尽快回复。

【关于Path的史诗级总结】画箭头、直线,监听箭头、直线的触摸事件,以及平移相关推荐

  1. java 接口文件夹_Java NIO.2 使用Path接口来监听文件、文件夹变化

    Java7对NIO进行了大的改进,新增了许多功能: •对文件系统的访问提供了全面的支持 •提供了基于异步Channel的IO 这些新增的IO功能简称为 NIO.2,依然在java.nio包下. 早期的 ...

  2. wps ppt画直线总是有箭头,如何还原成只画直线

    双击带箭头的直线 选直线 在设置为直线的地方右键

  3. 流程图虚线箭头的意思_Ai篇NO.3: 怎样画出不死板的箭头?

    再次感谢大家的关注!已经有260位小伙伴关注我的专栏啦!还有一些小伙伴提出合作,建群,分享素材等要求,我觉得都很好,我会认真考虑的! 今天我们来谈谈Ai科研示意图中必不可少的元素--箭头. 如果我们想 ...

  4. cad怎么画坐标系箭头_cad怎么插入箭头?cad插入箭头方法

    在cad制图中,我们经常会对图形进标注和注明,这里就需要一些箭头进行指向和声明.而在cad中插入箭头的方法并不是那么简单,不是直接插入就可以的.这里就给大家讲解在cad中插入各种箭头的方法,cad箭头 ...

  5. [html] 你能否画出一个0.5px的直线?

    [html] 你能否画出一个0.5px的直线? 通过scale(0.5)来实现 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢迎大家一起讨论 主目录 与歌谣一起通关 ...

  6. 用java的事件监听机制实现一个简单的画板应用:通过选择图形按钮和颜色按钮来画出自己想画的图形:直线、空心矩形、圆形、折线、多边形、圆角矩形、弧线、曲线、喷枪

    今天做一个简单的画板,完整代码附在文章末尾处. - 功能:通过选择图形按钮和颜色按钮来画出自己想画的图形. - 界面展示: - 思路: 1.做一个可视化界面:创建JFrame对象,并设置Title.S ...

  7. svg实现直线带左箭头

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  8. 【可视化】python-matplotlib画出普通箭头和带注释箭头

    画出带注释的箭头: # 注释箭头 bbox_props = dict(boxstyle="rarrow", fc=(0.8, 0.9, 0.9), ec="b" ...

  9. DDA画线算法+代码详解-直线扫描算法之一

    #DDA画线算法+代码详解-直线扫描算法之一 本文目录结构如下 1.直线扫描算法简介 2.DDA直线扫描算法 2.1 公式推理 1.求斜率K: 2.当|K| <= 1 时 3.当|K| > ...

最新文章

  1. CornerNet的配置、训练与测试
  2. SAP IDoc E1EDP04 Z8 数据错误之对策
  3. excel 某个单元格不是等于空值_excel 单元格为空与不存在
  4. 图解Win7下set命令使用
  5. python 在python的class中的,self到底是什么?
  6. 操作系统P,V(wait,signal原语)操作讲解,以及两个例题(答案仅供参考)
  7. memcpy和memmove的区别
  8. scala中处理json数据
  9. shopify二次开发教程_详细教程:如何将Shopify的Storefront API与React和Redux结合使用...
  10. 超级楼梯(HDU-2040)
  11. MySQL中的翻页优化和延迟缓存
  12. 关于TransactionScope出错:“与基础事务管理器的通信失败”的解决方法
  13. 哨兵系列卫星_传感器|英国Teledyne e2v公司为“哥白尼哨兵”卫星任务提供CO2监测传感器...
  14. stm32与计算机串口通信,STM32串口通信协议
  15. 微信公众号数据2019_微信公众号精准数据对比 让公众号运营更顺利
  16. 你画我猜---websocket
  17. ARP报文目的MAC为什么不是广播地址?
  18. VBA-自动筛选符合条件的数据
  19. 基于python的opencv图像处理对交通路口的红绿灯进行颜色检测,无人汽车驾驶第一步!
  20. 香港虚拟主机空间哪个好?

热门文章

  1. 破解计算机密码的各种方法
  2. day9.初始函数练习题
  3. Atitit s2018.5 s5 doc list on com pc.docx  v2
  4. 被创新工场、君联和华熙集团先后翻牌子,因为它把古风二次元玩得特别溜!
  5. 给出市政工程研究生面试十个简述题并给出答案
  6. Excel导出XML和CS脚本
  7. 泰拉瑞亚怎么样修改服务器时间,泰拉瑞亚如何修改时间 安卓版时间修改教程...
  8. BAT脚本学习篇——基本语法
  9. [书籍精读]《JavaScript设计模式与开发实践》精读笔记分享
  10. 互联网大厂的微服务架构系统应对超大流量解决方案