首页 > 代码库 > Qt on Android: Qt Quick 事件处理之捏拉缩放与旋转

Qt on Android: Qt Quick 事件处理之捏拉缩放与旋转

    上一篇《Qt on Android: Qt Quick事件处理之鼠标、键盘、定时器》我们介绍了常见的鼠标、键盘、定时器的处理,鼠标、键盘都是电脑上我们最常使用的事件,这节我们来介绍 Android 智能手机上的一个非常重要的手势:捏拉手势。捏拉手势最早在苹果手机上得到应用,苹果还曾经尝试为此操作申请专利,借以钳制三星在美国的手机和平板销售。这些我们且不管它,咱们只说在 Qt Quick 中如何处理捏拉手势。

    广而告之:我正在参加 CSDN 博文大赛,请给我的参赛文章《Qt on Android: Qt Quick 事件处理之信号与槽》投票,谢谢。

    Qt Quick 中的 PinchArea 带来捏拉手势,看名字是不是和 MouseArea 类似?木错,就是酱紫。先来看 PinchArea 都有哪些属性和信号,了解了这些才能使用它。

PinchArea简介

    PinchArea 本身是一个不可见的 Item ,通常和一个可见的 Item 配合使用来处理捏拉手势。比如和一个 Rectangle 一块使用,或者和 Image 一块使用实现图片缩放、旋转等效果。捏拉手势识别实际上是通过对若干触摸事件的处理来实现的。

属性

    PinchArea 是 Item 的派生类,除了继承自 Item 的属性外,还有两个专属属性: enabled 和 pinch 。

    enabled 属性默认值为 true ,如果你设置为 false ,那么 PinchArea 就嘛事儿不干,捏拉区域对鼠标、触摸事件就变透明了。

    pinch 属性知名与捏拉手势的详情,它是一个组合属性,包括 target 、 active 、 minimumScale 、 maximumScale 、 minimumRotation 、 maximumRotation 、 dragAxis 、 minimumX 、 maximumX 、 minimumY 、 maximumY 等属性。

    target 指明捏拉手势要操作的 Item , active (bool类型)属性表示目标 Item 是否正在被拖动。

    minimumScale / maximumScale 设置最小、最大缩放系数。 minimuxRotation / maximumRotation 设置对小、最大旋转角度。这四个属性都是 real 类型。

    dragAxis 设置沿 X 轴(Pinch.XAxis) 、 Y 轴(Pinch.YAxis) 还是 XY (Pinch.XAndYAxis)两个轴拖动,你也可以禁止拖动,只要给 dragAxis 赋值 Pinch.NoDrag 即可。当 dragAxis 允许拖动时,minimumX / maximumX 设定 X 轴的最小、最大拖动位置, minimumY / maximumY 设定 Y 轴的最小、最大拖动位置。

信号

    PinchArea 有三个信号:onPinchStarted() 、 onPinchUpdated() 、 onPinchFinished() 。它们都有一个名为 pinch 的参数,类型是 PinchEvent 。为了有效响应这些信号,必须了解 PinchEvent 类型,我们先介绍它。

    PinchEvent 具有下列属性:

  • accepted ,在 onPinchStarted() 信号处理器中设置为 true 表明你要响应 PinchEvent ,Qt 会持续发给你更新事件;设置为 false ,Qt 就不会再发 PinchEvent 事件给你了。
  • angle ,表示最近两个触点之间的角度, previousAngle 是上一次事件的角度, rotation 是从捏拉手势开始到当前事件的总的旋转角度。
  • scale ,表示最近两个触点之间的缩放系数, previousScale 是上一次事件的缩放系数。
  • center ,两个触点的中心点, previousCenter 是上一次事件的中心点, startCenter 是事件开始时的中心点
  • point1 , point2 保存当前触点的位置, startPoint1 , startPoint2 保存第二个触点按下时两个触点的位置。
  • pointCount 保存到现在为止的触点总数。

    onPinchStarted() 信号在第一次识别到捏拉手势时发出,如果你要处理它,那就要将其设置为 true 。然后就可以通过 pinch 参数来设置要变换的 Item 了。

    当你在 onPinchStarted() 的信号处理器中接受了 TouchEvent 事件,那么 Qt 就会不断的发送新事件给你, onPinchUpdated() 信号就会不断的发射,你可以在它的信号处理器中通过 pinch 参数,撷取你需要的值来更新你的 Item 。

    onPinchFinished() 信号在用户手指离开屏幕时触发。

