写点什么

Flutter 中的手势【Flutter 专题 10】

作者:坚果前端
  • 2021 年 11 月 28 日
  • 本文字数:4991 字

    阅读完需:约 16 分钟

Flutter 中的手势【Flutter 专题10】

在 Flutter 中处理手势

在创建应用程序时,您必须处理用户手势,例如触摸和拖动。这使您的应用程序具有交互性。


为了有效地处理手势,您需要倾听手势并做出响应。Flutter 提供了各种小部件,有助于为您的应用程序添加交互性。


在本文中,我们将使用GestureDetector小部件来处理手势。

介绍

一些小部件,如ContainerCard小部件,没有检测手势的内置方式。这些小部件被包裹在小部件中,GestureDetector小部件纯粹用于检测手势,不会像涟漪效应那样给出任何视觉响应。


GestureDetector小部件通过识别具有回调定义的手势并相应地响应事件来工作。如果要禁用手势,则会将null值传递给回调。


以下是GestureDetector小部件捕获的常见手势、它们对应的事件和可能的应用程序(所有插图均归功于Luke Wroblewski 的触摸手势参考指南):

轻敲

用户用指尖短暂地触摸了屏幕。



  • onTapDown — 当用户接触屏幕时触发,可能是点击

  • onTapUp — 当用户停止接触屏幕时触发

  • onTap — 当用户短暂触摸屏幕时触发

  • onTapCancel— 当触发的事件onTapDown不是点击时触发


点击手势的可能应用包括:


  1. 选择

  2. 取消

  3. 提交

双击

用户快速连续两次在同一位置点击屏幕。



  • onDoubleTapDown — 当用户接触屏幕时触发,可能是双击

  • onDoubleTap — 当用户快速连续两次点击同一位置的屏幕时触发

  • onDoubleTapCancel— 当触发的事件onDoubleTapDown不是双击时触发


双击手势的可能应用包括:


  1. 喜欢不喜欢

  2. 屏幕开/关

  3. 调整图像大小

长按

用户在同一位置长时间接触屏幕。



  • onLongPressDown — 当用户接触屏幕时触发,可能是长按

  • onLongPressStart — 检测到长按开始时触发

  • onLongPress — 检测到长按时触发

  • onLongPressMoveUpdate - 当检测到长按并且用户拖动手指时触发

  • onLongPressEnd — 检测到长按结束时触发

  • onLongPressUp— 检测到长按结束时触发;长按后联系人已删除

  • onLongPressCancel— 当触发的事件onLongPressDown不是长按时触发


长按手势的可能应用包括:


  1. 显示更多选项

  2. 移动图标

捏拉

用户捏住或展开屏幕。




  • onScaleStart — 当与屏幕接触已建立焦点且初始比例为 1.0 时触发

  • onScaleUpdate — 当与屏幕的接触指示新的焦点和/或比例时触发

  • onScaleEnd— 当用户不再接触screenPossible缩放手势的应用程序时触发


缩放手势的用途包括:


  1. 放大/缩小

  2. 回转

垂直拖动

用户接触屏幕并以稳定的方式垂直移动指尖。



  • onVerticalDragDown — 当用户接触屏幕时触发,可能会垂直移动

  • onVerticalDragStart — 当用户接触屏幕并开始垂直移动时触发

  • onVerticalDragUpdate — 当垂直移动的接触再次沿垂直方向移动时触发

  • onVerticalDragEnd — 在检测到垂直拖动结束时触发

  • onVerticalDragCancel— 当触发的事件onVerticalDragDown不是垂直拖动时触发


垂直拖动手势的可能应用包括:


  1. 滚动

水平拖动

用户接触屏幕并以稳定的方式水平移动指尖。



  • onHorizontalDragDown — 当用户接触屏幕时触发,可能会水平移动

  • onHorizontalDragStart — 当用户接触屏幕并开始水平移动时触发

  • onHorizontalDragUpdate — 当水平移动的接触再次在水平方向移动时触发

  • onHorizontalDragEnd — 当检测到水平拖动结束时触发

  • onHorizontalDragCancel— 当触发的事件onHorizontalDragDown不是水平拖动时触发


水平拖动手势的可能应用包括:


  1. 删除

  2. Archive

  3. 导航到不同的页面


这不是检测到的手势的完整列表。查看官方文档以获取完整列表。


