17、 Flutter Widgets 之 MaterialApp

545 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

MaterialApp使用material design的app组件,它是基于WidgetsApp的。那么,什么是material design呢?

material design是google设计的一套界面设计语言,简单来说,这是方便UI设计师们设计UI的一种语言。google为了开发者能更方便地开发出符合material design的app,于是封装了一些符合material design的组件库,通常一个符合material design的app有以下组件(参考其他博客筛选出一些我认为比较重要的组件):

1. 悬浮球(FAB)

2. 底部应用栏(App bars: bottom)

3.顶部应用栏(App bars: top)

4 横幅(Banner)

5. 底部导航(Bottom navigation)

6. 卡片式设计(Cards)

7.抽屉式导航(Navigation drawer)

MaterialApp

构造函数:

 MaterialApp({
  Key? key,
  this.navigatorKey,
  this.scaffoldMessengerKey,
  this.home,
  Map<String, WidgetBuilder> this.routes = const <String, WidgetBuilder>{},
  this.initialRoute,
  this.onGenerateRoute,
  this.onGenerateInitialRoutes,
  this.onUnknownRoute,
  List<NavigatorObserver> this.navigatorObservers = const <NavigatorObserver>[],
  this.builder,
  this.title = '',
  this.onGenerateTitle,
  this.color,
  this.theme,
  this.darkTheme,
  this.highContrastTheme,
  this.highContrastDarkTheme,
  this.themeMode = ThemeMode.system,
  this.locale,
  this.localizationsDelegates,
  this.localeListResolutionCallback,
  this.localeResolutionCallback,
  this.supportedLocales = const <Locale>[Locale('en', 'US')],
  this.debugShowMaterialGrid = false,
  this.showPerformanceOverlay = false,
  this.checkerboardRasterCacheImages = false,
  this.checkerboardOffscreenLayers = false,
  this.showSemanticsDebugger = false,
  this.debugShowCheckedModeBanner = true,
  this.shortcuts,
  this.actions,
  this.restorationScopeId,
  this.scrollBehavior,
  this.useInheritedMediaQuery = false,
})

MaterialApp 主要属性如下:

title : 在任务管理窗口中所显示的应用名字
theme : 应用各种 UI 所使用的主题颜色
color : 应用的主要颜色值(primary color),也就是安卓任务管理窗口中所显示的应用颜色
home : 应用默认所显示的界面 Widget
routes : 应用的顶级导航表格,这个是多页面应用用来控制页面跳转的,类似于网页的网址
initialRoute :第一个显示的路由名字,默认值为 Navigator.defaultRouteName
onGenerateRoute : 生成路由的回调函数,当导航的命名路由的时候,会使用这个来生成界面
onLocaleChanged : 当系统修改语言的时候,会触发这个回调
navigatorObservers : 应用 Navigator 的监听器
debugShowMaterialGrid : 是否显示 纸墨设计 基础布局网格,用来调试 UI 的工具
showPerformanceOverlay : 显示性能标签
debugShowCheckedModeBanner :是否显示右上角DEBUG标签 (调试开关)
checkerboardRasterCacheImages :检查缓存的图像开关,检测在界面重绘时频繁闪烁的图像(调试开关)
showSemanticsDebugger :是否打开Widget边框,类似Android开发者模式中显示布局边界(调试开关)

title参数是应用程序的描述,在Android上,在任务管理器的应用程序快照上面显示,在IOS上忽略此属性,IOS上任务管理器应用程序快照上面显示的是Info.plist文件中的CFBundleDisplayName。如果想根据区域显示不同的描述使用onGenerateTitle,用法如下:

MaterialApp(
    title: 'flutter',
    onGenerateTitle: (context){
      var local = Localizations.localeOf(context);
      if(local.languageCode=='zh'){
        return 'flutter 学习';
      }
      return 'flutter study';
    },
   ...
 
  )

themedarkThemethemeMode是关于主题的参数,设置整个App的主题,包括颜色、字体、形状等,修改主题颜色为红色用法如下:

MaterialApp(
  theme: ThemeData(
    primaryColor: Colors.blue
  ),
  darkTheme: ThemeData(
      primaryColor: Colors.blue
  ),
  themeMode: ThemeMode.dark,

效果:

图片.png routes、initialRoute、onGenerateRoute、onUnknownRoute是和路由相关的4个属性,路由简单的理解就是页面,路由的管理通常是指页面的管理,比如跳转、返回等。

MaterialApp按照如下的规则匹配路由:

路由为/,home不为null则使用home。

使用routes指定的路由。

使用onGenerateRoute生成的路由,处理除home和routes以外的路由。

如果上面都不匹配则调用onUnknownRoute。

用法:

 MaterialApp(
    title: 'flutter',
    onGenerateTitle: (context){
      var local = Localizations.localeOf(context);
      if(local.languageCode=='zh'){
        return 'flutter 学习';
      }
      return 'flutter study';
    },
    theme: ThemeData(primaryColor: Colors.blue),
    home: MyHomePage(
      title: "首页",
    ),
    routes: <String, WidgetBuilder>{
      'less': (BuildContext context) => StatefullGroup(),
      'photo': (BuildContext context) => PhotoAppDemo(),
    },
    initialRoute: '/',
    onGenerateRoute:(RouteSettings routeSettings){
      print('onGenerateRoute:$routeSettings');
      if(routeSettings.name =='less'){
        return MaterialPageRoute(builder: (context){
          return StatefullGroup();
        });
      }
    } ,
    onUnknownRoute: (RouteSettings routeSettings){
      print('onUnknownRoute:$routeSettings');
      return MaterialPageRoute(builder: (context){
        return PhotoAppDemo();
      });
    },
 
  )

如果initialRoute设置为less1,此时routes中并不存在名称为less1的路由,调用onGenerateRoute,如果onGenerateRoute返回路由页面,则加载此页面,如果返回的是null,且home不为null,则加载home参数指定的页面,如果home为null,则回调onUnknownRoute.

图片.png

locale、localizationsDelegates、localeListResolutionCallback、localeResolutionCallback、supportedLocales是区域设置和国际化相关的参数,如果App支持多国语言,那么就需要设置这些参数,默认情况下,Flutter仅支持美国英语,如果想要添加其他语言支持则需要指定其他MaterialApp属性,并引入flutter_localizations 包,到2019年4月,flutter_localizations包已经支持52种语言,如果你想让你的应用在iOS上顺利运行,那么你还必须添加“flutter_cupertino_localizations”包.

pubspec.yaml文件中添加包依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  flutter_cupertino_localizations: ^1.0.1

MaterialApp设置:

MaterialApp(
  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate
  ],
  supportedLocales: [
    const Locale('zh', 'CH'),
    const Locale('en', 'US'),
  ],
  ...
)

断点调试:

图片.png

系统语言切换到中文模式下后:

图片.png

  1. GlobalMaterialLocalizations.delegate :为Material Components库提供了本地化的字符串和其他值。
  2. GlobalWidgetsLocalizations.delegate:定义widget默认的文本方向,从左到右或从右到左。
  3. GlobalCupertinoLocalizations.delegate:为Cupertino(ios风格)库提供了本地化的字符串和其他值。

supportedLocales参数指定了当前App支持的语言。 localeResolutionCallback和localeListResolutionCallback都是对语言变化的监听,比如切换系统语言等,localeResolutionCallback和localeListResolutionCallback的区别是localeResolutionCallback返回的第一个参数是当前语言的Locale,而localeListResolutionCallback返回当前手机支持的语言集合,在早期的版本手机没有支持语言的集合,只显示当前语言,在设置->语言和地区的设置选项效果如下:

图片.png

因此我们只需使用localeListResolutionCallback即可,通过用户手机支持的语言和当前App支持的语言返回一个语言选项。

通常情况下,如果用户的语言正好是App支持的语言,那么直接返回此语言,如果不支持,则返回一个默认的语言,用法如下:

 localeListResolutionCallback: (locales, supportedLocales) {
      print('当前系统语言环境:$locales');
      if (locales!.contains('zh')) {
        return Locale('zh');
      }
      return Locale('en');
    }, 

还有几个方便调试的选项,debugShowMaterialGrid:打开网格调试

  debugShowMaterialGrid: true,

图片.png showPerformanceOverlay:打开性能检测

    showPerformanceOverlay: true,

图片.png

右上角有一个DEBUG的标识,这是系统在debug模式下默认显示的,不显示的设置如下:

  debugShowCheckedModeBanner: false,

图片.png

CupertinoApp

既然有Material风格的MaterialApp,那么也应该有Cupertino(ios)风格与之相对应,是的Cupertino风格的是CupertinoApp,CupertinoApp的属性及用法和MaterialApp一模一样,就不在具体介绍了。

基本构造方法:

const CupertinoApp({
    Key? key,
    this.navigatorKey,
    this.home,
    this.theme,
    Map<String, Widget Function(BuildContext)> this.routes = const <String, WidgetBuilder>{},
    this.initialRoute,
    this.onGenerateRoute,
    this.onGenerateInitialRoutes,
    this.onUnknownRoute,
    List<NavigatorObserver> this.navigatorObservers = const <NavigatorObserver>[],
    this.builder,
    this.title = '',
    this.onGenerateTitle,
    this.color,
    this.locale,
    this.localizationsDelegates,
    this.localeListResolutionCallback,
    this.localeResolutionCallback,
    this.supportedLocales = const <Locale>[Locale('en', 'US')],
    this.showPerformanceOverlay = false,
    this.checkerboardRasterCacheImages = false,
    this.checkerboardOffscreenLayers = false,
    this.showSemanticsDebugger = false,
    this.debugShowCheckedModeBanner = true,
    this.shortcuts,
    this.actions,
    this.restorationScopeId,
    this.scrollBehavior,
    this.useInheritedMediaQuery = false,)

全部代码地址

总结:

本篇主要介绍了MaterialApp的核心构造参数说明,MaterialApp基本是一个用户级别app的入口widget,系统层面的配置都基本通过次入口配置,这样主要提到app的全局标题,theme主题配置,路由跳转地址和异常路由处理,onLocaleChanged本地化语言相关的设置和回调处理。一些性能调试开关和debug相关开关等。Material设计风格还有底部导航,头部导航,策划菜单等,这些相关组件都在Scaffold脚手架中。后续会提到。