怎样使用

    介绍了 PinchArea 和 PinchEvent ,是时候看看怎么使用它们了。

    要想使用 PinchArea 来变换一个 Item ,有两个办法:

  1. 设定 target 属性,将其指向要变换的 Item ,然后 PinchArea 就会在合适的时候帮你变换它。
  2. 处理 onPinchStarted() / onPinchUpdated() / onPinchFinished() 信号,在信号处理器中变换目标 Item 。这种方式更灵活,你甚至可以同时处理多个 Item 。

    选定一种方式后,你可能还要配置 PinchArea.pinch 属性,给不同的参数设置合理的值,比方说最大可以放大到多少倍。

缩放与旋转实例

    这里提供一个简单的使用 PinchArea 的实例,我们用 PinchArea 来旋转和缩放一个矩形。

    项目的创建参考《Qt on Android: Qt Quick 之 Hello World 图文详解》,这里不再赘述。

使用 pinch.target

    我们先用第一种方式,指定 pinch.target 。直接看 main.qml 文档吧:

import QtQuick 2.0

Rectangle {
    width: 360;
    height: 360;
    focus: true;
    Rectangle {
        width: 100;
        height: 100;
        color: "blue";
        id: transformRect;
        anchors.centerIn: parent;
    }
    PinchArea {
        anchors.fill: parent
        pinch.maximumScale: 20;
        pinch.minimumScale: 0.2;
        pinch.minimumRotation: 0;
        pinch.maximumRotation: 90;
        pinch.target: transformRect;
    }
}

    代码很简单,初始化了最小、最大缩放系数,最小、最大旋转角度,然后将 pinch.target 指向 id 为 transformRect 的蓝色矩形。于是,一切都正常运转,两指捏拉之间,缩放与旋转效果就出来了。

    图 1 是在 Android 手机上运行的起始效果:


            图 1 pinchArea 示例启动效果

    图 2 是我两个指头捏拉 了几下后的效果:


            图 2 pinchArea 缩放与旋转效果

    使用 pinch.target 这种方式,你什么都不用关心,甚至不需要弄明白 pinch 属性到底是什么含义,就可以得到一个不错的变换效果, Qt Quick 默认帮你处理所有的事情。

    下面看看使用信号的方式。

使用信号

    使用 onPinchStarted() / onPinchUpdated() / onPinchFinished() 要稍微麻烦一些,你必须要了解 PinchEvent 每个参数的含义,自己设计变换策略。不过好处是,七十二般变化都由你控制。

    直接看新的 main.qml 文档:

import QtQuick 2.0

Rectangle {
    width: 360;
    height: 360;
    focus: true;
    Rectangle {
        width: 100;
        height: 100;
        color: "blue";
        id: transformRect;
        anchors.centerIn: parent;
    }
    PinchArea {
        anchors.fill: parent
        pinch.maximumScale: 20;
        pinch.minimumScale: 0.2;
        pinch.minimumRotation: 0;
        pinch.maximumRotation: 90;

        onPinchStarted: {
            pinch.accepted = true;
        }
        onPinchUpdated: {
            transformRect.scale *= pinch.scale;
            transformRect.rotation += pinch.rotation;
        }
        onPinchFinished: {
            transformRect.scale *= pinch.scale;
            transformRect.rotation += pinch.rotation;
        }
    }
}

    代码大部分都和 pinch.target 方式一样,只是去掉了 "pinch.target: transformRect" 语句,改用信号处理器。代码很直接,不再解释了。


    OK,这篇到此结束。

    回顾一下:

  • Qt on Android:Qt Quick 简介
  • Qt on Android:QML 语言基础
  • Qt on Android: Qt Quick 之 Hello World 图文详解
  • Qt on Android: Qt Quick 简单教程
  • Qt on Android: Qt Quick 事件处理之信号与槽
  • Qt on Android: Qt Quick事件处理之鼠标、键盘、定时器