Android移动、缩放和旋转手势实现
Android的部分图片编辑应用中需要对图片进行移动、缩放和旋转,这些变化都依赖于触摸手势实现,而本文主要阐述移动、缩放和旋转手势的简单实现。
一、移动
首先需要从触摸事件(MotionEvent)中获取每个手指(Pointer)的坐标,随后计算这些坐标的中心(重心)位置,那么本次触摸事件与前一次触摸事件的中心距离就是手势的移动距离:
// calc center coordinates
float centerX = 0;
float centerY = 0;
for (int index = 0; index < pointerCount; index++) {
centerX += event.getX(index);
centerY += event.getY(index);
}
centerX /= pointerCount;
centerY /= pointerCount;
// calc translation
float translateX = centerX - mPrevCenterX;
float translateY = centerY - mPrevCenterY;
mPrevCenterX = centerX;
mPrevCenterY = centerY;
二、缩放
同样手势缩放也需要计算触摸事件的中心,其次计算每一个手指坐标与中心的距离,然后计算这些距离的平均值,那么本次触摸事件平均中心距离与上一次触摸事件的比值就是本次手势的缩放比例:
// omit calc center coordinates
// calc mean distance
double sumDistance = 0;
for (int index = 0; index < pointerCount; index++) {
float vx = event.getX(index) - centerX;
float vy = event.getY(index) - centerY;
// calc distance to center coordinates
sumDistance += Math.sqrt(vx * vx + vy * vy);
}
float meanDistance = (float) (sumDistance / pointerCount);
// calc scale
float scale = mPrevMeanDistance < 1e-5 ? 1 : meanDistance / mPrevMeanDistance;
mPrevMeanDistance = meanDistance;
三、旋转
手势旋转同样需要计算触摸事件的中心,然后计算中心到每一个手指坐标的向量,计算每一个手指向量相对于上一次触摸事件中对应的手指向量的旋转角度,最后计算这些旋转角度的平均值,这个平均值就是本次手势的旋转角度:
// omit calc center coordinates
// calc rotate degrees
double sumRotateDegrees = 0;
for (int index = 0; index < pointerCount; index++) {
float vx = event.getX(index) - centerX;
float vy = event.getY(index) - centerY
// calc angle between vectors
int pointerId = event.getPointerId(index);
sumRotateDegrees = Math.toDegrees(angleBetweenVectors(mPrevVx[pointerId], mPrevVy[pointerId], vx, vy));
mPrevVx[pointerId] = vx;
mPrevVy[pointerId] = vy;
}
float rotateDegrees = (float) (sumRotateDegrees / pointerCount);
两个向量叉乘公式:\(\boldsymbol v_1*\boldsymbol v_2=\sin\alpha|\boldsymbol v_1||\boldsymbol v_2|=v_{x1}*v_{y2}-v_{y1}*v_{x2}\),那么两个向量之间的夹角:
&\alpha=arcsin(\frac{\boldsymbol v_1*\boldsymbol v_2}{|\boldsymbol v_1||\boldsymbol v_2|})&
\end{flalign*}
\]
private static double cross(float vx1, float vy1, float vx2, float vy2) {
return vx1 * vy2 - vy1 * vx2;
}
private static double angleBetweenVectors(float vx1, float vy1, float vx2, float vy2) {
double dist1 = Math.sqrt(vx1 * vx1 + vy1 * vy1);
double dist2 = Math.sqrt(vx2 * vx2 + vy2 * vy2);
if (dist1 < 1e-5 || dist2 < 1e-5) {
return 0;
}
return Math.asin(cross(vx1, vy1, vx2, vy2) / dist1 / dist2);
}
不管是移动、缩放和旋转都需要保证本次触摸事件手指数量与上一次相等,如果不相等计算出来的值则跳动较大。
四、完整示例
本文的完整示例放在github仓库中,主要实现了图片的移动、旋转和缩放效果:

Android移动、缩放和旋转手势实现的更多相关文章
- 微信小程序的拖拽、缩放和旋转手势
在开发中,有时会遇到像App中的手势那样的效果,下面就仿照App实现了一下. wxml部分: <view class="touch-container"> <vi ...
- Android动画及图片的缩放和旋转
Android动画有2种,一种是Tween Animation,另一种是Frame Animation,先说说Tween动画吧. Tween动画是对视图对象中的内容进行一系列简单的转换,比如位置的移动 ...
- 使用手势对UIImageView进行缩放、旋转和移动
// 添加所有的手势 - (void) addGestureRecognizerToView:(UIView *)view { // 旋转手势 UIRotationGestureRecognizer ...
- 使用手势对UIImageView进行缩放、旋转和移动(转)
原文地址:http://blog.csdn.net/crazy_frog/article/details/8664108 // 添加所有的手势 - (void) addGestureRecognize ...
- iOS--------手势识别的详细使用:拖动、缩放、旋转、点击、手势依赖、自定义手势
1.UIGestureRecognizer介绍 手势识别在iOS上非常重要,手势操作移动设备的重要特征,极大的增加了移动设备使用便捷性. iOS系统在3.2以后,为方便开发这使用一些常用的手势,提供了 ...
- [Android] 使用Matrix矩阵类对图像进行缩放、旋转、对照度、亮度处理
前一篇文章讲述了Android拍照.截图.保存并显示在ImageView控件中,该篇文章继续讲述Android图像处理技术,主要操作包含:通过打开相冊里的图片,使用Matrix对图像进行缩放. ...
- android学习笔记51——SQLite 手势Gesture
手势Gesture 所谓手势,是指用户手指或触摸笔在触摸屏幕上的连续触碰行为. Androi对两种手势行为都提供了支持: 1.对于第一种手势而言,android提供了手势检测,并为手势检测提供了相应的 ...
- iOS 七大手势之轻拍,长按,旋转手势识别器方法
一.监听触摸事件的做法 如果想监听一个view上面的触摸事件,之前的做法通常是:先自定义一个view,然后再实现view的touches方法,在方法内部实现具体处理代码 通过touches方法监听 ...
- 【原创】窥视懒人的秘密---android下拉刷新开启手势的新纪元
小飒的成长史原创作品:窥视懒人的秘密---android下拉刷新开启手势的新纪元转载请注明出处 **************************************************** ...
- View的平移、缩放、旋转以及位置、坐标系
原创 2015年05月12日 13:15:29 标签: Android / Scroll / Scale / Translation / Rotation 24733 Android开发中,经常会接触 ...
随机推荐
- linux上搭建Nacos集群(步骤详细,linux小白也能搞定)
(1)nacos官网:https://github.com/alibaba/nacos/releases/tag/1.2.1下载nacos安装包到window本地(后缀为tar.zip) (2)在li ...
- 算法打卡|Day2 数组part02
Day2 数组part02 今日任务:977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II 目录 Day2 数组part02 今日任务:977.有序数组的平方 ,209.长度最小的 ...
- IDEA降低注解检测级别
在 File | Settings | Editor | Inspections 选项中使用搜索功能找到 Autowiring for Bean Class,将 Severity 的级别由之前的 er ...
- Docker V24 及 Docker Compose V2 的安装及使用
前言 Docker 是一款流行的开源容器化平台,使用 Docker 可以有效地隔离应用程序和系统环境,使得应用程序在不同的环境中具有相同的行为 Docker Compose 是一个用于定义和管理多个 ...
- FreeSWITCH添加h264编码及pcap视频提取
操作系统 :CentOS 7.6_x64.Windows 10_x64 FreeSWITCH版本 :1.10.9 Python版本:3.9.2 一.启用h264相关模块 这里以 mod_openh26 ...
- King's Tour 题解
King's Tour 题面大意 在 \(n\times m\) 的网格中构造一种从 \((1,1)\) 走到 \((a,b)\) 的方案,要求经过所有格子恰好一次,格子之间八联通. 思路分析 模拟赛 ...
- Flex 布局项目实战,好像没那么难!
在上篇文章别再用 float 布局了,flex 才是未来!中,我们聊到 Flex 布局才是目前主流的布局方式.在文章最后,我们还贴了一个案例,并且还浅浅地讲解了一下. 有些小伙伴说,这讲解得太粗了,要 ...
- Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法
Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,此处测试代码如下,这里使用add方法: 1 public class main { 2 public static vo ...
- 3.MongoDB-备份恢复
备份工具 (1)** mongoexport/mongoimport (2)***** mongodump/mongorestore 备份工具区别在那里? 应用场景总结: mongoexport/mo ...
- 队列(c++源码)
queue.h #ifndef QUEUE_H_ #define QUEUE_H_ #include<iostream> template<class T> struct No ...