个人网站的色彩设计怎么做,建站之星网站建设下载版,网站建设总体要求,网络推广运营外包其实在我们日常的编程中#xff0c;对于缩放手势的使用并不是很经常#xff0c;这一手势主要是用在图片浏览方面#xff0c;比如下方例子。但是#xff08;敲重点#xff09;#xff0c;作为 Android 入门的基础来说#xff0c;学习 ScaleGestureDetector 的使用#x…其实在我们日常的编程中对于缩放手势的使用并不是很经常这一手势主要是用在图片浏览方面比如下方例子。但是敲重点作为 Android 入门的基础来说学习 ScaleGestureDetector 的使用算是不得不过的一道坎好在 ScaleGestureDetector 使用起来非常简单就是源码分析上得花些功夫。 本文首先将简单的介绍下 ScaleGestureDetector 的使用在重点给大家分析下源码由于源码方面是我自己的理解可能有偏差希望各位大佬能在评论区指出万分感谢 ScaleGestureDetector 使用 ScaleGestureDetector 包括一个监听器以及它所有方法的空实现 名称用途ScaleGestureDetector缩放手势的监听器SimpleOnScaleGestureListener该监听器的空实现在其中重写方法ScaleGestureDetector 方法 名称用途onScaleBegin当 2 个手指碰触屏幕时调用若返回 false 则忽略改事件调用onScale滑动缩放过程中调用若成功处理则用户返回 true监听器继续记录下一个缩放等动作若为 false 表明数据未处理则监听器继续积累onScaleEnd全部手指离开屏幕结束监听通常情况下手势监听会结合自定义 View 来讲这里我给出一个最简单的使用具体的使用实例以后再结合自定义 View 讲讲。 private void iniScaleGestureListener(){mListener new ScaleGestureDetector.SimpleOnScaleGestureListener(){Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return super.onScaleBegin(detector);}Overridepublic boolean onScale(ScaleGestureDetector detector) {MyLog.d(X: detector.getFocusX());MyLog.d(Y: detector.getFocusY());MyLog.d(scale: detector.getScaleFactor());return super.onScale(detector);}Overridepublic void onScaleEnd(ScaleGestureDetector detector) {super.onScaleEnd(detector);}};detector new ScaleGestureDetector(getContext(), mListener);}Overridepublic boolean onTouchEvent(MotionEvent event) {detector.onTouchEvent(event);return true;} ScaleGestureDetector 的使用 ScaleGestureDetector 在具体项目的使用有点复杂我打算过段时间结合自定义 View 写一篇用来总结所以这篇我们就先了解下 ScaleGestureDetector 的基本使用。 ScaleGestureDetector 源码分析 好了现在我们进入本章重点ScaleGestureDetector 源码分析敲黑板敲黑板。首先我们打开 ScaleGestureDetector 的源码可以看到几乎所有的代码都集中在了 onTouchEvent 这个方法上所以在这里我就主要给大家介绍这个方法的实现。 第一部分前期准备 if (mInputEventConsistencyVerifier ! null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);}mCurrTime event.getEventTime();final int action event.getActionMasked();// Forward the event to check for double tap gestureif (mQuickScaleEnabled) {mGestureDetector.onTouchEvent(event);}final int count event.getPointerCount();final boolean isStylusButtonDown (event.getButtonState() MotionEvent.BUTTON_STYLUS_PRIMARY) ! 0; mInputEventConsistencyVerifier 输入事件一致性验证器 有道根据名字以及前面的定义我们可以猜测这个对象应该是手势监听 Event 是否注册连接到硬件所以如果他为空那么我们在这里调用 onTouchEvent 进行注册 if (mInputEventConsistencyVerifier ! null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);} mCurrTime 获得事件发生时的时间 mCurrTime event.getEventTime(); action 获得事件类型 final int action event.getActionMasked(); mQuickScaleEnabled Forward the event to check for double tap gesture有道 转发事件以检查双击手势首先是 mQuickScaleEnabled 这个对象翻译过来是 有道 启用快速扩展作用大概就是调用双击监听事件比如双击最大化 if (mQuickScaleEnabled) {mGestureDetector.onTouchEvent(event);} count 获得屏幕上手指的数目 final int count event.getPointerCount(); isStylusButtonDown 这个主要是由于判断手写笔是否按下 由于我们很少处理手写笔所以这里不做过多说明 final boolean isStylusButtonDown (event.getButtonState() MotionEvent.BUTTON_STYLUS_PRIMARY) ! 0; ## 第二部分处理与手势变化 用户的缩放手势不总是一定的就是说对于用户而言随时可能有手指碰触或离开屏幕这就使得缩放中心的焦点随时可能发生变化这部分主要是用来处理这一变化并做出响应。 final boolean anchoredScaleCancelled mAnchoredScaleMode ANCHORED_SCALE_MODE_STYLUS !isStylusButtonDown;final boolean streamComplete action MotionEvent.ACTION_UP ||action MotionEvent.ACTION_CANCEL || anchoredScaleCancelled;// 如果发生了上面这种小动作或者说有一手指离开了屏幕进行调用if (action MotionEvent.ACTION_DOWN || streamComplete) {// Reset any scale in progress with the listener.// If its an ACTION_DOWN were beginning a new event stream.// This means the app probably didnt give us all the events. Shame on it.if (mInProgress) {mListener.onScaleEnd(this);mInProgress false;mInitialSpan 0;mAnchoredScaleMode ANCHORED_SCALE_MODE_NONE;} else if (inAnchoredScaleMode() streamComplete) {mInProgress false;mInitialSpan 0;mAnchoredScaleMode ANCHORED_SCALE_MODE_NONE;}if (streamComplete) {return true;}} ### anchoredScaleCancelled Google 锚定规模取消我的理解是用于判断滑动事件是否被取消 final boolean anchoredScaleCancelled mAnchoredScaleMode ANCHORED_SCALE_MODE_STYLUS !isStylusButtonDown; streamComplete Google Translate: 流完成我的理解是这个布尔变量用于标记当前动作是否完成我这里说的动作有两种这里指的是在大动作如三指触屏放大过程中又一个手指离开了屏幕这种在大动作三指触屏中发生的一个小动作离开一指 final boolean streamComplete action MotionEvent.ACTION_UP ||action MotionEvent.ACTION_CANCEL || anchoredScaleCancelled; action MotionEvent.ACTION_DOWN || streamComplete 如果发生了上面这种小动作或者说有一手指离开了屏幕就进行调用if (action MotionEvent.ACTION_DOWN || streamComplete) {...} if (mInProgress) google Translate重置侦听器正在进行的任何缩放。如果是ACTION_DOWN我们开始一个新的事件流。这意味着应用程序可能没有给我们所有的事件。很遗憾。首先判断该进程从第一个手指碰上屏幕到最后一个手指离开屏幕为止是否结束如果仍在运行中这调用回调方法onScaleEnd 使其结束 if (mInProgress) {mListener.onScaleEnd(this);mInProgress false;mInitialSpan 0;mAnchoredScaleMode ANCHORED_SCALE_MODE_NONE;} else if (inAnchoredScaleMode() streamComplete) 如果当前进程已经结束判断 mAnchoredScaleMode 是否为 ANCHORED_SCALE_MODE_STYLUS 状态同时判断操作流 streamComplete 是否完成都符合的情况下结束这一手势变化 else if (inAnchoredScaleMode() streamComplete) {mInProgress false;mInitialSpan 0;mAnchoredScaleMode ANCHORED_SCALE_MODE_NONE;} if (streamComplete) 结束本次 onTouchEvent 方法的调用等待下一次调用发生 if (streamComplete) {return true;} 总结 可以看到当触发 down 或者触发 upcancel 时如果之前处于缩放计算的状态会将其状态重置 并调用 onScaleEnd 方法。 进入锚定比例模式 当判断用户动作如果为双击这类点击事件进入该模式与正常缩放区分。这个模式功能一般是双击最大化和最小化 if (!mInProgress mStylusScaleEnabled !inAnchoredScaleMode() !streamComplete isStylusButtonDown) {// Start of a button scale gesturemAnchoredScaleStartX event.getX();mAnchoredScaleStartY event.getY();mAnchoredScaleMode ANCHORED_SCALE_MODE_STYLUS;mInitialSpan 0;} mAnchoredScaleStartX mAnchoredScaleStartY 后文中将用于重新计算焦点 mAnchoredScaleStartX event.getX();mAnchoredScaleStartY event.getY(); mAnchoredScaleMode 赋值之后再次调用 inAnchoredScaleMode() 方法返回值变为 true mAnchoredScaleMode ANCHORED_SCALE_MODE_STYLUS; 计算缩放中心 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;// Determine focal pointfloat sumX 0, sumY 0;final int div pointerUp ? count - 1 : count;final float focusX;final float focusY;if (inAnchoredScaleMode()) {// In anchored scale mode, the focal pt is always where the double tap// or button down gesture startedfocusX 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;} configChanged 布尔类型量标志着一个操作的完成或者结束手指离开手指按下 final boolean configChanged action MotionEvent.ACTION_DOWN ||action MotionEvent.ACTION_POINTER_UP ||action MotionEvent.ACTION_POINTER_DOWN || anchoredScaleCancelled; pointerUp 布尔类型量用于判断当前动作是否为手指离开抬起动作 final boolean pointerUp action MotionEvent.ACTION_POINTER_UP; skipIndex 标记量在是手指离开的情况下标记离开手指在后面计算新的焦点代码中跳过该手指的标记点坐标进行计算 final int skipIndex pointerUp ? event.getActionIndex() : -1; 初始化计算所需临时变量 // Determine focal pointfloat sumX 0, sumY 0;// 如果是抬起手指则当前手指数减1否则不变final int div pointerUp ? count - 1 : count;final float focusX;final float focusY; 判断是否为锚定比例模式 是的话直接将点击时记下的点作为焦点不是的话把所有点累加求和除以总个数计算平均值 if (inAnchoredScaleMode()) {// In anchored scale mode, the focal pt is always where the double tap// or button down gesture started// 在锚定比例模式中焦点pt始终是双击的位置或按下手势开始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;} 算缩放比例 计算缩放比例也很简单就是计算各个手指到焦点的平均距离在用户手指移动后用新的平均距离除以旧的平均距离并以此计算得出缩放比例。 // Determine average deviation from focal point Google translate float devSumX 0, devSumY 0;for (int i 0; i count; i) {if (skipIndex i) continue;// Convert the resulting diameter into a radius.devSumX Math.abs(event.getX(i) - focusX);devSumY Math.abs(event.getY(i) - focusY);}final float devX devSumX / div;final float devY devSumY / div;// Span is the average distance between touch points through the focal point;// i.e. the diameter of the circle with a radius of the average deviation from// the focal point.final float spanX devX * 2;final float spanY devY * 2;final float span;if (inAnchoredScaleMode()) {span spanY;} else {span (float) Math.hypot(spanX, spanY);} 计算平均偏差 确定焦点的平均偏差 float devSumX 0, devSumY 0;for (int i 0; i count; i) {if (skipIndex i) continue;// Convert the resulting diameter into a radius.devSumX Math.abs(event.getX(i) - focusX);devSumY Math.abs(event.getY(i) - focusY);}final float devX devSumX / div;final float devY devSumY / div; 计算缩放比例 跨度是通过焦点的触摸点之间的平均距离;即圆的直径其半径为平均偏差这里的 Math.hypot(spanX, spanY) 方法相当于 sqrt(xx yy) final float spanX devX * 2;final float spanY devY * 2;final float span;if (inAnchoredScaleMode()) {span spanY;} else {span (float) Math.hypot(spanX, spanY);} 结束缩放事件 Google Translate根据需要调度开始/结束事件。如果配置发生更改请通过开始通知应用重置其当前状态一个新的比例事件流。这里就不做太多描述主要就是判断是不是所有手指都离开了屏幕如果是那么索命这个缩放进程结束了则保存当前缩放的数据调用 onScaleEnd 方法结束当前操作 final boolean wasInProgress mInProgress;mFocusX focusX;mFocusY focusY;if (!inAnchoredScaleMode() mInProgress (span mMinSpan || configChanged)) {mListener.onScaleEnd(this);mInProgress false;mInitialSpan span;}if (configChanged) {mPrevSpanX mCurrSpanX spanX;mPrevSpanY mCurrSpanY spanY;mInitialSpan mPrevSpan mCurrSpan span;} 触发 onScaleBegin 开始缩放 当手指移动的距离超过一定数值(数值大小由系统定义)后会触发 onScaleBegin 方法如果用户在 onScaleBegin 方法里面返回了 true则接受事件后就会重置缩放相关数值并且开始积累缩放因子。 final int minSpan 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);} 通知用户进行缩放处理 Google Translate: 处理动作;焦点和跨度/比例因子正在发生变化。这块代码的功能主要就是通知用户编程者根据这些数据进行缩放 if (action MotionEvent.ACTION_MOVE) {mCurrSpanX spanX;mCurrSpanY spanY;mCurrSpan span;boolean updatePrev true;if (mInProgress) {updatePrev mListener.onScale(this);}if (updatePrev) {mPrevSpanX mCurrSpanX;mPrevSpanY mCurrSpanY;mPrevSpan mCurrSpan;mPrevTime mCurrTime;}} updatePrev 这个用于接收用户的返回值只要我们放回 true 系统就会保存当前数据重新获取并计算新的数据和比例系统默认返回 false 然后进行下一次事件的计算 if (mInProgress) {updatePrev mListener.onScale(this);}if (updatePrev) {mPrevSpanX mCurrSpanX;mPrevSpanY mCurrSpanY;mPrevSpan mCurrSpan;mPrevTime mCurrTime;} 结语 我要讲的所有内容到这里就完全结束了 由于源码是按照我自己的理解来讲的所以难免会有一些出入 希望大家能在评论区中帮我指出谢谢 ? 转载于:https://www.cnblogs.com/yuanhao-1999/p/11102806.html