如何从 StreamBuilder 访问快照?

How to access Snapshot out of the StreamBuilder?

我正在使用 BLOC 从 API 中获取电影。我能够访问 StreamBuilder 小部件内的 bloc,但我在 AppBar[=] 上也有一个 share 按钮 23=] 需要 movie.slug 来显示共享选项。但由于 AppBar 不在 StreamBuilder 中,我无法共享 link。 AppBar 是否可以访问 StreamBuilder Snapshot?

这是页面代码:

import 'package:cinemax_app/src/blocs/movie_bloc.dart';
import 'package:cinemax_app/src/components/movie/movie_header.dart';
import 'package:cinemax_app/src/models/movie.dart';
import 'package:flutter/material.dart';
import 'package:share/share.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';

class MoviePage extends StatefulWidget {
  final int movieId;

  MoviePage({ this.movieId });

  @override
  _MoviePageState createState() => _MoviePageState();
}

class _MoviePageState extends State<MoviePage> {
  MovieModel _movie;

  @override
  Widget build(BuildContext context) {
    movieBloc.fetchMovie(widget.movieId);

    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            StreamBuilder(
              stream: movieBloc.movie,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  _movie = snapshot.data as MovieModel;

                  return ListView(
                    children: <Widget>[
                      MovieHeader(movie: _movie),
                      Container(
                        padding: EdgeInsets.only(top: 45, bottom: 15, left: 15, right: 15),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text('Sinopse:', style: Theme.of(context).textTheme.title),
                            HtmlWidget(
                              _movie.sinopsis,
                              bodyPadding: EdgeInsets.only(top: 15),
                              textStyle: TextStyle(color: Colors.grey),
                            )
                          ],
                        ),
                      )
                    ]
                  );
                }

                return Center(child: CircularProgressIndicator());
              },
            ),
            AppBar(
              backgroundColor: Colors.transparent,
              elevation: 0.0,
              actions: <Widget>[
                PopupMenuButton(
                  icon: Icon(Icons.more_vert),
                  itemBuilder: (BuildContext context) {
                    return <PopupMenuItem>[
                      PopupMenuItem(
                        child: GestureDetector(
                          child: Text('Partilhar'),
                          onTap: () {
                            final movieSLug = _movie.slug;

                            // prints: 'https://cinema.com/movie/null';
                            final movieAddress = 'https://cinema.com/movie/${movieSLug}';

                            Share.share(movieAddress);
                          },
                        ),
                      )
                    ];
                  },
                )
              ],
            ),
          ]
        ),
      ),
    );
  }
}

我做错了什么?

您可以摆脱 Stack 并使 StreamBuilder 成为 Scaffold 的父级,这样包括应用栏在内的整个 Scaffold 都可以访问快照。

像这样

class MoviePage extends StatefulWidget {
  final int movieId;

  MoviePage({this.movieId});

  @override
  _MoviePageState createState() => _MoviePageState();
}

class _MoviePageState extends State<MoviePage> {
  MovieModel _movie;

@override
  void initState() {
    super.initState();
    movieBloc.fetchMovie(widget.movieId);
  }

  @override
  Widget build(BuildContext context) {
    movieBloc.fetchMovie(widget.movieId);

    return StreamBuilder(
      stream: movieBloc.movie,
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          _movie = snapshot.data as MovieModel;

          return Scaffold(
            appBar:  AppBar(
              backgroundColor: Colors.transparent,
              elevation: 0.0,
              actions: <Widget>[
                PopupMenuButton(
                  icon: Icon(Icons.more_vert),
                  itemBuilder: (BuildContext context) {
                    return <PopupMenuItem>[
                      PopupMenuItem(
                        child: GestureDetector(
                          child: Text('Partilhar'),
                          onTap: () {
                            final movieSLug = _movie.slug;

                            // prints: 'https://cinema.com/movie/null';
                            final movieAddress = 'https://cinema.com/movie/${movieSLug}';

                            Share.share(movieAddress);
                          },
                        ),
                      )
                    ];
                  },
                )
              ],
            ),
            body: SafeArea(
              child: ListView(children: <Widget>[
                MovieHeader(movie: _movie),
                Container(
                  padding:
                      EdgeInsets.only(top: 45, bottom: 15, left: 15, right: 15),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Text('Sinopse:',
                          style: Theme.of(context).textTheme.title),
                      HtmlWidget(
                        _movie.sinopsis,
                        bodyPadding: EdgeInsets.only(top: 15),
                        textStyle: TextStyle(color: Colors.grey),
                      )
                    ],
                  ),
                )
              ]),
            ),
          );
        }

        return Center(child: CircularProgressIndicator());
      },
    );
  }
}