关于flutter:flutter系列之Material主题的基础MaterialApp

37次阅读

共计 4665 个字符,预计需要花费 12 分钟才能阅读完成。

简介

为了简化大家的应用,尽管 flutter 举荐所有的 widget 都有本人来进行搭建,然而在大框架下面,flutter 提供了 Material 和 Cupertino 两种主题格调的 Widgets 汇合,大家能够在这两种格调的继承上进行个性化定制和开发。

这两种格调翻译成中文就是:资料和库比蒂诺?什么鬼 …. 咱们还是应用默认的英文名来称说它们吧。

本文咱们将会深刻解说 Material 主题的根底 -MaterialApp。

MaterialApp 初探

如果你应用最新的 android Studio 创立一个 flutter 我的项目的话,android Studio 会主动为你创立一个基于 flutter 的应用程序。

咱们来看下主动创立的 main.dart 文件:

  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue,),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    )
  }

这个 build 办法返回的 widget 就是这个 flutter 应用程序的根 Widget。能够看到,默认状况下是返回一个 MaterialApp。

在下面的样例代码中,为 MaterialApp 设置了 tile,theme 和 home 属性。

title 是 MaterialApp 的题目,theme 是整个 MaterialApp 的主题,home 示意的是 app 进入时候应该展现的主页面。

默认状况下 MyHomePage 会返回一个相似上面代码的 Scaffold:

    return Scaffold(
      appBar: AppBar(title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: const <Widget>[
            Text('home page',),
          ],
        ),
      ),
    );

这样咱们能够失去常见的 MaterialApp 界面:

MaterialApp 详解

有了下面的框架,咱们就能够在 home 中构建本人的组件,从而开始 flutter 的欢快 app 之旅。

那么 MaterialApp 还有其余的什么性能吗?它的底层原理是怎么样的呢?一起来看看吧。

首先是 MaterialApp 的定义:

class MaterialApp extends StatefulWidget

能够看到 MaterialApp 是一个 StatefulWidget,示意 MaterialApp 可能会依据用户的输出不同,从新 build 子组件,因为通常来说 MaterialApp 示意一个应用程序总体,所以它须要思考很多简单的交互状况,应用 StatefulWidget 是很正当的。

MaterialApp 中的 theme

接下来咱们看下 MaterialApp 能够配置的主题。

MaterialApp 中有上面几种 theme:

  final ThemeData? theme;

  final ThemeData? darkTheme;

  final ThemeData? highContrastTheme;

  final ThemeData? highContrastDarkTheme;

  final ThemeMode? themeMode;

ThemeData 用来定义 widget 的主题款式,ThemeData 包含 colorScheme 和 textTheme 两局部。

为了简略起见,flutter 提供了两个简洁的 Theme 创立形式,别离是 ThemeData.light 和 ThemeData.dark。当然你也能够应用 ThemeData.from 从 ColorScheme 中创立新的主题。

那么问题来了,一个 app 为什么有这么多 ThemeData 呢?

默认状况下 theme 就是 app 将会应用的 theme,然而思考到当初风行的 theme 切换的状况,所以也提供了 darkTheme 这个选项。

如果 theme 和 darkTheme 都设置的话,那么将会依据 themeMode 来决定具体到底应用哪个主题。

留神,默认的主题是 ThemeData.light()

highContrastTheme 和 highContrastDarkTheme 的存在也是因为在某些零碎中须要 high contrast 和 dark 的主题版本,这些 ThemeData 是可选的。

themeMode 这个字段,如果取 ThemeMode.system, 那么默认会应用零碎的主题配置,具体而言,是通过调用 MediaQuery.platformBrightnessOf 来查问零碎到底是 Brightness.light 还是 Brightness.dark.

尽管默认是 ThemeMode.system,然而你也能够指定其为 ThemeMode.light 或者 ThemeMode.dark.

MaterialApp 中的 routes

和 web 页面的首页一样,在 MaterialApp 中,咱们也须要定义一些页面跳转的路由信息。

在解说 routes 之前,咱们须要明确 flutter 中有两个和路由相干的定义,别离是 routes 和 Navigator。

