Flutter中App的主题和导航

栏目: IOS · Android · 发布时间: 5年前

内容简介:这里我们先看看需要注意的几点当通过
Flutter中App的主题和导航
  • Flutter和Dart系列文章代码GitHub地址
  • Flutter 一切皆 Widget 的核心思想, 为我们提供了两种主题风格
  • CupertinoApp : 一个封装了很多 iOS 风格的小部件,一般作为顶层 widget 使用
  • MaterialApp : 一个封装了很多安卓风格的小部件,一般作为顶层 widget 使用, 下面我们先看下这个 Widget

MaterialApp

这里我们先看看 MaterialApp 的构造函数和相关函数

const MaterialApp({
    Key key,
    // 导航主键, GlobalKey<NavigatorState>
    this.navigatorKey,
    // 主页, Widget
    this.home,
    // 路由
    this.routes = const <String, WidgetBuilder>{},
    // 初始化路由, String
    this.initialRoute,
    // 构造路由, RouteFactory
    this.onGenerateRoute,
    // 为止路由, RouteFactory
    this.onUnknownRoute,
    // 导航观察器
    this.navigatorObservers = const <NavigatorObserver>[],
    // widget的构建
    this.builder,
    // APP的名字
    this.title = '',
    // GenerateAppTitle, 每次在WidgetsApp构建时都会重新生成
    this.onGenerateTitle,
    // 背景颜色
    this.color,
    // 主题, ThemeData
    this.theme,
    // app语言支持, Locale
    this.locale,
    // 多语言代理, Iterable<LocalizationsDelegate<dynamic>>
    this.localizationsDelegates,
    // flutter.widgets.widgetsApp.localeListResolutionCallback
    this.localeListResolutionCallback,
    // flutter.widgets.widgetsApp.localeResolutionCallback
    this.localeResolutionCallback,
    // 支持的多语言, Iterable<Locale>
    this.supportedLocales = const <Locale>[Locale('en', 'US')],
    
    // 是否显示网格
    this.debugShowMaterialGrid = false,
    // 是否打开性能监控,覆盖在屏幕最上面
    this.showPerformanceOverlay = false,
    // 是否打开栅格缓存图像的检查板
    this.checkerboardRasterCacheImages = false,
    // 是否打开显示到屏幕外位图的图层的检查面板
    this.checkerboardOffscreenLayers = false,
    // 是否打开覆盖图,显示框架报告的可访问性信息 显示边框
    this.showSemanticsDebugger = false,
    // 是否显示右上角的Debug标签
    this.debugShowCheckedModeBanner = true,
})
复制代码

需要注意的几点

  • 如果 home 首页指定了, routes 里面就不能有 '/' 的根路由了,会报错, / 指定的根路由就多余了
  • 如果没有 home 指定具体的页面,那 routes 里面就有 / 来指定根路由
  • 路由的顺序按照下面的规则来:
    • 1、如果有 home ,就会从 home 进入
    • 2、如果没有 home ,有 routes ,并且 routes 指定了入口 '/' ,就会从 routes/ 进入
    • 3、如果上面两个都没有,或者路由达不到,如果有 onGenerateRoute ,就会进入生成的路由
    • 4、如果连上面的生成路由也没有,就会走到 onUnknownRoute ,不明所以的路由,比如网络连接失败,可以进入断网的页面

routes

  • 声明程序中有哪个通过 Navigation.of(context).pushNamed 跳转的路由
  • 参数以键值对的形式传递
    • key :路由名字
    • value :对应的 Widget
routes: {
  '/home': (BuildContext content) => Home(),
  '/mine': (BuildContext content) => Mine(),
},
复制代码

initialRoute

  • 初始化路由, 当用户进入程序时,自动打开对应的路由(home还是位于一级)
  • 传入的是上面 routeskey , 跳转的是对应的 Widget (如果该 WidgetScaffold.AppBar ,并不做任何修改,左上角有返回键)
routes: {
  '/home': (BuildContext content) => Home(),
  '/mine': (BuildContext content) => Mine(),
},
initialRoute: '/mine',
复制代码

onGenerateRoute

当通过 Navigation.of(context).pushNamed 跳转路由时, 在 routes 查找不到时,会调用该方法

