【Flutter — 进阶】交互

  • Post author:
  • Post category:其他


在这里插入图片描述



1. 自带交互的控件

在 Flutter 中,自带如点击事件的控件有

RaisedButton、IconButton、OutlineButton、Checkbox、SnackBar、Switch

等,如下面给

OutlineButton

添加点击事件:

         body:Center(
           child: OutlineButton(
               child: Text('点击我'),
               onPressed: (){
                 Fluttertoast.showToast(
                   msg: '你点击了FlatButton',
                   toastLength: Toast.LENGTH_SHORT,
                   gravity: ToastGravity.CENTER,
                   timeInSecForIos: 1,
                 );
               }),
         ),



2. 不自带交互的控件

很多控件不像

RaisedButton、OutlineButton

等已经对

presses(taps)

或手势做出了响应。那么如果要监听这些控件的手势就需要用另一个控件

GestureDetector

,那看看源码

GestureDetector

支持哪些手势:

  GestureDetector({
    Key key,
    this.child,
    this.onTapDown,//按下,每次和屏幕交互都会调用
    this.onTapUp,//抬起,停止触摸时调用
    this.onTap,//点击,短暂触摸屏幕时调用
    this.onTapCancel,//取消 触发了onTapDown,但没有完成onTap
    this.onDoubleTap,//双击,短时间内触摸屏幕两次
    this.onLongPress,//长按,触摸时间超过500ms触发
    this.onLongPressUp,//长按松开
    this.onVerticalDragDown,//触摸点开始和屏幕交互,同时竖直拖动按下
    this.onVerticalDragStart,//触摸点开始在竖直方向拖动开始
    this.onVerticalDragUpdate,//触摸点每次位置改变时,竖直拖动更新
    this.onVerticalDragEnd,//竖直拖动结束
    this.onVerticalDragCancel,//竖直拖动取消
    this.onHorizontalDragDown,//触摸点开始跟屏幕交互,并水平拖动
    this.onHorizontalDragStart,//水平拖动开始,触摸点开始在水平方向移动
    this.onHorizontalDragUpdate,//水平拖动更新,触摸点更新
    this.onHorizontalDragEnd,//水平拖动结束触发
    this.onHorizontalDragCancel,//水平拖动取消 onHorizontalDragDown没有成功触发
    //onPan可以取代onVerticalDrag或者onHorizontalDrag,三者不能并存
    this.onPanDown,//触摸点开始跟屏幕交互时触发
    this.onPanStart,//触摸点开始移动时触发
    this.onPanUpdate,//屏幕上的触摸点位置每次改变时,都会触发这个回调
    this.onPanEnd,//pan操作完成时触发
    this.onPanCancel,//pan操作取消
    //onScale可以取代onVerticalDrag或者onHorizontalDrag,三者不能并存,不能与onPan并存
    this.onScaleStart,//触摸点开始跟屏幕交互时触发,同时会建立一个焦点为1.0
    this.onScaleUpdate,//跟屏幕交互时触发,同时会标示一个新的焦点
    this.onScaleEnd,//触摸点不再跟屏幕交互,标示这个scale手势完成
    this.behavior,
    this.excludeFromSemantics = false
  })



2.1 onTapXXX

           child: GestureDetector(
             child: Container(
               width: 300.0,
               height: 300.0,
               color:Colors.red,
             ),
             onTapDown: (d){
               print("onTapDown");
             },
             onTapUp: (d){
               print("onTapUp");
             },
             onTap:(){
               print("onTap");
             },
             onTapCancel: (){
               print("onTaoCancel");
             },
           )

输出结果是:

I/flutter (16304): onTapDown

I/flutter (16304): onTapUp

I/flutter(16304): onTap

先触发onTapDown 然后onTapUp 继续onTap



2.2 onLongXXX

    //手势测试
    Widget gestureTest = GestureDetector(
          child: Container(
            width: 300.0,
            height: 300.0,
            color:Colors.red,
          ),
           onDoubleTap: (){
              print("双击onDoubleTap");
           },
           onLongPress: (){
              print("长按onLongPress");
           },
           onLongPressUp: (){
              print("长按抬起onLongPressUP");
           },

    );

输出结果:

I/flutter (16304): 长按onLongPress

I/flutter (16304): 长按抬起onLongPressUP

I/flutter (16304): 双击onDoubleTap



