Android Flutter 期末复习

客观题

Dart语言基础

Basic

  1. Dart中一切皆对象。函数,也是一个Function类型的对象; null也是对象;所有对象均继承自Object类型
  2. Dart是强类型语言,变量声明时支持类型自动推导,但必要时也需显式声明类型
    注释
  3. var,声明变量
  4. public/private等访问限定符,私有/局部变量/函数以"_"下划线前缀命名
  5. 单引号声明字符串
  6. $varibleName/${expression},可在字符串中直接包含变量,或表达式
  7. final,声明为常量,只能赋值一次
  8. const,编译时就必须确定的常量,一般为有字面量的常量,或引用不变的对象
  9. 常量建议使用小驼峰命名,而非全大写
  10. int/double,由于是对象,因此直接包含了取绝对值,四舍五入等方法
  11. 多行字符串
  12. 转义符
  13. bool,布尔值
    list集合
var list = [1, 2, 3];
list.length;
  1. {key: value },Map键值对,获取的写法类似js

Functions

  1. 函数,Function类型的对象
  2. main(),程序的入口,顶级函数,与C语言一样无需类
  3. 可以不显式声明返回类型main() => runApp(MyWedget());
  4. _,声明为私有函数

Optional parameters

  1. 构造函数/函数的必选参数在前,可选命名参数在后,通过{ }声明可选参数
  2. 没有赋值的可选参数,默认值为null
  3. 参数的默认值

Operators

  1. as(emp as Person).firstName = 'Bob'; 类型转换
  2. is,对象类型判断
  3. ??,空判断
// 如果name不为null,返回name;为null返回guest
String playerName(String name) => name ?? 'Guest';
  1. ..,方法级联操作符,忽略方法的返回值,直接调用,无需每次均指定变量调用
querySelector('#confirm') // 获取对象 (Get an object).
  ..text = 'Confirm' // 使用对象的成员 (Use its members).
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
  1. assert,断言,在结果不满足时打断程序的执行,生产环境下不会执行
  2. ?.,调用实例级变量/方法,可避免空指针

Classes

mixin 继承机制
创建对象,无需new操作符,直接调用构造函数
单继承

var p = Point(2, 2);
// 为实例变量 y 赋值。
p.y = 3;
// 如果 p 为非空则将其属性 y 的值设为 4
p?.y = 4;

省略getter/setter
构造函数初始化属性的语法糖

class Point {
  num x, y;

  // 在构造函数体执行前用于设置 x 和 y 的语法糖。
  Point(this.x, this.y);
}

命名构造函数
在构造函数体前,调用父类构造函数

class Employee extends Person {
  Employee() : super.fromJson(defaultData);
  // ···
}

类静态方法与变量

Structure

https://dart.cn/guides/libraries/create-library-packages


Row/column/container/listview/card等基本容器组件的基本属性

Layout

https://flutter.cn/docs/development/ui/layout

flutter组件,默认均不包括内/外边距/高宽属性。
因此,当需要内外边距边框时,需要置于容器中。
但flutter本身没有区分组件与容器,容器也是组件,一切皆为组件

有的容器仅能放单元素;单元素容器;有的可以放多个元素,多元素容器。通过提供的属性可以判断

  • child
  • children

Row & Column

https://flutter.cn/docs/development/ui/layout#lay-out-multiple-widgets-vertically-and-horizontally

row,多元素容器,声明一个行。行中的组件在一行横向排列
column,多元素容器,声明一个列。列中的组件在一列纵向排列
mainaxis/crossaxis,主轴/交叉轴,与排列方向有关。即,row的主轴为X轴,column的主轴为Y轴
默认row/column容器,均占用其主轴的最大空间,即父元素的空间
但当其内部元素,他元素/容器阻挡/约束时,为需要多大占多大(包裹)

  • mainAxisSize,MainAxisSize.min,wrap,包裹,仅占用所需空间
  • mainAxisAlignment,MainAxisAlignment,子项对齐方式,剩余空间的分配
    • spaceBetween,2端对齐
    • spacearound,每个元素占用相等剩余空间,包括第一/最后,的2端
    • spaceEvenly,剩余空间均匀分布在每个元素之间
  • crossAxisAlignment,CrossAxisAlignment,交叉轴对齐方向
  • children,集合,其中的多个组件

练习
自定义widget,封装Text,包含字体大小/颜色

Texts

