Flutter实战之手势基础篇

前言

平常开发应用中少不了交互功能,而交互就包括了点击触碰。好比点击一个按钮对操做作出响应又或者是拖拽列表作下拉刷新操做等一些常规交互的实现离不开手势功能。那么在Flutter中是如何实现经过手势操做实现交互操做的,下面就来介绍一下Flutter手势功能。app

手势(GestureDetector)

Flutter经过使用GestureDetector组件使得其余Widget支持手势功能。手势能够响应多种操做,主要分为如下几类:Tap、Double tap、Long press、Vertical drag、Horizontal drag、Pan。同时能够经过动做分为点击、双击、长按、拖拽、缩放等。学习

点击(Tap)& 双击(DoubleTap)& 长按(LongPress)

通用的操做方法,例如点击、双击、长按功能,只须要编写Function就能实现功能。固然在这些操做过程当中也具有中间过程的状态监听,例如点击按下时,抬起时,取消点击等。 动画

GestureDetector(
  onTap: (){
    showSnack(context, "OnTap");
  },
  onDoubleTap: (){
    showSnack(context, "onDoubleTap");
  },
  onLongPress: (){
    showSnack(context, "onLongPress");
  },
  child: Transform.translate(
    offset: offset,
    child: Text(
      "Transform",
      style: TextStyle(fontSize: 25),
    ),
  ),
);
复制代码

拖拽(Drag)

GestureDetector为拖拽功能提供水平方向拖拽(Horizontal drag)、垂直方向拖拽(Vertical drag)、同时支持两个方向拖拽(Pan)。 ui

水平和垂直两个拖拽监听只能获取对应方向偏移量变化,对应的垂直方向的数值返回始终为0,若在开发需求中若同时须要监听两个方向则推荐使用综合拖拽监听回调Pan同时监听水平和垂直方向的偏移量的变化。

在监听中Down、Start、Update三个过程能够监听到Details对象,从而知道当前手势定位值对于组件顶点位置的偏移量。spa

偏移量

在GestureDetector中两个重要属性值globalPosition和localPosition,二者都是Offset对象。globalPosition就像它的命名表示当前手势触点在全局坐标系位置与对应组件顶点坐标的偏移量(dx,dy),而localPosition则就表示当前手势触点在对应组件坐标系位置与对应组件顶点坐标的偏移量(dx,dy)也就是说若是当前手势位置在组件顶点坐标那么dx和dy都为0。指针

例如以下代码中,为Container设置了GestureDetector手势监听,在update回调中获取updateDetail对象,在Text中显示globalPosition偏移量。从中获取到的globalPosition和localPosition中dx都是相同值,dy却不一样。也就是由于Scaffold中设置了AppBar,相对于body他的全局坐标系并不是它自身。但若将Scaffold中的AppBar去除,让body撑满整个Scaffold,那么在手势监听中获取到的globalPosition和localPosition将相同。code

须要注意的是对于globalPosition在安卓中还包含了手机状态栏的高度。orm

MaterialApp(
      theme: AppTheme.themes[store.state.appThemeState.themeType],
      home: Scaffold(
        appBar: AppBar(),
        body: GestureDetector(
          onPanStart: (detail) {
            showLog(detail.runtimeType, detail.localPosition,
                detail.globalPosition);
          },
          onPanUpdate: (detail) {
            showLog(detail.runtimeType, detail.localPosition,
                detail.globalPosition);
            setState(() {
              offsetText = "globalPosition: ${Offset(detail.globalPosition.dx, detail.globalPosition.dy).toString()} \n"
                  "localPosition: ${Offset(detail.localPosition.dx, detail.localPosition.dy).toString()}";
            });
          },
          onPanEnd: (detail) {
            setState(() {
              offsetText = "end";
            });
          },
          child: Container(
            color: Colors.red,
            width: double.infinity,
            height: double.infinity,
            child: Center(
              child: Text(
                 offsetText,
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 25,
                ),
              ),
            ),
          ),
        ),
      ),
    );
复制代码

能够看到当Scaffold包含和未包含AppBar时,Container两个偏移量输出的差别。cdn

缩放(Scale)

缩放操做则须要两个指针对象配合才能发挥做用。当在屏幕上只有一个指针对象时也就是一个触点时,对应的缩放比为1和角度为0;当屏幕上出现两个指针对象时,根据两个初始位置做为基准点,也就是起始位置初始化缩放比为1和角度为0,经过手势变化得出两点的距离位置和夹角大小来计算缩放比和角度值。对象

GestureDetector(
          onScaleStart: (detail) {
            print(detail);
            setState(() {
              offsetText = "focalPoint: ${detail.focalPoint.toString()} \n"
                  "localFocalPoint: ${detail.localFocalPoint.toString()}";
            });
          },
          onScaleUpdate: (details) {
            print(details);
            Vector.Matrix3 matrix3 = Vector.Matrix3.zero();
            setState(() {
              offsetText = "focalPoint: ${details.focalPoint.toString()} \n"
                  "localFocalPoint: ${details.localFocalPoint.toString()}";
              scaleUpdateDetails = details;
            });
          },
          onScaleEnd: (details) {
            print(details);
            setState(() {
              scaleUpdateDetails = ScaleUpdateDetails();
            });
          },
          child: Container(
            color: Colors.red,
            width: double.infinity,
            height: double.infinity,
            child: Center(
                // 组件的动画效果
              child: Transform(
                transform: Matrix4.rotationZ(scaleUpdateDetails.rotation)
                    .scaled(
                        scaleUpdateDetails.scale),
                child: Text(
                  offsetText,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                  ),
                ),
              ),
            ),
          ),
        ),
复制代码

在onScaleUpdate方法中获取ScaleUpdateDetails对象,其包含了两触点实现的缩放值scale、角度值rotation、偏移量focalPoint信息。经过上述代码并可实现手势再结合上Transform的组件动效,关于Transform不作过多介绍,主要为实现组件动画效果的组件,以后如有时间再作学习。

结尾

这篇只能算是手势功能基础篇,还有一些手势高阶功能实现未探究相似于Android中的手势冲突等一些功能性自定义开发,暂且先熟悉手势基本功能以后如有对这方面开发需求再作更深层次学习和研究。

相关文章
相关标签/搜索