onGenerateRoute: (RouteSettings setting) {
  return MaterialPageRoute(
    settings: setting,
    builder: (BuildContext content) => Text('生成一个路由')
  );
},
复制代码

onUnknownRoute

未知路由, 效果跟 onGenerateRoute 一样, 在未设置 onGenerateRoute 的情况下, 才会去调用 onUnknownRoute

onUnknownRoute: (RouteSettings setting) {
  return MaterialPageRoute(
    settings: setting,
    builder: (BuildContext content) => Text('这是一个未知路由')
  );
},
复制代码

navigatorObservers

  • 路由观察器,当调用 Navigator 的相关方法时,会回调相关的操作
  • 比如 pushpopremovereplace 是可以拿到当前路由和后面路由的信息
  • 获取路由的名字: route.settings.name
// navigatorObservers: [HomeObserver()],

// 继承NavigatorObserver
class HomeObserver extends NavigatorObserver {
  @override
  void didPush(Route route, Route previousRoute) {
    super.didPush(route, previousRoute);

    // 获取路由的名字
    print('name = ${route.settings.name}');
    // 获取返回的内容
    print('reaule = ${route.currentResult}');
  }
}
复制代码

builder

如果设置了这个参数, 那么将会优先渲染这个 builder , 而不会在走路由

builder: (BuildContext content, Widget widget) => Text('builder'),
复制代码

title

  • 设备用于识别用户的应用程序的单行描述
  • Android 上,标题显示在任务管理器的应用程序快照上方,当用户按下“最近的应用程序”按钮时会显示这些快照
  • iOS 上,无法使用此值。来自应用程序的 Info.plistCFBundleDisplayName 在任何时候都会被引用,否则就会引用 CFBundleName
  • 要提供初始化的标题,可以用 onGenerateTitle

CupertinoApp

用于创建 iOS 风格应用的顶层组件, 相关属性和 MaterialApp 相比只是少了 themedebugShowMaterialGrid , 其他属性都一样, 如下所示

const CupertinoApp({
    Key key,
    this.navigatorKey,
    this.home,
    this.routes = const <String, WidgetBuilder>{},
    this.initialRoute,
    this.onGenerateRoute,
    this.onUnknownRoute,
    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,
})
复制代码

使用示例如下

return CupertinoApp(
  title: 'Cupertino App',
  color: Colors.red,
  home: CupertinoPageScaffold(
    backgroundColor: Colors.yellow,
    resizeToAvoidBottomInset: true,
    navigationBar: CupertinoNavigationBar(
      middle: Text('Cupertino App Bar'),
      backgroundColor: Colors.blue,
    ),
    child: Center(
      child: Container(
        child: Text('Hello World'),
      ),
    ),
  ),
);
复制代码

CupertinoPageScaffold

一个 iOS 风格的页面的基本布局结构。包含内容和导航栏

const CupertinoPageScaffold({
    Key key,
    // 设置导航栏, 后面会详解
    this.navigationBar,
    // 设置内容页面的背景色
    this.backgroundColor = CupertinoColors.white,
    // 子widget是否应该自动调整自身大小以适应底部安全距离
    this.resizeToAvoidBottomInset = true,
    @required this.child,
})
复制代码

navigationBar

const CupertinoNavigationBar({
    Key key,
    //导航栏左侧组件
    this.leading,
    //是否显示左边组件, 好像无效
    this.automaticallyImplyLeading = true,
    //是否显示中间组件, 好像无效
    this.automaticallyImplyMiddle = true,
    //导航栏左侧组件的右边的文本, 好像无效
    this.previousPageTitle,
    // 导航栏中间组件
    this.middle,
    // 导航栏右侧组件    
    this.backgroundColor = _kDefaultNavBarBackgroundColor,
    // 设置左右组件的内边距, EdgeInsetsDirectional
    this.padding,
    //左侧默认组件和左侧组件右边文本的颜色
    this.actionsForegroundColor = CupertinoColors.activeBlue,
    this.transitionBetweenRoutes = true,
    this.heroTag = _defaultHeroTag,
})
复制代码

使用示例