Text,文本

  • 第一项必填,字符串文本内容
  • textAlign,字体对齐方向
  • style,样式,TextStyle
    • color/fontSize/fontWeight/fontStyle,等等字体样式属性,size默认14

Expanded

Expanded,单元素容器。在主轴,占用尽可能大的剩余空间,类似match_parent
会忽略掉mainAxisAlignment对齐方式的布局
当元素内容超过设备屏幕尺寸时,可用于包裹限制元素(FittedBox也可)

  • flex,当多个expanded并列时,声明占用剩余空间的比重

row/column/expanded,内容超出屏幕,均不支持滚动

SizedBox & Padding & Margin & Center & FittedBox

Padding/Margin,单一容器,仅支持内或外边距,没有高宽/边框等属性
Center,单元素容器,使内容居中
SizedBox,单元素容器,支持高宽,无内外边距
FittedBox,单元素容器,可控制内部元素的缩放

dp,像素密度,设备屏幕尺寸无关的,描述控件间距离等。Flutter默认单位

Container

Container,单元素容器,支持边框/内外边距/高宽等属性的容器。便于扩展,建议使用

  • color,背景色
  • height/width
  • padding/margin,内外边距,EdgeInsets下的方法声明。
    EdgeInsets.only()/EdgeInsets.all()/EdgeInsets.fromLTRB等
  • decoration,BoxDecoration。绘制在child后的装饰。更详细的设置
    • color,背景色。Colors/Color
    • image,背景图片
    • border,边框,Border.all(color, width)等方法。或,Border()
      • bottom: BorderSide(color, width)
    • borderRadius,BorderRadius.all(Radius.circular(10)),圆角
    • shape,形状
      在这里插入图片描述

GridView

GridView.count 可指定列的数量,自动计算宽度
GridView.extent,可指定栅格宽度,自动计算列数
支持自动滚动,自动适应横竖屏切换,自动重用组件对象的平滑滚动
即,自动实现了原生Android中的ViewHolder

  • maxCrossAxisExtent,声明每个栅格的宽度
  • padding
  • mainAxisSpacing/crossAxisSpacing,主/交叉轴外边距
  • children

ListView

https://flutter.cn/docs/cookbook/lists/basic-list

可以用来放置一组相似的组件,或当内部元素过长而自动滚动的容器
与column相比,支持长度超过一屏的滚动
项默认不直接支持点击
Divider(),分割线,可作为项直接使用
ListView,当项固定时,可直接基于children属性构建

  • padding,ListView的内边距,不是项的内边距
  • shrinkWrap,用于item高度不确定时,适配item内容高度,避免内容溢出
  • itemExtent,可固定item高度,超过会异常

Work with long lists

https://flutter.cn/docs/cookbook/lists/long-lists

动态生成ListView,需要
ListView.builder(),支持内边距等,但没有分割线。自动循环itemCount次,创建itemBuilder中返回的item

  • itemCount,项的数量
  • itemBuilder: (BuildContext context, int index) {return },构造项的函数,返回每一个项。自动注入context以及项的索引

ListView.separated(),带分割线的静态方法,包含以上属性相同

  • separatorBuilder: (BuildContext context, int index) {return Divider()},自定义分隔符

ListTile

https://api.flutter-io.cn/flutter/material/ListTile-class.html
ListTile,简单常用的左/上/下布局的组件。可作为ListView的项,也可单独使用。可仅声明需要的部分

  • leading,一般置一个Icon
  • title,一般置一个文本,默认加粗
  • subTitle,一个文本
  • trailing,尾部右对齐控件,一般为icon
  • onTap,() {}。点击回调函数,自带波纹效果。不声明没有点击的波纹效果

leading与title/subTitle不自动居中对齐!
在这里插入图片描述

Icon

http://micon.dxbtech.cn/

Icon,图标,flutter内置Material图标

  • 第一项必填,Icons下的常量
  • color,颜色,Colors下的常量
  • size,尺寸
    在这里插入图片描述
    在这里插入图片描述

有状态组件的声明创建,更新的原理与方法

StatefulWidget

https://flutter.cn/docs/development/ui/interactive

为了构建更复杂的体验响应用户互交,需要保存改变一些组件的数据状态
Flutter提供StatefulWidget实现。StatefulWidget是一种特殊的组件,它会生成并维护一个State对象,用于保存数据状态

