美文网首页Android进阶之路Android开发Android开发经验谈
Flutter基础(五)Material组件之MaterialA

Flutter基础(五)Material组件之MaterialA

作者: 刘望舒 | 来源:发表于2019-08-20 01:51 被阅读13次

    本文首发于公众号「刘望舒」

    关联系列
    ReactNative入门系列
    React Native组件
    Flutter基础系列

    前言

    在上一篇文章Flutter基础(四)开发Flutter应用前需要掌握的Basics Widget,我们学习了Basics Widget,除了Basics Widget,我们还需要了解Material Components,也就是Material组件。它提供了实现Material Design准则的视觉、行为和动作的Widget。
    官方将Material组件分为为几个类型:

    • 应用程序结构和导航
    • Button
    • 输入和选择
    • 对话框,警告弹框和面板
    • 信息显示
    • 布局

    主要介绍应用程序结构和导航,会分为两篇文章进行介绍,这一篇介绍应用程序结构和导航分类中的MaterialApp、Scaffold、AppBar。

    1.MaterialApp

    说到Material组件,不得不提到MaterialApp,它包含了许多Widget,这些Widget通常是实现Material Design的应用程序所必需的。
    MaterialApp在此前的文章都用过,简单的使用这里就不介绍了,这里简单介绍下路由。
    在Android开发中我们使用Intent来进行界面跳转,也称之为原生路由,后来出现了一些路由框架,比如ARouter。
    在Flutter中进行界面跳转的就是路由,路由用Route类来进行表示,Navigator是对Route进行管理的Widget。Navigator不仅管理了一堆route,还提供管理堆栈的方法 Navigator.push 和 Navigator.pop,通过路由对象的进出栈来控制页面的跳转。

    flutter路由的使用方式主要有两种,一种是新建路由,一种是注册路由。我们分别用这两种方式写例子:
    首屏是第一个界面,通过第一个界面的按钮跳转到第二页,点击第二页的按钮回到第一页。

    1.1 新建路由

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Material Components',
          home: FirstPage(),
        );
      }
    }
    
    class FirstPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('第一页'),
          ),
          body: Padding(
            padding: EdgeInsets.all(30.0),
            child: RaisedButton(
              child:  Text('跳转到第二页'),
              onPressed: () {
                Navigator.push(//1
                  context,
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              },
            ),
          ),
        );
      }
    }
    
    class SecondPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('第二页'),
          ),
          body: Padding(
            padding: EdgeInsets.all(30.0),
            child: RaisedButton(
                child: Text('回到上一页'),
                onPressed: () {
                  Navigator.pop(context);//2
                }),
          ),
        );
      }
    }
    

    注释1处调用了Navigator.push,将新建的路由添加到Navigator管理的route堆栈的栈顶,这个路由我们可以自定义,但是建议使用MaterialPageRoute,它是一个模态路由,可以自适应各个平台进行页面替换,并提供了相应的页面切换动画。在Android平台时,页面进入动画是向上滑动并淡出,退出是相反的动画,如果是在iOS平台 ,页面进入动画是从右侧滑入,退出是相反的动画。
    点击'跳转到第二页'按钮时会跳转到SecondPage。注释2处的Navigator.pop用于弹出route堆栈最顶层的Route。效果如下两个图所示。

    image image

    1.2 注册路由

    import 'package:flutter/material.dart';
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Material Components',
          home: FirstPage(),
          routes:  <String, WidgetBuilder>{//1
            '/first': (BuildContext context) => FirstPage(),
            '/second': (BuildContext context) => SecondPage(),
          },
          initialRoute: '/first' ,
        );
      }
    }
    
    class FirstPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('第一页'),
          ),
          body: Padding(
            padding: EdgeInsets.all(30.0),
            child: RaisedButton(
              child: Text('跳转到第二页'),
              onPressed: () {
                Navigator.pushNamed(context, '/second');//2
              },
            ),
          ),
        );
      }
    }
    
    class SecondPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('第二页'),
          ),
          body: Padding(
            padding: EdgeInsets.all(30.0),
            child: RaisedButton(
                child: Text('回到上一页'),
                onPressed: () {
                  Navigator.of(context).pop();
                }),
          ),
        );
      }
    }
    

    通过注释1处的routes用于初始化一个路由列表,当推送路由时,将在routes中查找路径名称,如果名称存在,则关联的WidgetBuilder用于构造MaterialPageRoute。注释2处的Navigator.pushNamed和Navigator.push作用类似,只不过pushNamed的参数为路由的名称。

    2. Scaffold

    Scaffold同样属于Material组件,它实现了Material Design的基本布局结构,因此它经常会作为MaterialApp的子Widget, Scaffold会自动填充可用的空间,这通常意味着它将占据整个窗口或屏幕,并且Scaffold会自动适配屏幕。我们的布局就是在Scaffold中进行编写的。

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Scaffold示例'),
            ),
            body: Padding(
              padding: EdgeInsets.all(30.0),
              child: Text('Scaffold'),
            ),
            bottomNavigationBar: BottomAppBar(
              child: Container(height: 50),
            ),
            drawer: Drawer(
              child: Center(
                child: Text('抽屉'),
              ),
            ),
            floatingActionButton: FloatingActionButton(
              child: Icon(Icons.add),
            ),
          ),
        );
      }
    }
    

    Scaffold的属性有很多,例子中用了几个属性:

    • appBar:用于设置顶部的标题栏。
    • body:显示Scaffold的主要内容。
    • bottomNavigationBar:用于设置Scaffold的底部导航栏,
    • drawer:用于设置抽屉效果。
    • floatingActionButton:用于设置位于右下角的按钮。

    效果如下所示:


    image

    可以看到在AppBar上有个抽屉的按钮,点击按钮就会滑出抽屉。

    3. AppBar

    AppBar由toolbar和其他的可选Widget组成,比如TabBar和FlexibleSpaceBar。
    AppBar会在顶部显示leading、title、actions等内容,底部bottom通常显示TabBar,下图展示了这些内容的位置分布。

    image
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MyScaffld(),
        );
      }
    }
    
    class MyScaffld extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('AppBar示例'),
            leading: FlutterLogo(colors: Colors.lightGreen),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.share),
                onPressed: () {
                  print('添加按钮');
                },
              ),
            ],
          ),
        );
      }
    }
    

    这次没有把所有代码写在MyApp类中,而是将Scaffld的定义放在了MyScaffld类中。

    image

    上面代码的Widget树如下所示,遵守Material Design准则的flutter应用的Widget树大致也是如此。

    image

    总结

    本文总结了Material组件中的三种Widget,可以说它们是使用Material组件时最常使用的Widget,常用到我们可能会忽略它们。由于篇幅原因,会在下一篇介绍Material组件的其他Widget。

    Flutter基础系列
    Flutter基础(一)移动开发的跨平台技术演进
    Flutter基础(二)Flutter开发环境搭建和Hello World
    Flutter基础(三)Dart快速入门
    Flutter基础(四)开发Flutter应用前需要掌握的Basic Widget
    Flutter基础(五)Material组件之MaterialApp、Scaffold、AppBar
    Flutter基础(六)Material组件之BottomNavigationBar、TabBar、Drawer
    Flutter基础(七)Scrolling Widget之ListView、GridView、PageView
    Flutter基础(八)手势相关Widget:GestureDetector和Dismissible
    Flutter基础(九)资源和图片
    Flutter基础(十)布局Widget快速入门
    Flutter基础(十一)网络请求(Dio)与JSON数据解析
    Flutter基础(十二)路由(页面跳转)与数据传递
    Flutter基础(十三)Flutter与Android的相互通信


    <div align=center>这里不仅分享大前端、Android、Java等技术,还有程序员成长类文章。</div>
    <div align=center><img src="https://user-gold-cdn.xitu.io/2019/7/10/16bd7d4e754df569?w=234&h=231&f=jpeg&s=34771" width="260"/></div>

    相关文章

      网友评论

        本文标题:Flutter基础(五)Material组件之MaterialA

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