Flutter基础——ViewControllers、手势与触摸事件

Posted by lingjye on July 18, 2019

ViewControllers

在 Flutter 中,使用Widgets代替ViewControllers来管理用户界面。使用 Navigator 在 Route 之间跳转,或者渲染相同数据的不同状态。

可以通过hook WidgetsBinding观察者来监听生命周期事件。并监听didChangeAppLifecycleState()的变化事件。

可观察的生命周期事件有:

  • inactive — 应用处于不活跃的状态,并且不会接受用户的输入。(仅用于iOS,安卓端没有等价事件);
  • paused - 应用暂时对用户不可见,虽然不接受用户输入,但是是在后台运行的;
  • resumed - 应用可见,也响应用户的输入;
  • suspending - 应用暂时被挂起,在iOS上没有这一事件。

这些状态的更多细节和含义,可以查看AppLifecycleStatus documentation;

手势与触摸事件

在Flutter中有两种方法来添加点击监听者:

  1. 如果widget本身支持事件监测,直接传递给它一个函数,并在这个函数里实现响应方法。例如:RaisedButton Widget拥有一个RaisedButton参数:
1
2
3
4
5
6
7
8
9
@override
Widget build(BuildContext context) {
  return RaisedButton(
    onPressed: () {
      print("click");
    },
    child: Text("Button"),
  );
}
  1. 如果本身不支持事件监测,则在外面包裹一个GestureDetector,并给他的onTap属性传递一个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class GestureSampleAppGesturePage extends StatelessWidget {
  const GestureSampleAppGesturePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('手势与触摸事件'),
      ),
      body: Center(
        child: GestureDetector(
          child: FlutterLogo(
            size: 200.0,
          ),
          onTap: () {
            print("tap");
          },
        ),
      )
    );
  }
}

处理其他手势

使用GestureDetector还可以监听其他手势,比如:

  • Tapping
    • onTapDown — 在特定位置轻触手势接触了屏幕。
    • onTapUp — 在特定位置产生了一个轻触手势,并停止接触屏幕。
    • onTap — 产生了一个轻触手势。
    • onTapCancel — 触发了 onTapDown 但没能触发 tap。
  • Double tapping
    • onDoubleTap — 用户在同一个位置快速点击了两下屏幕。
  • Long pressing
    • onLongPress — 用户在同一个位置长时间接触屏幕。
  • Vertical dragging
    • onVerticalDragStart — 接触了屏幕,并且可能会垂直移动。
    • onVerticalDragUpdate — 接触了屏幕,并继续在垂直方向移动。
    • onVerticalDragEnd — 之前接触了屏幕并垂直移动,并在停止接触屏幕前以某个垂直的速度移动。
  • Horizontal dragging
    • onHorizontalDragStart — 接触了屏幕,并且可能会水平移动。
    • onHorizontalDragUpdate — 接触了屏幕,并继续在水平方向移动。
    • onHorizontalDragEnd — 之前接触屏幕并水平移动的触摸点与屏幕分离。

双击手势示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
class GestureSampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text',
      theme: ThemeData(
        primaryColor: Colors.blue
      ),
      // home: GestureSampleAppGesturePage(),
      // home: GestureSampleAppButtonPage(),
      home: DoubleTapAnimation(),
    );
  }
}

// 本身包含事件监测
class GestureSampleAppButtonPage extends StatelessWidget {
  const GestureSampleAppButtonPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('手势与触摸事件'),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: (){
            print('click');
          },
          child: Text('Button'),
          color: Colors.red,
        ),
      )
    );
  }
}

// 不包含事件监测
class GestureSampleAppGesturePage extends StatelessWidget {
  const GestureSampleAppGesturePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('手势与触摸事件'),
      ),
      body: Center(
        child: GestureDetector(
          child: FlutterLogo(
            size: 200.0,
          ),
          onTap: () {
            print("tap");
          },
        ),
      )
    );
  }
}

// 双击旋转图标,结合动画
class DoubleTapAnimation extends StatefulWidget {
  DoubleTapAnimation({Key key}) : super(key: key);

  _DoubleTapAnimationState createState() => _DoubleTapAnimationState();
}

class _DoubleTapAnimationState extends State<DoubleTapAnimation> with TickerProviderStateMixin {

  AnimationController controller;
  CurvedAnimation curve;

  @override
  void initState() {
    controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
    curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Double Tap'),
      ),
      body: Center(
        child: GestureDetector(
          child: RotationTransition(
            child: FlutterLogo(
              size: 200,
            ),
            turns: curve,
          ),
          
          onDoubleTap: () {
            if (controller.isCompleted) {
              controller.reverse();
            } else {
              controller.forward();
            }
            print('double tap');
          },
        ),
      ),
    );
  }
}

本文Demo