2.3 onVerticalXXX

    //手势测试
    Widget gestureTest = GestureDetector(
          child: Container(
            width: 300.0,
            height: 300.0,
            color:Colors.red,
          ),
            onVerticalDragDown: (_){
               print("竖直方向拖动按下onVerticalDragDown:"+_.globalPosition.toString());
            },
            onVerticalDragStart: (_){
               print("竖直方向拖动开始onVerticalDragStart"+_.globalPosition.toString());
            },
            onVerticalDragUpdate: (_){
               print("竖直方向拖动更新onVerticalDragUpdate"+_.globalPosition.toString());
            },
            onVerticalDragCancel: (){
               print("竖直方向拖动取消onVerticalDragCancel");
            },
            onVerticalDragEnd: (_){
               print("竖直方向拖动结束onVerticalDragEnd");
            },

    );

输出结果:

I/flutter (16304): 竖直方向拖动按下onVerticalDragDown:Offset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动开始onVerticalDragStartOffset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.7, 289.3)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.3, 290.0)

I/flutter (16304): 竖直方向拖动更新onVerticalDragUpdateOffset(191.3, 291.3)

I/flutter (16304): 竖直方向拖动结束onVerticalDragEnd



2.4 onPanXXX

    //手势测试
    Widget gestureTest = GestureDetector(
          child: Container(
            width: 300.0,
            height: 300.0,
            color:Colors.red,
          ),
             onPanDown: (_){
                 print("onPanDown");
             },
             onPanStart: (_){
                 print("onPanStart");
             },
             onPanUpdate: (_){
                 print("onPanUpdate");
             },
             onPanCancel: (){
                 print("onPanCancel");
             },
             onPanEnd: (_){
                 print("onPanEnd");
             },

    );

输出结果:

I/flutter (16304): onPanDown

I/flutter (16304): onPanStart

I/flutter (16304): onPanUpdate

I/flutter (16304): onPanUpdate

I/flutter (16304): onPanEnd



2.5 onScaleXXX

    //手势测试
    Widget gestureTest = GestureDetector(
          child: Container(
            width: 300.0,
            height: 300.0,
            color:Colors.red,
          ),
           onScaleStart: (_){
                 print("onScaleStart");
          },
          onScaleUpdate: (_){
                print("onScaleUpdate");
               },
          onScaleEnd: (_){
               print("onScaleEnd");

    );

输出结果:

I/flutter (16304): onScaleStart

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleUpdate

I/flutter (16304): onScaleEnd



3. 原始指针事件

除了 GestureDetector 能够监听触摸事件外,Pointer 代表用户与设备屏幕交互的原始数据,也就是也能监听手势:


  • PointerDownEvent

    :指针接触到屏幕的特定位置

  • PointerMoveEvent

    :指针从屏幕上的一个位置移动到另一个位置

  • PointMoveEvent

    :指针停止接触屏幕

  • PointUpEvent

    :指针停止接触屏幕

  • PointerCancelEvent

    :指针的输入事件不再针对此应用
    //Pointer
    Widget TestContainer = Listener(
      child:Container(
        width: 300.0,
        height: 300.0,
        color:Colors.red,
    ),
      onPointerDown: (event){
        print("onPointerDown");
      },
      onPointerUp: (event){
        print("onPointerUp");
      },
      onPointerMove: (event){
        print("onPointerMove");
      },
      onPointerCancel: (event){
        print("onPointerCancel");
      },

    );

输出结果:

I/flutter (16304): onPointerDown

I/flutter (16304): onPointerMovee

I/flutter (16304): onPointerMove

I/flutter (16304): onPointerMoves

I/flutter (16304): onPointerMove

I/flutter (16304): onPointerUp



4. 路由(页面)跳转

在 Android 原生中,页面跳转是通过

startActvity()

来跳转不同页面,而在Flutter就不一样。Flutter中,跳转页面有两种方式:静态路由方式和动态路由方式。在Flutter管理多个页面有两个核心概念和类:

Route



Navigator

。一个

route

是一个屏幕或者页面的抽象,

Navigator

是管理

route

的Widget。

Navigator

可以通过

route

入栈和出栈来实现页面之间的跳转。



4.1 静态路由


  • 配置路由


    在原页面配置路由跳转,就是在MaterialApp里设置每个route对应的页面,注意:一个app只能有一个材料设计(MaterialApp),不然返回上一个页面会黑屏。代码如下:
//入口页面
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //静态路由方式 配置初始路由
      initialRoute: '/',
      routes: {
        //默认走这个条件`/`
        '/':(context){
          return HomeStateful();
        },
        //新页面路由
        '/mainnewroute':(context){
          return new newRoute();
        }
      },
      //主题色
      theme: ThemeData(
        //设置为红色
          primarySwatch: Colors.red),
      //配置了初始路由,下面就不需要了
      //home: HomeStateful(),
    );
  }
}

  • 点击跳转
