美文网首页
Flutter 事件与布局 demo

Flutter 事件与布局 demo

作者: 一只笔 | 来源:发表于2021-09-05 20:44 被阅读0次

点击点事

按钮的点击事件,只需要设置 onPressed 参数就可以了:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

// 设置主题
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Title'),
        ),
        body: HomeContent(),
      ),
      theme: ThemeData(primarySwatch: Colors.yellow),
    );
  }
}

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text('click'),
      onPressed: () => debugPrint('打印点击'),
    );
  }
}

任意控件的手势事件

跟 button 不同,大多数的控件没有手势事件监听函数可以设置,为了监听这些控件上的手势事件,我们需要使用另一个控件——GestureDetector(没错,它也是一个控件):

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Text(
        '你好 Flutter ',
        style: TextStyle(
          fontSize: 40.0,
          color: Colors.blue,
        ),
      ),
      onTap: () => debugPrint('onTap'), // 点击动作
      onTapDown: (e) => debugPrint('onTapDown'),//按下
      onTapUp: (e) => debugPrint('onTapUp'),
      onTapCancel: () => debugPrint('onTapCancel'),
      onDoubleTap: () => debugPrint('onDoubleTap'),
      onLongPress: () => debugPrint('onLongPress'),
    );
  }
}

onTapDown:按下
onTap:点击动作
onTapUp:抬起
onTapCancel:前面触发了 onTapDown,但并没有完成一个 onTap 动作
onDoubleTap:双击
onLongPress:长按
onScaleStart, onScaleUpdate, onScaleEnd:缩放
onVerticalDragDown, onVerticalDragStart, onVerticalDragUpdate, onVerticalDragEnd, onVerticalDragCancel, onVerticalDragUpdate:在竖直方向上移动
onHorizontalDragDown, onHorizontalDragStart, onHorizontalDragUpdate, onHorizontalDragEnd, onHorizontalDragCancel, onHorizontalDragUpdate:在水平方向上移动
onPanDown, onPanStart, onPanUpdate, onPanEnd, onPanCancel:拖曳(水平、竖直方向上移动)
如果同时设置了 onVerticalXXX 和 onHorizontalXXX,在一个手势里,只有一个会触发(如果用户首先在水平方向移动,则整个过程只触发 onHorizontalUpdate;竖直方向的类似)
这里要说明的是,onVerticalXXX/onHorizontalXXX 和 onPanXXX 不能同时设置。如果同时需要水平、竖直方向的移动,使用 onPanXXX。
如果读者希望在用户点击的时候能够有个水波纹效果,可以使用 InkWell,它的用法跟 GestureDetector 类似,只是少了拖动相关的手势(毕竟,这个水波纹效果只有在点击的时候才有意义)

原始手势事件监听

GestureDetector 在绝大部分时候都能够满足我们的需求,如果真的满足不了,我们还可以使用最原始的 Listener 控件。

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Listener(
      child: Text('text'),
      onPointerDown: (event) => print('onPointerDown'),
      onPointerUp: (event) => print('onPointerUp'),
      onPointerMove: (event) => print('onPointerMove'),
      onPointerCancel: (event) => print('onPointerCancel'),
    );
  }
}

stack 结合 align 使用

image.png
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Container(
      height: 400,
      width: 300,
      color: Colors.blue,
      child: Stack(
        children: [
          Align(
            alignment: Alignment.topLeft,
            child: Icon(
              Icons.ac_unit_outlined,
              color: Colors.white,
            ),
          ),
          Align(
            alignment: Alignment.center,
            child: Icon(
              Icons.home,
              color: Colors.white,
            ),
          ),
          Align(
            alignment: Alignment.bottomRight,
            child: Icon(
              Icons.accessibility_new_sharp,
              color: Colors.white,
            ),
          ),
        ],
      ),
    ));
  }
}

stack 结合 Positioned 使用

image.png
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Container(
      height: 400,
      width: 300,
      color: Colors.blue,
      child: Stack(
        children: [
          Positioned(
            top: 10,
            left: 10,
            child: Icon(
              Icons.ac_unit_outlined,
              color: Colors.white,
            ),
          ),
          Positioned(
            right: 10,
            top: 10,
            child: Icon(
              Icons.home,
              color: Colors.white,
            ),
          ),
          Positioned(
            bottom: 10,
            left: 10,
            child: Icon(
              Icons.accessibility_new_sharp,
              color: Colors.white,
            ),
          ),
        ],
      ),
    ));
  }
}

Wrap 组件的使用

实现流式布局

image.png
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 500,
      color: Colors.pink,
      child: Wrap(
        direction: Axis.horizontal, //控制方向
        spacing: 10, // 子节点间距
        runSpacing: 10, // 行间距
        runAlignment: WrapAlignment.end, // 显示在 Container 底部
        children: [
          MyButton("第一季,11111"),
          MyButton("第二季"),
          MyButton("第三季"),
          MyButton("第四季"),
          MyButton("第五季"),
          MyButton("第六季"),
          MyButton("第七季,22222222"),
          MyButton("第八季"),
          MyButton("第九季"),
          MyButton("第十季"),
        ],
      ),
    );
  }
}