创建过程

  • 创建有状态组件
  • 创建对应的,管理组件数据状态的状态管理组件
  • 重写有状态组件的createState()方法
  • 重写state类的initState()方法,初始化数据(可选)。
    类似vue的created()回调,完成组件创建时的异步网络请求等
  • initState()回调函数中,必须首先调用父类initState()
  • 重写state类的build方法,构建组件
  • 在任何回调函数中,执行setState((){})方法通知组件数据状态改变
  • 回调State build()方法重绘组件

build()方法会在每次重新渲染时回调,因此不能在此方法中执行初始化!
在这里插入图片描述

floatingActionButton

绝对定位在指定位置的按钮
可在Scaffold中的floatingActionButton属性声明

  • floatingActionButton: FloatingActionButton(),声明一个浮动按钮
    • child: Icon(Icons.add),一般为图标
    • onPressed,点击回调函数

Scaffold中的floatingActionButtonLocation属性,可声明浮动按钮的位置

  • floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,声明位置
    在这里插入图片描述

Suggestion

当状态改变时,有状态组件将被重新绘制。因此,仅将必要的,内容会改变的组件声明为有状态,可提高渲染速度
例如,如果直接将MyApp创建为有状态,则其内任何组件对数据状态的改变,
都会从MyApp对象节点开始到其内的所有组件重新创建,重绘
但是,flutter内部也会智能判断,组件是否需要重新创建
可以将2个需要互交控件的父组件,声明为有状态组件,传递信息

StatefulWidget,适用于简单的状态处理。类似vue组件内部声明的,仅在组件内使用的响应式数据的方法

复杂的,涉及影响到多个组件数据状态变化时,应使用Provider,类似vuex的全局单一数据源解决方法

BuildContext

widget对象是不可变对象(引用不可变,封装的属性对象可变)
其封装着需要渲染的元素element对象,以及若干属性的对象
实际需要在组件树上渲染的,是element对象,而非widget对象
因此,重新渲染widget时,并不是重新创建widget组件对象,而是重新创建其对应的element对象。即,回调build()方法

创建widget对象后,基于widget对象创建element对象
element对象同时持有widget对象引用
将element对象添加到element树上
element实现了BuildContext接口(dart中,类即接口)
element对象回调widget build方法,将自己以BuildContext类型传入
因此,BuildContext对象,就是element元素对象
因此,可以在state对象的build方法中,直接使用element上的widget对象

ListTile组件

https://api.flutter-io.cn/flutter/material/ListTile-class.html
ListTile,简单常用的左/上/下布局的组件。可作为ListView的项,也可单独使用。可仅声明需要的部分

  • leading,一般置一个Icon
  • title,一般置一个文本,默认加粗
  • subTitle,一个文本
  • trailing,尾部右对齐控件,一般为icon
  • onTap,() {}。点击回调函数,自带波纹效果。不声明没有点击的波纹效果

leading与title/subTitle不自动居中对齐!

在这里插入图片描述

路由/导航/传参的方法

Navigation

https://flutter.cn/docs/development/ui/navigation

MaterialApp routes属性。Map<String, Widget Function(BuildContext)>
键:字符串,路由名称;值:返回路由组件的函数
/,默认路由名称。即首页
路由是指大功能“页面”的切换,而非页面内组件的切换
因此,路由切换的是包含AppBar在内的,不同的Scaffold对象的页面
不支持嵌套路由。页面与PC的页面有明显的尺寸差距,不适合复杂的路由

在这里插入图片描述
该处的路由以常量的形式进行了书写,实际上为字符串
在这里插入图片描述
在这里插入图片描述

Navigator

Navigator.pushNamed(BuildContext, String, {arguments: Object})

  • BuildContext
    - String,路由名称
  • arguments,可选,传递参数

如果路由栈顶组件声明了AppBar,且leading为空。
则自动添加返回箭头图标;显式声明了leading,则不会覆盖

Navigator.popAndPushNamed()。不保存在路由栈的路由。即返回时不会此页面
在这里插入图片描述

Return

Navigator.of(context).pop([T t])
弹出路由栈顶页面,即返回上一页面。可以声明返回携带的参数
在这里插入图片描述

Navigate With Arguments

final T t = ModalRoute.of(context).settings.arguments;
可在路由组件接收传入的参数

接收返回参数。可在调用时,Navigator.pushNamed().then((t) {return t}),获取返回结果
then()方法返回异步的Future类型函数,类似JS的Promise
重写泛型,回调函数返回结果