return CupertinoApp(
  title: 'Cupertino App',
  color: Colors.red,
  debugShowCheckedModeBanner: false,
  home: CupertinoPageScaffold(
    backgroundColor: Colors.yellow,
    resizeToAvoidBottomInset: true,
    navigationBar: CupertinoNavigationBar(
      leading: Icon(Icons.person),
      automaticallyImplyLeading: false,
      automaticallyImplyMiddle: false,
      previousPageTitle: '返回',
      middle: Text('Cupertino App Bar'),
      trailing: Icon(Icons.money_off),
      border: Border.all(),
      backgroundColor: Colors.white,
      padding: EdgeInsetsDirectional.fromSTEB(10, 10, 10, 10),
      actionsForegroundColor: Colors.red,
      transitionBetweenRoutes: false,
      heroTag: Text('data'),
    ),
    child: Center(
      child: Container(
        child: Text('Hello World'),
      ),
    ),
  ),
);
复制代码

Scaffold

  • Scaffold 通常被用作 MaterialApp 的子 Widget (安卓风格),它会填充可用空间,占据整个窗口或设备屏幕
  • Scaffold 提供了大多数应用程序都应该具备的功能,例如顶部的 appBar ,底部的 bottomNavigationBar ,隐藏的侧边栏 drawer
const Scaffold({
    Key key,
    // 显示在界面顶部的一个AppBar
    this.appBar,
    // 当前界面所显示的主要内容Widget
    this.body,
    // 悬浮按钮, 默认在右下角位置显示
    this.floatingActionButton,
    // 设置悬浮按钮的位置
    this.floatingActionButtonLocation,
    // 悬浮按钮出现消失的动画
    this.floatingActionButtonAnimator,
    // 在底部呈现一组button,显示于[bottomNavigationBar]之上,[body]之下
    this.persistentFooterButtons,
    // 一个垂直面板,显示于左侧,初始处于隐藏状态
    this.drawer,
    // 一个垂直面板,显示于右侧,初始处于隐藏状态
    this.endDrawer,
    // 出现于底部的一系列水平按钮
    this.bottomNavigationBar,
    // 底部的持久化提示框
    this.bottomSheet,
    // 背景色
    this.backgroundColor,
    // 重新计算布局空间大小
    this.resizeToAvoidBottomPadding = true,
    // 是否显示到底部, 默认为true将显示到顶部状态栏
    this.primary = true,
})
复制代码

appBar

设置导航栏, 接受一个抽象类 PreferredSizeWidget , 这里使用其子类 AppBar 进行设置, 后面会详解

floatingActionButton

  • 设置一个悬浮按钮, 默认在右下角位置显示, 这里使用 FloatingActionButton 设置
  • FloatingActionButtonMaterial 设计规范中的一种特殊 Button ,通常悬浮在页面的某一个位置作为某种常用动作的快捷入口, 后面会详解

floatingActionButtonLocation

设置悬浮按钮的位置, 接受一个抽象类 FloatingActionButtonLocation

// 右下角, 距离底部有一点距离, 默认值
static const FloatingActionButtonLocation endFloat = _EndFloatFabLocation();
// 中下方, 距离底部有一点距离
static const FloatingActionButtonLocation centerFloat = _CenterFloatFabLocation();
// 右下角, 距离底部没有间距
static const FloatingActionButtonLocation endDocked = _EndDockedFloatingActionButtonLocation();
// 中下方, 距离底部没有间距
static const FloatingActionButtonLocation centerDocked = _CenterDockedFloatingActionButtonLocation();
复制代码

FloatingActionButton

Material Design 中,一般用来处理界面中最常用,最基础的用户动作。它一般出现在屏幕内容的前面,通常是一个圆形,中间有一个图标, 有以下几种构造函数

const FloatingActionButton({
    Key key,
    this.child,
    // 文字解释, 按钮呗长按时显示
    this.tooltip,
    // 前景色
    this.foregroundColor,
    // 背景色
    this.backgroundColor,
    // hero效果使用的tag,系统默认会给所有FAB使用同一个tag,方便做动画效果
    this.heroTag = const _DefaultHeroTag(),
    // 未点击时阴影值,默认6.0
    this.elevation = 6.0,
    // 点击时阴影值,默认12.0
    this.highlightElevation = 12.0,
    // 点击事件监听
    @required this.onPressed,
    // 是否为“mini”类型,默认为false
    this.mini = false,
    // 设置阴影, 设置shape时,默认的elevation将会失效,默认为CircleBorder
    this.shape = const CircleBorder(),
    // 剪切样式
    this.clipBehavior = Clip.none,
    // 设置点击区域大小的样式, MaterialTapTargetSize的枚举值
    this.materialTapTargetSize,
    // 是否为”extended”类型
    this.isExtended = false,
})
复制代码