好的,上面介绍了手势相关的使用场景等,接下来


让我们试试吧!

入门

要使用GestureDetector小部件:


  1. GestureDetector小部件包装所需的小部件。

  2. 为您希望检测的手势传递回调。

  3. 相应地更新应用程序


我们将构建一个简单的演示应用程序来处理单击、双击、长按和缩放手势。

创建一个新的 Flutter 应用

创建一个新的 Flutter 应用程序并清除文件中的默认代码。main.dart

更新用户界面

我们将创建下面的四个文件。您可以在此处查看文件夹结构

main.dart

import 'package:flutter/material.dart';import 'presentation/my_app_widget.dart';void main() {  runApp(const MyApp());}
复制代码

my_app_widget.dart

import 'package:flutter/material.dart';import 'home_page.dart';class MyApp extends StatelessWidget {  const MyApp({Key? key}) : super(key: key);  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Flutter Gesture Detector Demo',      theme: ThemeData(        primarySwatch: Colors.blue,      ),      home:  const HomePage(),    );  }}
复制代码

home_page.dart

import 'package:flutter/material.dart';import 'widgets/widgets.dart';class HomePage extends StatelessWidget {  const HomePage({Key? key}) : super(key: key);  @override  Widget build(BuildContext context) {    final height = MediaQuery.of(context).size.height;    final width = MediaQuery.of(context).size.width;    return Scaffold(      body: Padding(        padding: EdgeInsets.symmetric(            horizontal: width * 0.1, vertical: height * 0.2),        child: Column(          mainAxisAlignment: MainAxisAlignment.spaceBetween,          children:  const [            MyCardWidget(),            MyFavoriteIconWidget()          ],        ),      ),    );  }}
复制代码

my_card_widget.dart

import 'dart:math';import 'package:flutter/material.dart';class MyCardWidget extends StatefulWidget {  const MyCardWidget({    Key? key,  }) : super(key: key);  @override  State<MyCardWidget> createState() => _MyCardWidgetState();}class _MyCardWidgetState extends State<MyCardWidget> {  @override  Widget build(BuildContext context) {    return const Card(      child: SizedBox(        height: 300,        width: 300,      ),      color: Colors.yellow,    );  }}
复制代码

my_favorite_icon_widget.dart

import 'package:flutter/material.dart';class MyFavoriteIconWidget extends StatefulWidget {  const MyFavoriteIconWidget({    Key? key,  }) : super(key: key);
@override State<MyFavoriteIconWidget> createState() => _MyFavoriteIconWidgetState();}
class _MyFavoriteIconWidgetState extends State<MyFavoriteIconWidget> { @override Widget build(BuildContext context) { return const Icon( Icons.favorite_border, size: 40, ); }}
复制代码


您的最终应用程序应如下所示:



现在我们已经准备好了 UI,让我们处理一些手势。

处理点击手势

在您的文件中:my_favorite_icon_widget.dart


  1. 将选定的标志属性添加到 StatefulWidgetbool isSelected = false;

  2. IconGestureDetector小部件包裹小部件

  3. onTap属性提供非空回调

  4. 根据 flag 属性值改变图标和图标颜色


class _MyFavoriteIconWidgetState extends State<MyFavoriteIconWidget> {  bool isSelected = false;
@override Widget build(BuildContext context) { return GestureDetector( onTap: (){ setState(() { isSelected = !isSelected; }); }, child: Icon( isSelected ? Icons.favorite: Icons.favorite_border, size: 40, color: isSelected? Colors.red: Colors.black , )); }}
复制代码

处理双击手势

在您的文件中:my_card_widget.dart


  1. 添加颜色属性

  2. Card小部件包装小GestureDetector部件

  3. onDoubleTap属性提供非空回调

  4. 根据颜色属性的值改变卡片的颜色


class _MyCardWidgetState extends State<MyCardWidget> {  Color bgColor = Colors.yellow;  @override  Widget build(BuildContext context) {    return GestureDetector(      onDoubleTap: (){        setState(() {          bgColor = Colors.primaries[Random().nextInt(Colors.primaries.length)];        });      },      child:   Card(        child: const SizedBox(          height: 300,          width: 300,        ),        color: bgColor,      ),    );  }}
复制代码

处理长按手势

在您的文件: 1.添加标记属性 2.提供一个非空回调的财产 基础上的价值 3.更改卡的形状属性my_card_widget.dartmakeCircularonLongPressmakeCircular


class _MyCardWidgetState extends State<MyCardWidget> {  Color bgColor = Colors.yellow;  bool makeCircular = false;  @override  Widget build(BuildContext context) {    return GestureDetector(      onLongPress: (){        setState(() {          makeCircular = !makeCircular;        });      },      child:   Card(        shape: makeCircular? const CircleBorder(): const RoundedRectangleBorder(),        child: const SizedBox(          height: 300,          width: 300,        ),        color: bgColor,      ),    );  }}
复制代码

处理缩放手势

在您的文件中: 1. 添加一个属性 2. 添加一个属性 3. 为该属性提供一个非空回调——建立一个初始比例 4.为该属性提供一个非空回调——建立一个新的比例 5. 提供一个属性的非空回调— 返回初始比例 6.用小部件包裹小部件 7. 根据my_card_widget.dart_scaleFactor_baseFactoronScaleStartonScaleUpdateonScaleEndCard``Transorm.scale_scaleFactor


class _MyCardWidgetState extends State<MyCardWidget> {  Color bgColor = Colors.yellow;  bool makeCircular = false;  double _scaleFactor = 0.5;  double _baseScaleFactor = 0.5;  @override  Widget build(BuildContext context) {    return GestureDetector(      onScaleStart: (details){        _baseScaleFactor = _scaleFactor;      },      onScaleUpdate: (details){        setState(() {          _scaleFactor = _baseScaleFactor * details.scale;        });      },      onScaleEnd: (details){        // return to initial scale        _scaleFactor = _baseScaleFactor;      },      child:   Transform.scale(        scale: _scaleFactor,        child: Card(          shape: makeCircular? const CircleBorder(): const RoundedRectangleBorde(),          child: const SizedBox(            height: 300,            width: 300,          ),        color: bgColor,      ),    );  }}
复制代码


<img src="https://luckly007.oss-cn-beijing.aliyuncs.com/images/1.jpg" alt="1" style="zoom:25%;" />


<img src="https://luckly007.oss-cn-beijing.aliyuncs.com/images/2.jpg" alt="2" style="zoom:25%;" />

手势消歧

那么当我们onGestureDown为单击和双击提供 事件回调,并且发生两个延迟的、短暂的触摸事件时会发生什么?


考虑下图:



当识别出两个或多个具有非空回调的手势事件时,Flutter 通过让每个识别器加入手势领域来消除用户想要的手势的歧义。在手势竞技场中, “战斗” 事件和获胜事件生效,而失败事件被取消。


手势领域考虑了以下因素:


  1. 用户触摸屏幕的时间长度

  2. 每个方向移动的像素数

  3. 哪个手势在竞技场

  4. 哪个手势宣告胜利


这些是竞争状态:


  • 也许——也许是手势

  • 保持——如果它以特定的方式发展,可能是一种姿态;对于我们的案例,如果第二次点击发生在预期时间内,则发生了一次点击并且可能是两次点击

  • 是——获得优先

  • 取消——退出竞争


例如,假设发生以下情况:


1.onTapDownonDoubleTapDown被触发


2 两个手势竞争 3.单击手势获胜并执行onTap回调(回调)


4.单击手势失败并取消(onDoubleTapCancel触发)


对于我们的案例,点击手势竞争是因为:


  • 两次敲击之间的持续时间被延迟

  • 点击手势以“是”宣布胜利

  • 点击手势是取消双击后剩下的手势,没有其他竞争对手

结论

我们已经浏览了GestureDetector小部件并了解了它的工作原理。我们已经学会了如何使用它为我们的应用程序添加交互性,并且我们已经实现了一些常见的手势,比如点击、长按、双击和缩放。我们最后还研究了手势消歧。


有了这些知识,我们现在对GestureDetector小部件有了更好的理解,并且可以轻松地使用它的任何属性来识别手势。随意玩弄不同的手势。您可以在 GitHub 上找到演示应用程序

发布于: 5 小时前阅读数: 6
用户头像

坚果前端

关注

此间若无火炬,我便是唯一的光 2020.10.25 加入

公众号:“坚果前端”,51CTO博客首席体验官,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。

评论

发布
暂无评论
Flutter 中的手势【Flutter 专题10】