前言
最近有需求要做一个画布,这个画布以一个图片为背景,可以实现缩放,涂鸦以及贴纸的功能,缩放和涂鸦要兼顾,于是就想到了可以加入手势和多点触控,大致就是两只手指头可以拖动或者旋转或者放大,单只手指可以涂鸦画东西之类的,恩,具体的需求在这里先描述了,然后看下大致的实现。
效果展示
自定义view.gif
思路
思考一
通过继承ImageView,类似PhotoView 的实现,因为photoivew 已经实现了旋转和缩放的功能,在其基础上继承拓展,只需要复写onDraw方法,将触摸的轨迹转化为Path 直接draw到canvas上即可。可以实现的,但是要注意一点,那就是坐标转化:你的单个手指移动的轨迹坐标点们是相对于这个view的位置的,当你旋转或者缩放这个view 的时候,结果是先前保存的坐标轨迹是无法匹配到当前旋转或缩放处理后的view,这个时候就需要你将坐标轨迹进行映射处理。
思 考二
则是直接复写View控件,通过将图片直接转换为bitmap后,draw到view 的画布上。整个过程就是先在bitmap上新建一个画布,然后将轨迹坐标draw到这个bitmap的canvas上,也就是这个bitmap上,最后在onDraw的回调里面,将这个bitmap 画到整个View 的canvas上,当然,最后要自行实现bitmap的缩放,旋转等坐标转换功能,好处是先前的涂鸦会一直保持。
预先准备
这个时候就必须要提一下Martix,Andorid 贴心的给我们提供了这样一个工具类,我们完全可以摆脱坐标点计算之苦啦。
在这里强烈推荐大家看下 android matrix 最全方法详解与进阶(完整篇),原理以及api介绍的相当详细。
实现
考虑到要有贴图,并且贴图支持大小缩放的功能,拖动功能,采用了第二种方式,其实感觉采用第一种方式应该会更简单点(微笑脸),好了,下面介绍下具体实现
首先要处理这个view 的touch事件:
if (actionMode == ACTION_DRAG) {
onDragAction(curX - preX, curY - preY, event);//拖动监听
} else if (actionMode == ACTION_ROTATE) {
onRotateAction(curPhotoRecord);//旋转监听
} else if (actionMode == ACTION_SCALE) {
mScaleGestureDetector.onTouchEvent(event); //缩放监听
}
涂鸦
就是将拇指略过之处的所以坐标连接起来,而这个坐标id呢,不是绝对坐标,而是对于这个view 的相对坐标(毕竟还要支持缩放和撤销操作的),单是缩放则不用过多约束,只要将path画到bitmap Canvas上,显示出来即可,但是需要支持撤销,这就要求必须要保持每一个笔画的坐标点组啦,缩放或者旋转时,