但按设备返回键,需单独监听
较复杂,建议通过Provider实现
在这里插入图片描述

Sliver联动的主要组件及属性

NestedScrollview

基于Scaffold的appbar+listview布局,listview的滑动不会影响到固定的appbar

但,当需要appbar随下部的listview的滑动而显示/隐藏/改变时,则需要将他们置于一个
统一管理的,支持滑动联动的容器中。

  • CustomScrollView,是可定制的管理滚动的容器
  • NestedScrollView,是基于CustomScrollView并已实现部分功能的容器
    在这里插入图片描述
    且,普通组件不支持滑动统一管理,
    flutter提供了独立的基于sliver的控件:
    SliverAppBar/SliverList/SliverGrid/SliverFillRemaining(不随滑动的部分)等等。
    将以上所需sliver组件对象,slivers属性

即,Scaffold不再单独声明appBar属性,由body属性包含NestedScrollView,NestedScrollView中包含支持联动的appbar以及body
NestedScrollView,

  • headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {return SliverAppBar()}。创建支持滑动联动的SliverAppBar
  • body,支持滑动联动的内容容器
  • controller,滑动监听回调函数
    在这里插入图片描述

SliverAppBar

https://api.flutter-io.cn/flutter/material/SliverAppBar-class.html

SliverAppBar,支持滑动联动,具有自动弹性伸缩/隐藏功能的AppBar

  • primary,true,是否预留系统的状态栏
  • expandedHeight: 200,声明高度;
  • pinned: true,向上滑动时,保留SliverAppBar的title/leading等信息,自动缩放title中文字。false,不保留SliverAppBar
  • floating: false,当不在最顶端而向下滑动时,是否渐出appbar(无效了?)
  • snap: false,只在floating true时有效。appbar默认出现效果为渐出。snap true,appbar为弹出效果
  • flexiblespace,FlexibleSpaceBar(),sliverappbar容器
  • bottom,底部,可放置tab。位置与FlexibleSpaceBar中的title重叠
    在这里插入图片描述
    SliverAppBar的其他属性,许多与AppBar相同
  • leading
  • title
  • actions
  • bottom
  • forceElevated: true,展开flexibleSpace之后是否显示阴影
  • automaticallyImplyLeading: true。没有leading,当有侧边栏的时候,false:不会显示默认的图片,true 会显示默认图片,并响应打开侧边栏的事件。如果有leading,忽略;
    在这里插入图片描述

FlexibleSpaceBar

FlexibleSpaceBar,在SliverAppBar中随滚动自动隐藏的容器,不能是普通的card等容器

  • background,相当于child。可以是基本颜色/图片。也可将内容封装到card等容器
  • title,标题容器。默认下部居中,滑动时支持置顶保留。与SliverAppBar bottom位置重叠
    在这里插入图片描述

CustomScrollView

https://api.flutter-io.cn/flutter/widgets/CustomScrollView-class.html

更复杂的自定义滑动容器。组合SliverAppBar/SliverList/SliverGrid等

SliverList

  • SliverList,滑动联动列表组件
    • delegate,SliverChildBuilderDelegate((BuildContext context, int index) {return Container()}, childCount),
      第一项为必填的构造项的回调函数,返回项;childCount,项的个数

在这里插入图片描述

Tab与内容联动的主要组件与属性

Tabs

https://flutter.cn/docs/cookbook/design/tabs

Tab,支持左右滑动的,顶部标签导航
Tab声明在scaffold AppBar中;TabBarView声明在scaffold body中;通过DefaultTabController实现联动

即,页面不再直接创建Scaffold组件,而是包裹DefaultTabController
DefaultTabController,同步Tab标签与标签内容的控制器(联动)。在无状态widget使用的控制器,包裹scaffold(中的appbar与body用于联动)

  • length
  • initialIndex,指定初始化时位置。默认0
  • child,Scaffold。包裹页面

AppBar bottom属性,声明使用TabBar

  • tabs,声明Tab集合
  • 其他样式等属性

Tab,标签。一般图标即可

  • icon,标签图标
  • text,标签名称。字符串
  • child,自定义标签。与text不能同时使用

TabBarView,声明在scaffold的body,包裹标签对应的内容

  • children,对应标签的内容

TabBar与TabBarView项的个数必须相同

