美文网首页Android使用场景
Android开发:实现双向滑动BidirectionalIma

Android开发:实现双向滑动BidirectionalIma

作者: 享学课堂 | 来源:发表于2020-05-29 17:22 被阅读0次

前言

在平时打开图库经常能看到这个效果 闲暇时光决定 模仿了一下写了这个demo, 下边就是效果图。这个效果主要利用GestureDetectorCompat处理手势 然后通过OverScroller实现。

正文大纲

GestureDetectorCompat使用

放大以及平移功能的实现

  • 放大功能实现

  • 平移功能实现

  • 平滑过程的实现

OverScroller实现快速滑动效果

  • OverScroller及其滑动范围

  • post和postOnAnimation区别

  • OverScroller和Scroller区别

总结

正文

GestureDetectorCompat使用

首先看初始化创建对象


1.  `detector = newGestureDetectorCompat(context, this);`

然后我们利用GestureDetectorCompat 拦截当前的的事件


1.  `@Override`

2.  `publicboolean onTouchEvent(MotionEventevent) {`

3.  `return detector.onTouchEvent(event);`

4.  `}`

处理好这些,GestureDetectorCompat可实现的回调就可以响应了。


1.  `@Override`

2.  `publicboolean onDown(MotionEvent e) {`

3.  `returntrue;`

4.  `}`

6.  `@Override`

7.  `publicvoid onShowPress(MotionEvent e) {`

9.  `}`

10.  `@Override`

11.  `publicboolean onSingleTapUp(MotionEvent e) {`

12.  `returnfalse;`

13.  `}`

14.  `@Override`

15.  `publicboolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {`

17.  `}`

18.  `@Override`

19.  `publicvoid onLongPress(MotionEvent e) {`

21.  `}`

22.  `@Override`

23.  `publicboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {`

24.  `returnfalse;`

25.  `}`

28.  `@Override`

29.  `publicboolean onDoubleTap(MotionEvent e) {`

31.  `}`

这时候我们会有两类疑问,这些相似的响应的方法是什么?他们和我们自带的那些onclick有什么区别?下边简单介绍一下

1.  `publicboolean onDown(MotionEvent e);`

onDown是我们收到ACTION_DOWN时候就会被调用,一般来说,通过该事件处理我当前事件是否被消费了,然后返回的值通过detector.onTouchEvent(event)返回体现出来。

1.  `publicvoid onShowPress(MotionEvent e);`

onShowPress是一个预按下的事件,在GestureDetector中是响应到ACTION_DOWN事件,100毫秒之后触发的。


1.  `publicboolean onSingleTapUp(MotionEvent e);`

onSingleTapUp很好理解 每次点击抬起时调用。这里要注意,如果长按事件被执行那么onSingleTapUp就不执行。

1.  `publicboolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);`

onScroll 类似ACTION_MOVE手指发生移动之后调用,e1表示按下时候的时间,e2表示正在处理的事件,distanceX和distanceY表示移动距离。

1.  `publicvoid onLongPress(MotionEvent e);`

onLongPress是长按时调用的默认事件是600毫秒。可以通过detector.setIsLongpressEnabled(false);将长按事件取消。

1.  `publicboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);`

onFling是手指快速滑动时调用的,下边我会介绍。

1.  `publicboolean onDoubleTap(MotionEvent e);`

2.  `publicboolean onDoubleTapEvent(MotionEvent e);`

onDoubleTap和onDoubleTapEvent都是双击点击事件,区别在于onDoubleTapEvent第二次点击可以滑动。


放大以及平移功能的实现

放大功能实现

1.  `@Override`

2.  `public  boolean onDoubleTap(MotionEvent e)  {`

3.  `isEnlarge =  !isEnlarge;`

4.  `scaleAnimator =  ObjectAnimator.ofFloat(this,  "currentScale",  0);`

5.  `if  (isEnlarge)  {`

6.  `scaleAnimator.start();`

7.  `}  else  {`

8.  `scaleAnimator.reverse();`

9.  `}` 

10.  `....`

11.  `}`

13.  `@Override`

14.  `protected  void onDraw(Canvas canvas)  {`

15.  `super.onDraw(canvas);`

16.  `....`

17.  `canvas.scale(currentScale, currentScale, getWidth()  /  2f, getHeight()  /  2f);`

18.  `}`

onDoubleTap 我利用onDoubleTap双击事件 控制isEnlarge操作动画来实现图片的放大和缩小的效果。

接下来我们去看一下放到后如何进行移动的。

平移功能实现

1.  `@Override`

2.  `protected  void onDraw(Canvas canvas)  {`

3.  `super.onDraw(canvas);`

4.  `....`

5.  `canvas.translate(motionEventX * currentScale, motionEventY * currentScale);`

6.  `....`

7.  `}`

这个也很简单,通过canvas.translate 改变坐标系,然后随着手指对应图片的滑动的。那么motionEventX和motionEventY是如何计算出来的呢?这里 我们是通过GestureDetectorCompat中的onScroll这个方法计算出来的,为什么会有两个MotionEvent参数,下边简单叙述一下对应的参数的作用。

