Flutter学习日记Flutter圈子

Flutter 学习笔记 10 - 路由和导航(2)

2019-01-05  本文已影响5人  三流之路

返回数据

如果要返回数据,pop 方法还有一个重载方法,有个可选的位置参数,用于传递返回的数据。

static bool pop<T extends Object>(BuildContext context, [ T result ]) {
  return Navigator.of(context).pop<T>(result);
}

比如 Navigator.pop(context, "返回内容");,然后将 push 放到异步函数里,返回值就是其它页面返回的 result。

class FirstScreen extends StatelessWidget {

  // 异步函数
  _toSecond(BuildContext context) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => SecondScreen(title: "标题", content: "内容")),
    );
    
    // 等待页面返回,数据存为 result
    print('result=$result');
    Scaffold.of(context)
      ..removeCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text("$result")));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('content'),
          onPressed: () {
            _toSecond(context);
          },
        ),
      ),
    );
  }
}

结果日志打印出来了,但是 SnackBar 未显示,看错误日志以及官网有效的代码,发现要把 FirstScreen 这个 widget 放到 Scaffold 的 body 位置才行,SnackBar 的 Scaffold.of(context) 参数有问题。

尝试将 FirstScreen 改成 StatefulWidget。

class FirstScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return FirstState();
  }
}

class FirstState extends State<FirstScreen> {
  int count = 0;
  var content = 'content';
  _toSecond(BuildContext context) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => SecondScreen(title: "标题", content: "内容${++count}")), // 每次传递的内容有变化
    );

    // 当从其它页面返回时,重新设置 content 以让当前页面发生变化
    setState(() {
      content = result;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: RaisedButton(
          // 使用 content 变量内容,从其它页面返回时会发生变化
          child: Text('$content'),
          onPressed: () {
            _toSecond(context);
          },
        ),
      ),
    );
  }
}

然后修改 SecondScreen,返回传进来的值。

class SecondScreen extends StatelessWidget {
  final String title;
  final String content;

  // 构造方法接收两个参数
  SecondScreen({Key key, @required this.title, @required this.content}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            // 返回传进来的内容
            Navigator.pop(context, "返回$content");
          },
          child: Text(content),
        ),
      ),
    );
  }
}
2019_01_05_10_32_54.gif

通过给 route 命名来跳转

MaterialApp(
  // initialRoute 表示当前要显示的内容
  initialRoute: '/',
  routes: {
    // 根路径表示 FirstScreen
    '/': (context) => FirstScreen(),
    '/second': (context) => SecondScreen(),
  },
);

测试发现必须要在 MaterialApp 里用,initialRoute 表示要显示的内容,不允许写 home 了

页面跳转时使用

Navigator.pushNamed(context, '/second');
// 代替下面的写法
// Navigator.push(
//   context,
//   MaterialPageRoute(builder: (context) => FirstScreen()),
// );

返回依然用 Navigator.pop 方法。

在不同页面对一个 Widget 做动画

类似 Android 的转场动画

将两个页面都要显示的 Widget 用 Hero 这个 Widget 包裹一层。

Hero(
  tag: 'imageHero',
  child: Image.network(
    'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
  ),
);

在两个页面 tag 必须一样,child 是要做动画的内容。

class MainScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Main Screen'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: 'imageHero',
          child: Image.network(
            'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
          ),
        ),
        onTap: () {
          Navigator.push(context, MaterialPageRoute(builder: (_) {
            return DetailScreen();
          }));
        },
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        child: Center(
          child: Hero(
            tag: 'imageHero',
            child: Image.network(
              'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
            ),
          ),
        ),
        onTap: () {
          Navigator.pop(context);
        },
      ),
    );
  }
}

第一个页面中图片在上边,到了第二个页面,图片到了中间。

2019_01_05_18_17_27.gif

修改第二个页面的图片大小

child: Hero(
  tag: 'imageHero',
  child: Container(
    height: 100,
    margin: const EdgeInsets.symmetric(horizontal: 10.0),
    child: Image.network(
      'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
    ),
  )
),
2019_01_05_18_22_01.gif
上一篇下一篇

猜你喜欢

热点阅读