每一个tab均由,一个标签与一个对应的内容组成。因此抽象成独立的类
创建封装多自定义tab
通过dart集合函数式操作方法,将集合中元素映射为封装新元素的集合
在这里插入图片描述
在这里插入图片描述

PageStorageKey

切换标签时,保存ScrollView(ListView等支持滑动的组件)组件滚动位置
在ScrollView,通过PageStorageKey()方法显式声明key属性值

本地存储的方法

SharedPreferences

https://flutter.cn/docs/cookbook/persistence/key-value

pubspec.yaml添加插件依赖,shared_preferences

shared_preferences,
是整合封装了iOS NSUserDefaults/Android SharedPreferences操作的持久化插件
为简单的基本数据类型提供持久化存储
Android平台,数据以键值对保存在xml文件,文件保存在/data/data/应用包/shared_prefs/

类似于可以置于springboot配置中的键值对数据,非复杂大量的数据

基本数据类型,int/double/bool/string/stringList

SharedPreferences.getInstance(),获取SharedPreferences对象。必须在异步方法中执行

  • getter/setter,对以上基本数据类型的获取/修改操作
  • remove
    在这里插入图片描述
    加载组件时弹出对话框,必须在异步操作中执行
    可以将创建操作置于Future,或异步方法
    Future.delayed(Duration.zero, () {showDialog()})

在这里插入图片描述

对话框

Dialog

https://api.flutter.dev/flutter/material/AlertDialog-class.html

对话框Dialog。透明阴影覆盖,标题栏/内容自带外边距,尽量简洁

AlertDialog。

  • title,标题区。一般为Text
  • content,内容区。可以是复杂的容器
  • elevation,阴影
  • actions [],按钮执行区。默认右对齐,建议使用FlatButton

SimpleDialog。一般没有执行按钮

  • title,标题
  • elevation,阴影
  • children,自定义子项,或SimpleDialogOption

SimpleDialogOption。简单的单选

  • onPressed
  • child
    在这里插入图片描述
    在这里插入图片描述

showDialog

showDialog,是一个函数,但函数也是Function类型。当执行某操作时,点击按钮等,创建showDialog对象

  • context: context,必选参数
  • barrierDismissible,是否允许点击其他关闭对话框
  • builder: (context) {return Widget}。创建对话框
    在这里插入图片描述

close the dialog

showDialog barrierDismissible属性。允许点击非dialog区域关闭,类似web的css+js的实现
Navigator.of(context).pop()。弹出

FlatButton & RaisedButton

FlatButton,文字按钮,一般用于弹出的窗口,ok/cancel/accept等
RaisedButton,凸起悬浮按钮
FlatButton/RaisedButton,均包含child/color/textColor/onPressed等属性

编程题

创建指定样式的Appbar

1.在这里插入图片描述
2.
在这里插入图片描述

AppBar

https://api.flutter-io.cn/flutter/material/AppBar-class.html
https://flutter.cn/docs/catalog/samples/basic-app-bar

应用栏。可通过Scaffold中的appBar属性声明
AppBar是固定高度/布局的,应用栏组件。类似的,提供的常用ListTile组件

  • leading: 一般为图标/按钮图标
  • title: 一般为text
  • actions: [IconButton … PopupMenuButton],标题后的组件集合。一般为常用功能的按钮图标,和缩略不常用功能
  • elevation/centerTitle
  • bottom

Scafford appBar仅接受PreferredSizeWidget类型,不能使用普通的statelesswidget组件
因此,在MyHomePage中通过方法创建AppBar。也可直接继承AppBar;实现PreferredSizeWidget接口等方式实现

可通过PreferredSize嵌套AppBar自定义高度

  • preferredSize: Size.fromHeight(50.0),
  • child

PopupMenuButton

https://api.flutter-io.cn/flutter/material/PopupMenuButton-class.html

PopupMenuButton,弹出式菜单按钮

  • icon,默认为缩略图图标
  • itemBuilder: (context) {return [PopupMenuItem]},创建子项集合的函数。自动注入context对象
  • onSelected (value) {}。PopupMenuButton中的项被选择后回调。注入PopupMenuItem的值

PopupMenuItem

PopupMenuItem,菜单项。不包含点击等回调,仅支持声明数值,当值改变时激活菜单栏onSelected回调函数(后期讨论)

  • value,值
  • child,项,可以是基本text/listtile,或自定义