平滑过程的实现


1.  `publicboolean onScroll(MotionEvent down, MotionEventevent, float distanceX, float distanceY);`

MotionEvent down 代表按下的事件,MotionEvent event代表当前的事件,distanceX代表上一个点到当前点的x轴距离,distanceY代表上一个点到当前点的Y轴距离。


1.  `@Override`

2.  `public  boolean onScroll(MotionEvent e1,  MotionEvent e2,  float distanceX,  float distanceY)  {`

3.  `if  (isEnlarge)  {`

4.  `motionEventX -= distanceX;`

5.  `motionEventY -= distanceY;`

6.  `....`

7.  `invalidate();`

8.  `}`

9.  `return  false;`

10.  `}`

上边是onScroll的具体实现,motionEventX和motionEventY是通过distanceX和distanceY计算出来的,但是这里为什么要用减法呢?手指向右移动图片,distanceX是正值,canvas.translate的坐标也要是负值图片才能要向右移动。同理distanceY也是如此。

这里要注意motionEventX和motionEventY的不要超过屏幕的边距。


OverScroller实现快速滑动效果

OverScroller及其滑动范围

运行了之后,我发现快滑的时候没有效果,这是因为我们没有对onFling进行处理,我们可以利用OverScroller中的scroller.fling方法进行计算,处理快速滑动的事件。


1.  `private  OverScroller scroller;`

3.  `@Override`

4.  `public  boolean onFling(MotionEvent e1,  MotionEvent e2,  float velocityX,  float velocityY)  {`

5.  `if  (isEnlarge)  {`

6.  `scroller.fling((int) motionEventX,  (int) motionEventY,  (int) velocityX,  (int) velocityY,`

7.  `-(int)  (bitmap.getWidth()  * bigScale - getWidth())  /  2,`

8.  `(int)  (bitmap.getWidth()  * bigScale - getWidth())  /  2,`

9.  `-(int)  (bitmap.getHeight()  * bigScale - getHeight())  /  2,`

10.  `(int)  (bitmap.getHeight()  * bigScale - getHeight())  /  2);`

11.  `postOnAnimation(motionRunnable);`

12.  `}`

13.  `return  false;`

14.  `}`

scroller.fling的参数有点多 但是很好记。先看下八个参数是什么。


1.  `publicvoid fling(int startX, int startY, int velocityX, int velocityY,`

2.  `int minX, int maxX, int minY, int maxY);`

startX和startY代表初始的位置,在这个demo中就是我们手指点击的位置motionEventX,和motionEventY。velocityX和velocityY代表速度,手指抬起的时和之前的位移除以时间的计算,得出的结果。minX maxX minY maxY处理边距,这里以中心点为原点,放大后超过图片大小的部分除以2找到对应边界,如下图所示。

手指可滑动的范围是黑色框以外的部分。

上边说到scroller.fling是对于滑动方法的计算,但是我们需要对当前布局进行刷新。这里就用到了一个方法scroller.computeScrollOffset()判断是否完成滚动从而进行刷新。这里可以看一下postOnAnimation(motionRunnable);方法。

1.  `MotionRunner motionRunnable =  new  MotionRunner();`

2.  `....`

3.  `postOnAnimation(motionRunnable);`
1.  `class  MotionRunner  implements  Runnable  {`

3.  `@Override`

4.  `public  void run()  {`

5.  `if  (scroller.computeScrollOffset())  {`

6.  `motionEventX = scroller.getCurrX();`

7.  `motionEventY = scroller.getCurrY();`

8.  `invalidate();`

9.  `postOnAnimation(this);`

10.  `}`

11.  `}`

12.  `}`

这样我们每一帧动画执行完成后,不断调用postOnAnimation,直到scroller滚动完成。

post和postOnAnimation区别

这里postOnAnimation和post区别在于postOnAnimation在下一帧之后执行而post是立即在主线程中执行,有可能post执行要比postOnAnimation快,或者一帧中post会执行多次。这里使用ViewCompat.postOnAnimation兼容性更好。

OverScroller和Scroller区别

在这个demo中我用的是OverScroller,但是他与Scroller有什么区别呢?简单说下overscrller会多两个参数

1.  `publicvoid fling(int startX, int startY, int velocityX, int velocityY,`

2.  `int minX, int maxX, int minY, int maxY, int overX, int overY);`

overX和overY代表超过范围的位置,在原来基础的距离上增加overx和overy。

总结

这里我们利用GestureDetectorCompat处理手势操作,处理双击事件以及滑动事件。双击事件执行后通过动画和canvas.scale()实现了放大缩小操作,通过滑动事件(onFling和onScroll)来处理图片放大后滑动。

相关文章

网友评论

    本文标题:Android开发:实现双向滑动BidirectionalIma

    本文链接:https://www.haomeiwen.com/subject/xmlfzhtx.html