mini

  • 是否为 mini 类型,默认为 false
  • FloatingActionButton 分为三种类型: regular , mini , extended
  • regularmini 两种类型通过默认的构造方法实现, 只有图片
  • 大小限制如下
const BoxConstraints _kSizeConstraints = const BoxConstraints.tightFor(
  width: 56.0,
  height: 56.0,
);

const BoxConstraints _kMiniSizeConstraints = const BoxConstraints.tightFor(
  width: 40.0,
  height: 40.0,
);

const BoxConstraints _kExtendedSizeConstraints = const BoxConstraints(
  minHeight: 48.0,
  maxHeight: 48.0,
);
复制代码

isExtended

  • 是否为 extended 类型, 设置为 true 即可
  • 除此之外, 还可以使用 extended 构造函数创建该类型
FloatingActionButton.extended({
    Key key,
    this.tooltip,
    this.foregroundColor,
    this.backgroundColor,
    this.heroTag = const _DefaultHeroTag(),
    this.elevation = 6.0,
    this.highlightElevation = 12.0,
    @required this.onPressed,
    this.shape = const StadiumBorder(),
    this.isExtended = true,
    this.materialTapTargetSize,
    this.clipBehavior = Clip.none,
    // 设置图片
    @required Widget icon,
    // 设置文字
    @required Widget label,
})
复制代码

从参数上看差异并不大,只是把默认构造方法中的 child 换成了 iconlabel ,不过通过下面的代码可以看到,传入的 labelicon 也是用来构建 child 的,不过使用的是 Row 来做一层包装而已

AppBar

AppBar 是一个 Material 风格的导航栏,它可以设置标题、导航栏菜单、底部 Tab

AppBar({
    Key key,
    // 导航栏左侧weidget
    this.leading,
    // 如果leading为null,是否自动实现默认的leading按钮
    this.automaticallyImplyLeading = true,
    // 导航栏标题
    this.title,
    // 导航栏右侧按钮, 接受一个数组
    this.actions,
    // 一个显示在AppBar下方的控件,高度和AppBar高度一样,可以实现一些特殊的效果,该属性通常在SliverAppBar中使用
    this.flexibleSpace,
    // 一个AppBarBottomWidget对象, 设置TabBar
    this.bottom,
    //中控件的z坐标顺序,默认值为4,对于可滚动的SliverAppBar,当 SliverAppBar和内容同级的时候,该值为0,当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改elevation的值
    this.elevation = 4.0,
    // 背景颜色,默认值为 ThemeData.primaryColor。改值通常和下面的三个属性一起使用
    this.backgroundColor,
    // 状态栏的颜色, 黑白两种, 取值: Brightness.dark
    this.brightness,
    // 设置导航栏上图标的颜色、透明度、和尺寸信息
    this.iconTheme,
    // 设置导航栏上文字样式
    this.textTheme,
    // 导航栏的内容是否显示在顶部, 状态栏的下面
    this.primary = true,
    // 标题是否居中显示,默认值根据不同的操作系统,显示方式不一样
    this.centerTitle,
    // 标题间距,如果希望title占用所有可用空间,请将此值设置为0.0
    this.titleSpacing = NavigationToolbar.kMiddleSpacing,
    // 应用栏的 工具 栏部分透明度
    this.toolbarOpacity = 1.0,
    // 底部导航栏的透明度设置
    this.bottomOpacity = 1.0,
})
复制代码

leading

导航栏左侧 weidget

final Widget leading;

// 示例
leading: Icon(Icons.home),
复制代码

actions

导航栏右侧按钮, 接受一个数组

final List<Widget> actions;

// 示例
actions: <Widget>[
    Icon(Icons.add),
    Icon(Icons.home),
],
复制代码

brightness

状态栏的颜色, 黑白两种

// 状态栏白色
brightness: Brightness.dark,
// 状态栏黑色
brightness: Brightness.light,
复制代码

iconTheme

设置导航栏上图标的颜色、透明度、和尺寸信息

const IconThemeData({this.color, double opacity, this.size})

