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

上一篇介绍安卓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;// 记录上一次两点的距离

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView (R.layout.activity_main);

        detector = new GestureDetector (this, this);
        iv = (ImageView) findViewById (R.id.iv);
    }

    @Override
    public boolean onTouchEvent (MotionEvent event) {
        return detector.onTouchEvent (event);
    }

    @Override
    public boolean onDown (MotionEvent e) {
        // 每次按下后重新复位-1f
        lastDistance = -1f;
        return false;
    }

    @Override
    public void onShowPress (MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp (MotionEvent e) {
        return false;
    }

    @Override
    public 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) {
                    // 放大,最大放大到500
                    Log.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) {
                    // 缩小,最小缩小到100
                    Log.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;
    }

    @Override
    public void onLongPress (MotionEvent e) {

    }

    @Override
    public 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)-实现自定义手势。(待续)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值