旋转控件(一):矩形的平移旋转缩放
之前做了这个东西,一个内部素材加外操作边框,包含基本的移动、缩放、旋转,拉伸,快速定位,十字对齐等操作。常见使用场景如增加马赛克,增加画中画等。感觉比较有意思而且中间也遇到了少量问题就记录一下
先上图:
scaleRotae.gif
如图,这次就先讲一下平移、旋转、缩放
假如只是view做平移,有很多种实现方式比方通过layout、动画等。
基于我们的使用场景:知道一个图片的位置信息和旋转角度(中心旋转),即可以将它画出来。所以选择了维护一个rect以及绕中心旋转的角度rotation,这样少量第三方如需要c层操作的地方,直接把这些信息给c层也可以马上明确。
一、如何画
可以看出这个控件其实是一个图片+外面一个框,不过要考虑到旋转的情况,这里我们就借助matrix来做中心旋转。其实相对的就是先把canvas绕图片的中心做一次旋转
@Override protected void dispatchDraw(Canvas canvas) { canvas.save(); canvas.concat(mRotateMatrix); mainDrawable.setBounds((int) mRect.left, (int) mRect.top, (int) mRect.right, (int) mRect.bottom); mainDrawable.draw(canvas); canvas.drawRect(mRect, mPaint); drawAnchors(canvas, mRect); canvas.restore(); super.dispatchDraw(canvas); }虚线就用paint设置setPathEffect即可以了,虚线框角上的几个角标也是借助rect的位置信息来画出来
比方画右上角的旋转按钮:
if (rotateDrawable != null) { //右上角 rotateDrawable.setBounds(right - drawableWidth, top - drawableHeight, right + drawableWidth, top + drawableHeight); rotateDrawable.draw(canvas); }重点就是去计算上面代码的mRotateMatrix
private void invalidateMatrix() { mRotateMatrix.reset(); mRotateMatrix.postTranslate(-mRect.centerX(), -mRect.centerY()); mRotateMatrix.postRotate(mRotation); mRotateMatrix.postTranslate(mRect.centerX(), mRect.centerY()); }这里简单提一下matrix。学过线性代数的都知道矩阵吧,matrix其实就是个3×3的矩阵,里面的元素控制着旋转、缩放、平移、错切。直接new出来的矩阵是一个单位矩阵,形容的就是原来的图形信息,没有做变换。
而后就是矩阵计算不满足交换律,换句话说矩阵的前乘和后乘结果不一样,反应在matrix里面就是pre和post接口效果不一样。
简单点了解就是pre是放在操作队列头,post放在队尾,还有个set会清空整个队列再把它放进去。假如觉得担心记混,推荐就用post接口,符合先进先出的准则,先post的先执行。
二、如何判断什么时候该缩放、旋转或者者平移
这里一定是事件解决相关的了。处于方便,我们在ontouchEvent的时候把操作委托给GestureDetector,在onDown回调时判断点到了哪里,比方旋转、缩放、平移。而后在onScroll回调的时候通过每次的增量dx,dy计算缩放的比例、旋转角度以及移动距离。
在手指头按下时,因为我们知道图片rec的位置信息和角标位置信息,所以通过x和y可以判断能否点到了角标。
但是有个问题是,画的矩形是在旋转过的画布上面,我们手指头的xy是屏幕上的位置,这里对应不起来,会出现旋转后就点不到角标了
为理解决这个问题,手指头按下的point需要利用matix做一次映射。在这里的场景其实就相当于把旋转的信息考虑进去,其实也完全可以自己用三角函数算,但是matrix已经提供这种接口了,而且是调用的c层计算,效率应该更高些。
final Matrix rotateMatrix = new Matrix(); //反向旋转回去 抵消canvas的旋转 rotateMatrix.postTranslate(-mRect.centerX(), -mRect.centerY()); rotateMatrix.postRotate(-mRotation); rotateMatrix.postTranslate(mRect.centerX(), mRect.centerY()); rotateMatrix.mapPoints(point); eventX = point[0]; eventY = point[1]; RectF rectF = mRect; //hit rotate 右上 if (Math.abs(rectF.right - eventX) < drawableWidth * 2 && Math.abs(rectF.top - eventY) < drawableHeight * 2) { return HitModes.ROTATE; }需要注意的是这里matix的旋转角度和canvas的是相反的,其实就相当于转了n角度,而后又转回去n角度,相当于没有转。而后即可以按照没有旋转的情况判断有没有点到角标。
三、如何进行旋转、缩放、平移
第二步已经判断到客户想要进行什么操作了,接下来就是执行对应的操作了。
平移
先说简单的平移吧,上面说了,我们的场景是一个矩形位置信息+绕中心旋转角度。所以平移其实就是改矩形的位置罢了,直接调rec的offset,而后肯定要记得在重新绘制前升级canvas的旋转矩阵
private void onMove(float dx, float dy) { mRect.offset(-dx, -dy); invalidateMatrix(); invalidate(); }缩放
首先我们要明确一个东西,就是缩放时旋转中心肯定是不变的。所以可以算出中心和右下角的距离以及scroll后的中心和右下角的距离算出两个距离的变化当成x的变化。我们这里是等比例缩放,根据比例算出y的变化。
这里做了一个缩放最小的限制,缩放到1.5个角度宽高后就不嫩再缩小了,这样可以保证角标不会挤在一起。
private void onScale(float dx, float dy) { // TODO: 2019/4/8 这里的dx,dy计算需要改进 float[] pt1 = new float[] { mRect.centerX(), mRect.centerY() }; float[] pt2 = new float[] { mRect.right, mRect.bottom }; float[] pt3 = new float[] { mRect.right + dx, mRect.bottom + dy }; float distance1 = getPointDistance(pt1, pt2); float distance2 = getPointDistance(pt1, pt3); float distance = distance1 - distance2; if (!checkCanScale(distance)) { return; } mRect.inset(-distance, -distance / mRatio); invalidateMatrix(); invalidate(); }旋转
至于旋转其实也简单,由于旋转时中心也是不变的,相似缩放的操作。根据右上角的旋转角标和中心的角度,以及scroll后右上角和中心的角度,这两个的角度差就是旋转角度。
已知两个点的位置,通过math的atan2函数可以算出角度
private void onRotate(float triggerX, float triggerY) { // TODO: 2019/4/8 这里的dx,dy计算需要改进 float[] pt1 = new float[] { mRect.centerX(), mRect.centerY() }; float[] pt2 = new float[] { mRect.right, mRect.top }; float[] pt3 = new float[] { triggerX, triggerY }; double angel1 = PointUtil.calculateAngleBetweenPoints(pt2, pt1); double angel2 = PointUtil.calculateAngleBetweenPoints(pt3, pt1); mRotation = (float) (angel1 - angel2); invalidateMatrix(); invalidate(); }到这里基本的平移旋转缩放都详情完了,详细的少量位置计算可以参考demo
dynamicBai/ScaleRotateView 给个star鼓励下呗
后面会逐渐详情:拉伸四边的操作(旋转中心会变化)、图片在屏幕上的快速定位和微调、移动时十字辅助线对齐等效果。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 旋转控件(一):矩形的平移旋转缩放