// 示例
iconTheme: IconThemeData(color: Colors.white, opacity: 0.56, size: 30),
复制代码

TabBar

  • AppBar 中通过 bottom 属性来添加一个导航栏底部 tab 按钮组, 接受一个 PreferredSizeWidget 类型
  • PreferredSizeWidget 是一个抽象类, 这里我们使用 TabBar
class TabBar extends StatefulWidget implements PreferredSizeWidget {
  const TabBar({
    Key key,
    // 数组,显示的标签内容,一般使用Tab对象,当然也可以是其他的Widget
    @required this.tabs,
    // TabController对象
    this.controller,
    // 是否可滚动
    this.isScrollable = false,
    // 指示器颜色
    this.indicatorColor,
    // 指示器高度
    this.indicatorWeight = 2.0,
    // 指示器内边距
    this.indicatorPadding = EdgeInsets.zero,
    // 设置选中的样式decoration,例如边框等
    this.indicator,
    // 指示器大小, 枚举值TabBarIndicatorSize
    this.indicatorSize,
    // 选中文字颜色
    this.labelColor,
    // 选中文字样式
    this.labelStyle,
    // 文字内边距
    this.labelPadding,
    // 未选中文字颜色
    this.unselectedLabelColor,
    // 未选中文字样式
    this.unselectedLabelStyle,
  })
}

// Tab的构造函数
const Tab({
    Key key,
    // 文本
    this.text,
    // 图标
    this.icon,
    // 子widget
    this.child,
})
复制代码

效果如下

Flutter中App的主题和导航

相关代码如下

void main(List<String> args) => runApp(NewApp());

class NewApp extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return App();
  }
}

class App extends State<NewApp> with SingleTickerProviderStateMixin {
  List tabs = ['语文', '数学', '英语', '政治', '历史', '地理', '物理', '化学', '生物'];
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(initialIndex: 0, length: tabs.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text('CoderTitan'),
              backgroundColor: Colors.blueAccent,
              brightness: Brightness.dark,
              centerTitle: true,
              bottom: TabBar(
                controller: _tabController,
                tabs: tabs.map((e) => Tab(text: e)).toList(),
                isScrollable: true,
                indicatorColor: Colors.red,
                indicatorWeight: 2,
                indicatorSize: TabBarIndicatorSize.label,
                labelColor: Colors.orange,
                unselectedLabelColor: Colors.white,
                labelStyle: TextStyle(fontSize: 18, color: Colors.orange),
                unselectedLabelStyle: TextStyle(fontSize: 15, color: Colors.white),
              ),
            ),
            body: TabBarView(
              controller: _tabController,
              children: tabs.map((e) {
                return Container(
                  alignment: Alignment.center,
                  child: Text(e, style:TextStyle(fontSize: 50)),
                );
              }).toList(),
            ),
        ),
        debugShowCheckedModeBanner: false,
    );
  }
}
复制代码

BottomNavigationBar

  • Scaffold 中有一个属性 bottomNavigationBar 用于设置最底部的 tabbar 导航栏
  • 使用 Material 组件库提供的 BottomNavigationBarBottomNavigationBarItem 两个 Widget 来实现Material风格的底部导航栏
BottomNavigationBar({
    Key key,
    // 子widget数组
    @required this.items,
    // 每一个item的点击事件
    this.onTap,
    // 当前选中的索引
    this.currentIndex = 0,
    // 类型
    BottomNavigationBarType type,
    // 文字颜色
    this.fixedColor,
    // 图片大小
    this.iconSize = 24.0,
})
复制代码

items

包含所有子 Widget 的数组

final List<BottomNavigationBarItem> items;

const BottomNavigationBarItem({
    // 未选中图片
    @required this.icon,
    // 标题
    this.title,
    // 选中的图片
    Widget activeIcon,
    // 背景色
    this.backgroundColor,
})
复制代码

以上所述就是小编给大家介绍的《Flutter中App的主题和导航》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ajax Design Patterns

Ajax Design Patterns

Michael Mahemoff / O'Reilly Media / 2006-06-29 / USD 44.99

Ajax, or Asynchronous JavaScript and XML, exploded onto the scene in the spring of 2005 and remains the hottest story among web developers. With its rich combination of technologies, Ajax provides a s......一起来看看 《Ajax Design Patterns》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具