新闻资讯  快讯  焦点  财经  政策  社会
互 联 网   电商  金融  数据  计算  技巧
生活百科  科技  职场  健康  法律  汽车
手机百科  知识  软件  修理  测评  微信
软件技术  应用  系统  图像  视频  经验
硬件技术  知识  技术  测评  选购  维修
网络技术  硬件  软件  设置  安全  技术
程序开发  语言  移动  数据  开源  百科
安全防护  资讯  黑客  木马  病毒  移动
站长技术  搜索  SEO  推广  媒体  移动
财经百科  股票  知识  理财  财务  金融
教育考试  育儿  小学  高考  考研  留学
您当前的位置:首页 > IT百科 > 程序开发 > 移动端 > Android

Android缩放手势的检测

时间:2019-09-10 11:31:15  来源:  作者:

 

缩放手势对于大部分 Android 工程师来说,需要用到的机会比较少,它最常见于以下的一些应用场景中,例如:图片浏览,图片编辑(贴图效果)、网页缩放、地图、文本阅读(通过缩放手势调整文字大小)等。应用场景相对比较狭窄,不过肯定也会有一些用武之地,它可以实现如下的效果:

缩放手势的检测

 

2.缩放手势检测(ScaleGestureDetector)

缩放手势检测同样是官方提供的手势检测工具,它的使用方式的 GentureDetector 类似,也是通过 Listener 进行监听用户的操作手势,它是对缩放手势进行了一次封装, 可以方便用户快速的完成缩放相关功能的开发。缩放手势相对比较简单,网络上也能查到不少非官方实现的缩放手势计算方案,但部分非官方的方案确实有所局限,例如只支持两个手指的计算,在出现超过两个手指时,只计算了前两个手指的移动,这样显然是不合理的。而官方的这种实现方案轻松的应对了多个手指的情况,下面我们就来看看它是如何实现的吧。

2.1 构造方法

它有两个构造方法,和 GestureDetector 类似,如下所示:

ScaleGestureDetector(Contextcontext,ScaleGestureDetector.OnScaleGestureListenerlistener)
ScaleGestureDetector(Contextcontext,ScaleGestureDetector.OnScaleGestureListenerlistener,Handlerhandler) 

2.2 手势监听器

它只有两个监听器,但严格来说,这两个监听器是同一个,只不过一个是接口,另一个是空实现而已。

监听器 简介

OnScaleGestureListener 缩放手势检测器

SimpleOnScaleGestureListene r缩放手势检测器的空实现。

2.3 简单示例

这是使用 ScaleGestureDetector 的一个极简用例,当然,它没有实现任何功能,只是用日志的方式输出了几个我们比较关心的参数而已。

public class ScaleGestureDemoView extends View { 
 private static final String TAG = "ScaleGestureDemoView";
 private ScaleGestureDetector mScaleGestureDetector;
 public ScaleGestureDemoView(Context context) { 
 super(context);
 }
 public ScaleGestureDemoView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 initScaleGestureDetector();
 } 
 private void initScaleGestureDetector() { 
 mScaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() {
 @Override
 public boolean onScaleBegin(ScaleGestureDetector detector) { 
 return true;
 } 
 @Override
 public boolean onScale(ScaleGestureDetector detector) {
 Log.i(TAG, "focusX = " + detector.getFocusX()); // 缩放中心,x坐标
 Log.i(TAG, "focusY = " + detector.getFocusY()); // 缩放中心y坐标
 Log.i(TAG, "scale = " + detector.getScaleFactor()); // 缩放因子
 return true;
 }
 @Override 
 public void onScaleEnd(ScaleGestureDetector detector) { 
 }
 });
 } 
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 mScaleGestureDetector.onTouchEvent(event);
 return true; 
 }
 }

3. 基本原理

由于缩放手势检测使用起来非常简单,没有什么复杂的内容,不仅如此,它的实现也非常简单,下面我就带大家简单分析一下它的基本原理。在缩放手势中我们其实主要关心的只有两个参数而已,一个是缩放的中心点,另一个就是缩放比例了。 下面我们就看看这两个参数是如何计算出来的.

3.1 计算缩放的中心点(焦点)

如果只有两个手指的话,缩放的中心点自然是非常容易计算的,那就是两个手指坐标的中点,但是如果有多个手指该如何计算缩放的中心点呢?

计算中心点的原理其实也非常简单,那就是将所有的坐标都加起来,然后除以数量即可。

这是一个简单的数学原理,并不复杂,如果有不理解的,自己尝试计算一下也就能明白了。不过在实际运用中还是需要注意一下的, 用户的手指数量可能并不是固定的,用户可能随时抬起来或者按下手指,ScaleGestureDetector 中是这样实现的:

 finalbooleananchoredScaleCancelled=
 mAnchoredScaleMode == ANCHORED_SCALE_MODE_STYLUS && !isStylusButtonDown;
 final boolean streamComplete = action == MotionEvent.ACTION_UP ||
 finalbooleanstreamComplete=action==MotionEvent.ACTION_UP||
 action == MotionEvent.ACTION_CANCEL || anchoredScaleCancelled;
 // 注意这里
 if(action==MotionEvent.ACTION_DOWN||streamComplete){
 //重置侦听器正在进行的任何缩放。
 //如果是ACTION_DOWN,我们正在开始一个新的事件流。
 //这意味着应用程序可能没有给我们所有的事件(事件被上层直接拦截了)。
 if(mInProgress){
 mListener.onScaleEnd(this);
 mInProgress=false;
 mInitialSpan=0;
 mAnchoredScaleMode=ANCHORED_SCALE_MODE_NONE;
 }elseif(inAnchoredScaleMode()&&streamComplete){
 mInProgress=false;
 mInitialSpan=0;
 mAnchoredScaleMode=ANCHORED_SCALE_MODE_NONE;
 }
 if(streamComplete){
 returntrue;
 }
} 