其中 routes 是路由的定义,它示意的是不同门路对应的 widget 地址,比方上面的 routers 的定义:

routes: <String, WidgetBuilder> {'/a': (BuildContext context) => MyPage(title: 'page A'),
       '/b': (BuildContext context) => MyPage(title: 'page B'),
       '/c': (BuildContext context) => MyPage(title: 'page C'),
     },

routers 的类型是 Map<String, WidgetBuilder>,对应的 key 就是路由地址,value 就是路由地址对应的 WidgetBuilder。

Navigator 是一个 Widget,用来对 routers 进行治理。

Navigator 能够通过是用 Navigator.pages、Navigator.push 或者 Navigator.pop 来对 routers 进行治理。举个例子:

push:

 Navigator.push(context, MaterialPageRoute<void>(builder: (BuildContext context) {
     return Scaffold(appBar: AppBar(title: Text('My Page')),
       body: Center(
         child: TextButton(child: Text('POP'),
           onPressed: () {Navigator.pop(context);
           },
         ),
       ),
     );
   },
 ));

pop:

Navigator.pop(context);

对于 MaterialApp 来说,如果是 / route, 那么将会查找 MaterialApp 中的 home 属性对应的 Widget, 如果 home 对应的 Widget 不存在,那么会应用 routers 外面配置的。

如果下面的信息都没有,则阐明须要创立 router,则会调用 onGenerateRoute 办法来创立新的 routers。

所以说 onGenerateRoute 是用来解决 home 和 routers 办法中没有定义的路由。你也能够将其看做是一种创立动静路由的办法。

最初,如果所有的 route 规定都不匹配的话,则会调用 onUnknownRoute。

如果 home,routes,onGenerateRoute,onUnknownRoute 全都为空,并且 builder 不为空的话,那么将不会创立任何 Navigator。

MaterialApp 中的 locale

local 是什么呢?local 在国际化中示意的是一种语言,通过应用 Local,你不必再程序中硬编码要展现的文本,从而做到 APP 的国际化反对。

dart 中的 local 能够这样应用:

const Locale swissFrench = Locale('fr', 'CH');
const Locale canadianFrench = Locale('fr', 'CA');

在 MaterialApp 中, 须要同时配置 localizationsDelegates 和 supportedLocales:

MaterialApp(
  localizationsDelegates: [// ... app-specific localization delegate[s] here
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
  ],
  supportedLocales: [const Locale('en', 'US'), // English
    const Locale('he', 'IL'), // Hebrew
    // ... other locales the app supports
  ],
  // ...
)

supportedLocales 中配置的是反对的 locales,localizationsDelegates 用来生成 WidgetsLocalizations 和 MaterialLocalizations.

无关 locale 的具体应用,能够关注后续的文章。

MaterialApp 和 WidgetsApp

MaterialApp 是一个 StatefulWidget, 那么和它绑定的 State 叫做:_MaterialAppState, _MaterialAppStatez 中有个 build 办法,返回的 widget 到底是什么呢?

    return ScrollConfiguration(behavior: widget.scrollBehavior ?? const MaterialScrollBehavior(),
      child: HeroControllerScope(
        controller: _heroController,
        child: result,
      ),
    );

能够看到,最终返回的是一个 ScrollConfiguration,它的实质是返回一个包装在 HeroControllerScope 中的 result。

什么是 Hero 呢?Hero 在 flutter 中是一个组件,用来示意在路由切换的过程中,能够从老的路由 fly 到新的路由中。这样的一个航行的动画,也叫做 Hero 动画。

而这个 result 其实是一个 WidgetsApp。

WidgetsApp 就是 MaterialApp 底层的 Widget, 它包装了应用程序通常须要的许多小部件。

WidgetsApp 的一个次要性能就是将零碎后退按钮绑定到弹出导航器或退出应用程序。

从实现上讲,MaterialApp 和 CupertinoApp 都应用它来实现应用程序的基本功能。

总结

MaterialApp 作为 Material 格调的第一入口,心愿大家可能熟练掌握它的用法。

本文的例子:https://github.com/ddean2009/learn-flutter.git

更多内容请参考 http://www.flydean.com/06-flutter-material-materialapp/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

正文完
 0