PopupMenuDivider,item的分割线

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: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: _getAppbar(),
      body: Center(
        child: Text('Context'),
      ),
    );
  }

  _getAppbar() {
    return AppBar(
      leading: Icon(Icons.ac_unit),
      title: Text('My AppBar'),
      actions: <Widget>[
        IconButton(
          icon: Icon(Icons.search),
          onPressed: () {},
        ),
        IconButton(
          icon: Icon(Icons.markunread_mailbox),
          onPressed: () {},
        ),
        _buildPopupMenuButton()
      ],
    );
  }

  PopupMenuButton _buildPopupMenuButton() {
    return PopupMenuButton(
      onSelected: (value) {
      },
      icon: Icon(Icons.menu),
      itemBuilder: (BuildContext context) {
        return [
          PopupMenuItem(
            value: 1,
            child: ListTile(
              leading: Icon(Icons.chat_bubble),
              title: Text('发起群聊'),
            ),
          ),
          PopupMenuItem(
            value: 2,
            child: ListTile(
              leading: Icon(Icons.person_add),
              title: Text('添加朋友'),
            ),
          ),
          PopupMenuItem(
            value: 3,
            child: ListTile(
              leading: Icon(Icons.aspect_ratio),
              title: Text('扫一扫'),
            ),
          ),
          PopupMenuDivider(),
          PopupMenuItem(
            value: 3,
            child: ListTile(
              leading: Icon(Icons.attach_money),
              title: Text('收付款'),
            ),
          ),
        ];
      },
    );
  }
}


创建指定样式的对话框

上文中已经给出

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: <Widget>[
            RaisedButton(
              child: Text('AlertDialog'),
              onPressed: () {
                showDialog(
                    barrierDismissible: false,
                    context: context,
                    builder: (context) {
                      return MyAlertDialog();
                    });
              },
            ),
            RaisedButton(
              child: Text('SimpleDialog'),
              onPressed: () {
                showDialog(
                    context: context,
                    builder: (context) {
                      return MySimpleDialog();
                    });
              },
            )
          ],
        ),
      )
    );
  }
}

/// ------------
class MyAlertDialog extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return AlertDialog(
      title: Row(
        children: <Widget>[
          Container(
              margin: EdgeInsets.only(right: 10),
              child: Icon(Icons.info_outline)),
          Text('AlertDialog')
        ],
      ),
      content: Text('You will never be satisfied.'),
      elevation: 24,
      actions: <Widget>[
        FlatButton(
          child: Text('NO'),
          onPressed: () {Navigator.of(context).pop();},
        ),
        FlatButton(
          child: Text('YES'),
          onPressed: () {},
        )
      ],
    );
  }
}

///
class MySimpleDialog extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return SimpleDialog(
      title: Text('SimpleDialog'),
      elevation: 24,
      children: <Widget>[
        SimpleDialogOption(
          onPressed: () {  },
          child: const Text('Treasury department'),
        ),
        SimpleDialogOption(
          onPressed: () {  },
          child: const Text('State department'),
        ),
      ],
    );
  }

}

创建指定样式的下导航,无需联动

BottomNavigationBar

BottomNavigationBar,在Scafford bottomNavigationBar属性声明
当底部按钮超过3个,无默认颜色,需手动设置

  • type: BottomNavigationBarType.shifting,当多于3个时,显式图标,激活项显式文本,动画。fixed,固定显式图标与文本

  • selectedXXX: 选中项设置。颜色/字体/图标大小等

  • unselectedXXX: Colors.orange,未选中项设置

  • onTap: (int index) {},点击回调函数。注入点击items的索引

  • currentIndex: _currentIndex,动态绑定当前索引

  • items: BottomNavigationBarItem集合
    在这里插入图片描述
    BottomNavigationBarItem,BottomNavigationBar中的具体导航组件子项

  • icon,图标

  • title,文本

  • backgroundColor
    在这里插入图片描述

IndexedStack

在Scafford body声明IndexedStack/PageView容器,响应下导航按钮
创建可以保持状态的有状态组件包裹Scaffold

IndexedStack,基于索引index值,自动加载children中相同位置的组件

  • children,与下导航对应的内容组件集合
  • index,动态绑定应显式的,内容组件集合的索引

联动切换
IndexedStack不支持滑动操作,只能通过BottomNavigationBar实现切换
当点击BottomNavigationBar,获取被点击item的索引位置,通知组件状态更新
IndexedStack基于新索引加载组件

PageView