// 自定义 button
class MyButton extends StatelessWidget {
  final String text;

  const MyButton(this.text, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
        textColor: Colors.blue,
        child: Text(this.text),
        onPressed: () {
          debugPrint(this.text);
        });
  }
}

StatefulWidget 组件的使用

改变 Widget 状态


device-2021-09-25-170505.gif
// 有状态组件
class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return HomePageState();
  }
}

class HomePageState extends State<HomePage> {
  int number = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(height: 10),
        Chip(label: Text("${this.number}")),
        RaisedButton( // 数量增加点击
          onPressed: () {
            setState(() { // 只有有状态组件里才有
              this.number += 50;
            });
            print("数量:${this.number}");
          },
          child: Text("按钮"),
        ),
        SizedBox(height: 10),
        RaisedButton( // 归零点击
          onPressed: () {
            setState(() {
              this.number = 0;
            });
            print("数量:${this.number}");
          },
          child: Text("清楚"),
        ),
      ],
    );
  }
}

StatefulWidget 组件的使用2

配合 list 的使用


device-2021-09-25-221823.gif
class HomePageState extends State<HomePage> {
  List list = new List();
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        RaisedButton(
          // 数量增加点击
          onPressed: () {
            setState(() {
              count++;
              this.list.add("条目-${this.count}");
            });
          },
          child: Text(" 添加条目"),
        ),
        RaisedButton(
          // 数量增加点击
          onPressed: () {
            setState(() {
              count=0;
              this.list.clear();
            });
          },
          child: Text(" 清楚条目"),
        ),
        Column(
          children: this.list.map((value) {
            return ListTile(title: Text(value));
          }).toList(),
        ),
      ],
    );
  }
}

BottomNavigationBar 组件的使用

被击底部 Tab 切换功能

device-2021-09-26-001713.gif
// 有状态组件
class Tabs extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TabsState();
  }
}

class TabsState extends State<Tabs> {
  int _currentIndex = 0;
  List _pageList = [HomePage(), CategoryPage(), SettingPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('FlutterDemo_Tab')),
        body: this._pageList[this._currentIndex],
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: this._currentIndex, // 设置索引值
          onTap: (int index) { // 点击 tab 回调
            setState(() {
              this._currentIndex = index;
            });
          },
          iconSize: 30.0, // 图标大小
          fixedColor: Colors.green, // 选中的颜色
          type: BottomNavigationBarType.fixed, // 布局类型
          items: [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: ("首页")),
            BottomNavigationBarItem(icon: Icon(Icons.category), label: ("分类")),
            BottomNavigationBarItem(icon: Icon(Icons.settings), label: ("设置")),
          ],
        ));
  }
}

普通路由

打开一个页面

     Navigator.of(context).push(MaterialPageRoute(
                builder: (context) => FormPage(
                      title: "传递参数",
                    )));

关闭页面

      Navigator.of(context).pop();

自定义路由

实现 routers 指定页面与自定义 路由地址的对应关系。

    @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter UX demo',
      home: Tabs(),
      routes: {
        '/SearchPage': (context) => SearchPage(),
      },
    );
  }

通过 Navigator.pushNamed() 传入自定义的路由名称

       Navigator.pushNamed(context, '/SearchPage');

自定义路由传参

实现 onGenerateRoute

class MyApp extends StatelessWidget {
  // 路由配置表
  final routes = {
    '/SearchPage': (context, {arguments}) => SearchPage(arguments: arguments),
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter UX demo',
      home: Tabs(),
      onGenerateRoute: (RouteSettings settings) {  // 自定义路由传参的实现
        // 统一处理
        final name = settings.name;
        final Function pageContentBuilder = this.routes[name];
        if (pageContentBuilder != null && settings.arguments != null) {
          final Route route = MaterialPageRoute(
              builder: (context) => pageContentBuilder(context, arguments: settings.arguments));
          return route;
        } else {
          final Route route = MaterialPageRoute(
              builder: (context) => pageContentBuilder(context));
          return route;
        }
      },
    );
  }
}

打开带参数的路由

      Navigator.pushNamed(context, '/SearchPage',
                    arguments: {"id": 124});

接收参数的页面

class SearchPage extends StatelessWidget {
  final arguments;
  const SearchPage({this.arguments});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('搜索页面 ${arguments != null ? arguments['id'] : "0"}'),
          // title: Text('搜索页面 ${this.arguments}'),
        ),
        body: HomeContent(),
      ),
      theme: ThemeData(primarySwatch: Colors.yellow),
    );
  }
}

相关文章

网友评论

      本文标题:Flutter 事件与布局 demo

      本文链接:https://www.haomeiwen.com/subject/csagvltx.html