当前位置: 代码迷 >> 综合 >> Iwfu-安卓Gesture手势(2)-实现多点触控控制图片的放大缩小。
  详细解决方案

Iwfu-安卓Gesture手势(2)-实现多点触控控制图片的放大缩小。

热度:83   发布时间:2023-12-19 02:09:27.0

上一篇介绍安卓Gesture手势初步使用,这一篇用Gesture来实现多点触控达到控制图片放大缩小。

上文中写道,进行手势监听的Activity要实现对应的OnGestureListener接口,重写其中的几个方法,其中最关键的两个方法:

@Override/* 手指滑动触发 */public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,float distanceY) {return false;}@Override/* 手指抛掷(快速划屏幕后松开) */public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {return false;}

这两个方法都传入了四个参数,分别代表:

e1: 第一个按下时的事件,可以当做第一次按下时的点

e2: 移动时的事件,分别用于触发scroll和fling

在onScroll中;

dsitanceX表示每次滑动的X方向的偏移量
dsitanceY表示每次滑动的Y方向的偏移量

在onFling中:

velocityX表示X方向的速度
velocityY表示Y方向的速度

知道了这个以后,我们要实现多点触控,那么怎么获取触摸时的多个点呢,这里有一个坑,大部分人认为是通过onScroll的e1.getPointCount( ),测试以后会发现,触摸点永远是1,其实e1代表的是第一个触摸到屏幕的那个手指的事件,即使你看上去两个手指是同时按下的,也有一个手指是最先碰到屏幕的,而这个手指就产生了这个MotionEvent e1,所以触摸点数永远是1。

真正的做法是,在onScroll()中使用

e2.getPointCount( )

来获取触摸点的数量,一般来说控制图片的放大缩小两个点就够了,这里以两个触摸点为例。

获取到触摸点以后,接下来就通过获取到的触摸点来判断监听事件,对图片进行相关操作.一般我们使用相册什么的对图片进行放大缩小是用两根手指,根据两点的距离变化来判断是要放大还是要缩小图片,其中对于的手指滑动的手势,会回调我们的onScroll和onFling,其中onScroll会随着手指滑动一直调用,就类似onTouch里监听到MotionEvent为Action_Move一样。所以我们重点重写这两个方法,并通过一个全局变量来保存每次滑动的距离,方便比较大小。

先贴代码,然后总结下里面容易踩到的坑。

代码:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.chan.gesturepointstouch.MainActivity"><ImageView  android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/iv"android:layout_centerInParent="true"android:src="@mipmap/ic_launcher"/>
</RelativeLayout>

MainActivity:

package com.chan.gesturepointstouch;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;/*** 多点触控 ,控制图片缩放*/
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {
    private GestureDetector detector;private ImageView iv;private float lastDistance = -1f;// 记录上一次两点的距离@Overrideprotected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState);setContentView (R.layout.activity_main);detector = new GestureDetector (this, this);iv = (ImageView) findViewById (R.id.iv);}@Overridepublic boolean onTouchEvent (MotionEvent event) {return detector.onTouchEvent (event);}@Overridepublic boolean onDown (MotionEvent e) {// 每次按下后重新复位-1flastDistance = -1f;return false;}@Overridepublic void onShowPress (MotionEvent e) {}@Overridepublic boolean onSingleTapUp (MotionEvent e) {return false;}@Overridepublic boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {// 从e2获取触点数量int pointCount = e2.getPointerCount ();if (pointCount == 2) {float deltaX = e2.getX (1) - e2.getX (0);float deltaY = e2.getY (1) - e2.getY (0);float distance = (float) Math.sqrt (deltaX * deltaX + deltaY * deltaY);// 误差值float slop = 5;RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) iv.getLayoutParams ();if (lastDistance < 0) {lastDistance = distance;} else {// 真正的比较if (distance - lastDistance > slop) {// 放大,最大放大到500Log.d ("tag", "放大");if (layoutParams.width < 800) {layoutParams.width = (int) (iv.getWidth () * 1.1f);layoutParams.height = (int) (iv.getHeight () * 1.1f);iv.setLayoutParams (layoutParams);} else {Toast.makeText (MainActivity.this, "不能再放大了", Toast.LENGTH_SHORT).show ();}} else if (distance - lastDistance < slop) {// 缩小,最小缩小到100Log.d ("tag", "缩小");if (layoutParams.width > 50) {layoutParams.width = (int) (iv.getWidth () * 0.9f);layoutParams.height = (int) (iv.getHeight () * 0.9f);iv.setLayoutParams (layoutParams);} else {Toast.makeText (MainActivity.this, "不能再缩小了", Toast.LENGTH_SHORT).show ();}}}}return false;}@Overridepublic void onLongPress (MotionEvent e) {}@Overridepublic boolean onFling (MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {return false;}
}

其中重点:

  • 每次回调onScroll都计算出两触摸点的距离(利用勾股定理),判断下如果lastDistance=-1,即没有保存状态,就保存当前的状态,继续滑动就继续回调onScroll,此时lastDistance保存的是上一次的两触摸点的距离,执行比较距离的代码~

  • 比较的时候给了一个临界值slop,这个值用于避免手指很微小的误操作都被捕捉到,并且这个值也不能太大,否则手指很难滑到这个临界值。

  • 比较时添加了判断图片大小,如果图片大到一定值就不允许继续放大,如果小到一定值就不允许继续缩小。

-改变图片大小用LayoutParams布局参数,每次判断完是放大还是缩小后按一定比例设置LayoutParams的宽高,再重新赋值给图片ImageView

  • 每次执行完一个完整的流程后要将全局的lastDistance复位为-1f,否则会保存上一次的触摸点的距离。

下一篇:安卓Gesture手势(3)-实现自定义手势。(待续)

  相关解决方案