可以看到,当触发 down 或者触发 up,cancel 时,如果之前处于缩放计算的状态,会将其状态重置, 并调用 onScaleEnd 方法。

计算中心点:

 final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
 action == MotionEvent.ACTION_POINTER_UP ||
 action == MotionEvent.ACTION_POINTER_DOWN || anchoredScaleCancelled; 
 // 注意这里
 final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP; 
 final int skipIndex = pointerUp ? event.getActionIndex() : -1; 
 // 确定焦点
 float sumX = 0, sumY = 0;
 final int div = pointerUp ? count - 1 : count; 
 final float focusX; 
 final float focusY;
 if (inAnchoredScaleMode()) { 
 // 在锚定比例模式下,焦点始终是双击或按钮按下时手势开始的位置
 focusX = mAnchoredScaleStartX; 
 focusY = mAnchoredScaleStartY; 
 if (event.getY() < focusY) {
 mEventBeforeOrAboveStartingGestureEvent = true;
 } else { 
 mEventBeforeOrAboveStartingGestureEvent = false; 
 } } else {
 // 注意这里, 最终计算得到焦点 
 for (int i = 0; i < count; i++) {
 if (skipIndex == i) continue;
 sumX += event.getX(i);
 sumY += event.getY(i);
 }
 focusX = sumX / div; 
 focusY = sumY / div;
 } 

3.2 计算缩放比例

计算缩放比例也很简单,就是计算各个手指到焦点的平均距离,在用户手指移动后用新的平均距离除以旧的平均距离,并以此计算得出缩放比例。

 // 计算到焦点的平均距离
 floatdevSumX=0,devSumY=0;
 for(inti=0;i<count;i++){
 if (skipIndex == i) continue;
 devSumX+=Math.abs(event.getX(i)-focusX);
 devSumY+=Math.abs(event.getY(i)-focusY);
 }
 finalfloatdevX=devSumX/div;
 finalfloatdevY=devSumY/div;
 // 注意这里
 finalfloatspanX=devX*2;
 finalfloatspanY=devY*2;
 finalfloatspan;
 if(inAnchoredScaleMode()){
 span=spanY;
 }else{
 // 相当于 sqrt(x*x + y*y)
 span=(float)Math.hypot(spanX,spanY);
 }

当用户移动的距离超过一定数值(数值大小由系统定义)后,会触发 onScaleBegin 方法,如果用户在 onScaleBegin 方法里面返回了 true,表示接受事件后,就会重置缩放相关数值,并且开始积累缩放因子。

 // mSpanSlop 和 mMinSpan 都是从系统里面取得的预定义数值,该数值实际上影响的是缩放的灵敏度。
 // 不过该参数并没有提供设置的方法,如果对灵敏度不满意的话,和通过直接之际复制一个 ScaleGestureDetector 到项目中, 并且修改其中的数值。
 finalintminSpan=inAnchoredScaleMode()?mSpanSlop:mMinSpan;
 if(!mInProgress&&span>=minSpan&&
 (wasInProgress||Math.abs(span-mInitialSpan)>mSpanSlop)){
 mPrevSpanX=mCurrSpanX=spanX;
 mPrevSpanY=mCurrSpanY=spanY;
 mPrevSpan=mCurrSpan=span;
 mPrevTime=mCurrTime;
 mInProgress=mListener.onScaleBegin(this);
 }

通知用户缩放:

 if(action==MotionEvent.ACTION_MOVE{
 mCurrSpanX=spanX;
 mCurrSpanY=spanY;
 mCurrSpan=span;
 booleanupdatePrev=true;
 if(mInProgress){
 // 注意这里,用户的返回值决定了是否重新计算缩放因子
 updatePrev=mListener.onScale(this);
 }
 // 如果用户返回了 true ,就会重新计算缩放因子
 if(updatePrev){
 mPrevSpanX=mCurrSpanX;
 mPrevSpanY=mCurrSpanY;
 mPrevSpan=mCurrSpan;
 mPrevTime=mCurrTime;
 }
 }

由于缩放手势检测确实比较简单,也大概就这么多了,感兴趣的话,可以私信我



Tags:Android 缩放手势   点击:()  评论:()
声明:本站部分内容来自互联网,内容观点仅代表作者本人,如有任何版权侵犯请与我们联系,我们将立即删除。
▌相关评论
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
▌相关推荐
缩放手势对于大部分 Android 工程师来说,需要用到的机会比较少,它最常见于以下的一些应用场景中,例如:图片浏览,图片编辑(贴图效果)、网页缩放、地图、文本阅读(通过缩放手势调...【详细内容】
2019-09-10   Android 缩放手势  点击:(8)  评论:(0)  加入收藏
推荐资讯
相关文章
栏目更新
栏目热门