PageView,与IndexedStack相似的可切换不同内容的容器,默认支持左右滑动与动画效果
PageView.builder()。与ListView.builder()相似

  • initialPage,初始索引
  • itemCount,项的个数
  • itemBuilder(context, index) {return },构建项的函数,注入当前索引
  • onPageChanged(int index) {},切换回调函数。注入当前项的索引

联动切换
BottomNavigationBar/PageView均可切换组件,且通过一种方法切换必须通知另一组件更新
因此,无论通过BottomNavigationBar还是PageView切换,均改变当前显式项的索引
索引改变,BottomNavigationBar自动更新
索引改变,PageView itemBuilder返回响应索引对应的item

基于Provider实现数据绑定与更新

  1. 声明共享式数据:创建计数器类混入了通知类
    在这里插入图片描述
  2. 如何获取共享数据
    这里创建的是可以使用多个ChangeNotifierProvider的providers,
    单独声明ChangeNotifierProvider可以。
    在这里插入图片描述

在这里插入图片描述

Provider

https://flutter.cn/docs/development/data-and-backend/state-mgmt/simple
https://pub.flutter-io.cn/documentation/provider/latest/

pubspec.yaml配置中,添加依赖
点击,pub get,下载获取依赖

由于需要引入依赖,因此不支持dartpad网页调试

Mixin

Mixins are a way of reusing code in multiple class hierarchies
Mixin,混入,是一种在多重继承中复用某个类中代码的方法模式

Dart为单继承,mixin允许在不直接继承另一个类的基础上,借用/复用这个类中的成员(方法/变量等)
A with B
则类A中的成员为AB的集合,重复的取B覆盖

Creating a ChangeNotifier

创建一个类,mixin混入ChangeNotifier,支持通知所有监听者的,可监听类。类的对象为可监听对象
类中封装响应式数据的共享数据
类似于在vuex的state上声明一个响应式数据
vuex可以统一放在一个集合里,但是flutter必须一个一个单独声明

类中封装更新响应式数据的方法,重写getter/setter方法,或单独声明暴露方法。
在方法中调用notifyListeners()方法,通知所有监听者更新

Creating Global Provider

flutter是单页面应用,创建的 MaterialApp 组件不会变动
因此,应用全局Provider,应声明在创建MaterialApp组件对象外层,
即在MyApp组件的build()方法,创建全局Provider

在MyApp组件,声明创建ChangeNotifierProvider

  • create,(context) {return Widget},函数中,创建全局可监听对象
  • child,返回MaterialApp

ChangeNotifierProvider在销毁时自动回调ChangeNotifier dispose()方法,
因此可重写dispose()方法释放共享数据中资源

MultiProvider。全局声明多个Provider

  • providers,集合。声明多个ChangeNotifierProvider

Updating Value

在需要执行更新组件的build()方法,
Provider.of<T>(),获取可监听的共享数据

  • context,
  • listen: false,可选参数。获取的共享数据更新时,当前组件是否重绘。
    当仅需要操作而非消费共享数据时,不监听

Consuming value

Consumer/Consumer6<T>,支持组件同时获取1-6个共享数据

  • builder: (context, ChangeNotifier, child) {return widget},注入了需要消费的共享数据;
    可复用的无需重复渲染的child组件;返回需要绘制的组件

Provider.of<T>(),可仅更新而不消费共享数据。即可以在更新后不重绘组件
Consumer<T>(),共享数据更新,必须重绘组件

Suggestion

建议将需要绑定更新的组件,单独提出创建,挂载

ChangeNotifierProxyProvider

If you want to pass variables to your ChangeNotifier, consider using ChangeNotifierProxyProvider.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => MyCount(),
        )
      ],
      child: MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Expanded(
            child: Center(child: MyContext()),
          ),
          MySlider()
        ],
      ),
    );
  }
}

/// ------------ MySlider
class MySlider extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    final myCount = Provider.of<MyCount>(context);
    return Slider(
      value: myCount.value,
      onChanged: (value) => myCount.value = value,
    );
  }
}

/// ---------- MyContext
class MyContext extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Consumer<MyCount>(
      builder: (context, myCount, child) {
        return Text(
          '${myCount.value}',
          style: TextStyle(fontSize: 40),
        );
      },
    );
  }
}

/// ----------- MyCount
class MyCount with ChangeNotifier {
  double _value = 0.2;

  get value => _value;

  set value(double newValue) {
    _value = newValue;
    notifyListeners();
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值