//如果新页面不在同一个类中,记得把它导入
import 'mainnewroute.dart';
class HomeStateful extends StatefulWidget{
  @override
  State<StatefulWidget> createState(){
    return new HomeWidget();
  }

}

class HomeWidget extends State<HomeStateful> {
    @override
  Widget build(BuildContext context) {
   ...
       //Pointer
    Widget TestContainer = Listener(
      child:Container(
        width: 300.0,
        height: 300.0,
        color:Colors.red,
        child: RaisedButton(
            child: Text('点击我'),
            onPressed: (){
              //页面跳转方法
              Navigator.of(context).pushNamed('/mainnewroute');
            }),
    ),
   );
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('Flutter Demo'),
        ),
         body:Center(
           child: TestContainer,
         ),
      );
 }
}

  • 配置新页面


    新页面,我在 lib 下建立一个新的文件(页面)

    mainfourday.dart

    ,很简单:
import 'package:flutter/material.dart';
class newRoute extends StatelessWidget{

  @override
  Widget build(BuildContext context){
    return HomeWidget();
    //注意:不需要MaterialApp
//    return MaterialApp(
//      theme: ThemeData(
//        //设置为hongse
//          primarySwatch: Colors.red),
//      home: HomeWidget(),
//      );

  }
}

class HomeWidget extends StatelessWidget{

  @override
  Widget build(BuildContext context){
     return Scaffold(
       appBar: AppBar(
         title: Text('new Route'),
       ),
       body: Center(
         child:RaisedButton(
           child: Text('返回'),
             onPressed: (){
               //这是关闭页面
               Navigator.pop(context);
             }),
        // child: Text('这是新的页面'),
       ),
     );
  }
}

  • 效果图


    在这里插入图片描述



4.2 动态路由

下面说一下跳转页面的第二种方式,动态路由方式:

        child: RaisedButton(
            child: Text('点击我'),
            onPressed: (){
              //Navigator.of(context).pushNamed('/mainnewroute');
              //动态路由
              Navigator.push(
                context,
                MaterialPageRoute(builder: (newPage){
                  return new newRoute();
                }),
              );
            }),

效果和上面是一样的。



4.3 页面传递数据

两种方式都是传递参数的,直接上动态路由传递数据代码:

              Navigator.push(
                context,
                MaterialPageRoute(builder: (newPage){
                  return new newRoute("这是一份数据到新页面");
                }),
              );

在新页面改为如下:


import 'package:flutter/material.dart';
class newRoute extends StatelessWidget{
  //接收上一个页面传递的数据
  String str;
  //构造函数
  newRoute(this.str);

  @override
  Widget build(BuildContext context){
    return HomeWidget(str);
  }
}

class HomeWidget extends StatelessWidget{
  String newDate;
  HomeWidget(this.newDate);

  @override
  Widget build(BuildContext context){
     return Scaffold(
       appBar: AppBar(
         title: Text('new Route'),
       ),
       body: Center(
         child:RaisedButton(
           //显示上一个页面所传递的数据
           child: Text(newDate),
             onPressed: (){
               Navigator.pop(context);
             }),
        // child: Text('这是新的页面'),
       ),
     );
  }
}

静态路由方式传递参数,也就是在newRoute()加上所要传递的参数就可以了

        //新页面路由
        '/mainnewroute':(context){
          return new newRoute("sdsd");
        }



4.4 页面返回数据

传递数据给新页面可以了,那么怎样将新页面数据返回上一个页面呢?也是很简单,在返回方法pop加上所要返回的数据即可:

       body: Center(
         child:RaisedButton(
           //显示上一个页面所传递的数据
           child: Text(newDate),
             onPressed: (){
               Navigator.pop(context,"这是新页面返回的数据");
             }),
        // child: Text('这是新的页面'),
       ),

因为打开页面是异步的,所以页面的结果需要通过一个Future来返回,静态路由方式:

        child: RaisedButton(
            child: Text('点击我'),
            onPressed: () async {
              var data = await Navigator.of(context).pushNamed('/mainnewroute');
              //打印返回来的数据
              print(data);
            }),

动态路由方式:

        child: RaisedButton(
            child: Text('点击我'),
            onPressed: () async {
              var data = await Navigator.push(
                context,
                MaterialPageRoute(builder: (newPage){
                  return new newRoute("这是一份数据到新页面");
                }),
              );
              //打印返回的值
              print(data);
            }),



版权声明:本文为duoduo_11011原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。