Flutter Page 每次在导航弹出时都会重新加载

Posted

技术标签:

【中文标题】Flutter Page 每次在导航弹出时都会重新加载【英文标题】:Flutter Page Keeps reloading every time on navigation pop 【发布时间】:2019-09-05 02:50:03 【问题描述】:

我正在构建一个示例应用程序来使用颤振框架显示新闻列表。该应用程序有两个页面,一个是主页和详细信息页面。当我从详细页面弹出主页时,每次都会重新加载。

我使用 FutureBuilder 小部件来加载新闻并显示为卡片列表,对于详细信息页面,我使用 webview fluggin 进行颤振以从 url 加载完整新闻。

主页面代码为:

import 'package:flutter/material.dart';
import 'package:flutter_post/detail_page.dart';
import 'package:flutter_post/model/news.dart';
import 'package:flutter_post/services/news_services.dart';

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

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter News',
      debugShowCheckedModeBanner: false,
      theme: new ThemeData(primaryColor: Colors.white, fontFamily: 'Raleway'),
      home: NewsPage(title: 'Flutter News'),
    );
  


class NewsPage extends StatefulWidget 
  NewsPage(Key key, this.title) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _NewsPageState createState() => _NewsPageState();


class _NewsPageState extends State<NewsPage> 

  @override
  Widget build(BuildContext context) 
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Align(alignment: Alignment.center, child: Text(widget.title),),
        elevation: 0.1,
        backgroundColor: Colors.white,
      ),
      backgroundColor: Colors.white,
      body: _newsPage(),
    );
  

  Widget _newsPage() 
    return FutureBuilder<News>(
        future: loadNews(), builder: (context, snapshot) 
      switch (snapshot.connectionState) 
        case ConnectionState.none:
        case ConnectionState.waiting:
          return _loadingRow();
        case ConnectionState.done:
          if (snapshot.hasError) 
            return _errorRow();
          
          return _newsList(snapshot.data.articles);
        case ConnectionState.active:
      
    );
  

  Widget _newsList(List<Article> articles) 
    return ListView.builder(itemCount: articles.length,
        itemBuilder: (BuildContext context, int index) 
          return InkWell(child: Card(
            elevation: 8.0,
            clipBehavior: Clip.antiAlias,
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(5.0))),
            margin: EdgeInsets.only(left: 15.0, right: 15.0, bottom: 15.0),
            child: _cardItem(articles[index]),),
            onTap: () 
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) =>
                          DetailPage(article: articles[index],)));
            ,);
        );
  

  Widget _errorRow() 
    return Align(alignment: Alignment.center,
      child: Text(
          "Error!", style: _textStyle(Colors.black38, FontWeight.bold, 20.0)),);
  

  Widget _cardItem(Article article) 
    return new Container(
      height: 250.0,
      child: new Stack(
        children: <Widget>[
          _cardBackground(article),
          _cardContent(article)
        ],
      ),
    );
  

  Widget _cardBackground(Article article) 
    return new Container(
      decoration: new BoxDecoration(
        image: new DecorationImage(
            colorFilter: new ColorFilter.mode(
                Colors.black.withOpacity(0.6),
                BlendMode.luminosity),
            image: new NetworkImage(
                article.urlToImage != null ? article.urlToImage : null),
            fit: BoxFit.cover
        ),
      ),
    );
  

  Widget _cardContent(Article article) 
    return new Align
      (child: Container(
      alignment: Alignment.bottomCenter,
      padding: EdgeInsets.all(10),
      child: new Column(mainAxisAlignment: MainAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Flexible(child: new Text(article.title, maxLines: 2,
              style: _textStyle(Colors.white, FontWeight.bold, 20.0)),),
          Padding(padding: EdgeInsets.only(top: 5.0),),
          Flexible(child: new Text(publishedBy(article),
            style: _textStyle(Colors.white, FontWeight.w400, 12.0),),)
        ],
      ),
    ), alignment: Alignment.bottomLeft,
    );
  

  String publishedBy(Article article) 
    return "published by " + article.source.name;
  

  TextStyle _textStyle(Color color, FontWeight weight, double size) 
    return TextStyle(color: color, fontWeight: weight, fontSize: size);
  

  Widget _loadingRow() 
    return Align(
      alignment: Alignment.center, child: CircularProgressIndicator(),);
  

详细页面代码为:

import 'package:flutter/material.dart';
import 'package:flutter_post/model/news.dart';
import 'package:share/share.dart';
import 'package:webview_flutter/webview_flutter.dart';

class DetailPage extends StatelessWidget 
  final Article article;

  DetailPage(this.article);

  void shareUrl() 
    Share.share('Read the full news from ' + article.url);
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        leading: new InkWell(
          onTap: () 
            Navigator.pop(context);
          ,
          child: new Icon(Icons.close, color: Colors.black),),
        elevation: 0.1,
        title: new Text(article.url),
        backgroundColor: Colors.white,
      ),
      body: WebView(initialUrl: article.url,),
      floatingActionButton: FloatingActionButton(
        child: new Icon(Icons.share, color: Colors.white),
        onPressed: shareUrl,),
    );
  

我想要的是,每次我从详细信息页面返回时,主页不应该刷新/重新加载。非常感谢任何帮助。

【问题讨论】:

我想实现每次从详细页面返回时主页不应该加载。 您无法对Widget 的重建次数做出任何假设 嗨,@pskink 我解决了这个问题,方法是将列表保留在外面,并在未来的构建器小部件上设置条件,无论列表是否为空。 【参考方案1】:

我想我知道你的问题的答案。

    _NewsPageState 中创建一个新闻状态/对象 使用 initState 加载您的数据loadNews()FutureBuilder&lt;News&gt; 中引用未来对象

示例代码:

class _NewsPageState extends State<NewsPage> 

  Future<News> _myNews;

  @override
  void initState() 
    _myNews = loadNews();
  

  ...

  Widget _newsPage() 
    return FutureBuilder<News>(
      future: _myNews,
      builder: (context, snapshot) 
        ...
      
    );
  

  ...
 

希望对你有帮助:)

你的 Glup3

【讨论】:

这无济于事,因为您无法在 initState 中执行异步函数; 你可以执行它。但你不能等待它。一旦你在initState() 中执行loadNews(),它会给你一个未来。这样一来,将使用之前获得的相同未来,而不是在每次调用 build() 时都获得一个新未来。

以上是关于Flutter Page 每次在导航弹出时都会重新加载的主要内容,如果未能解决你的问题,请参考以下文章

每次更改页面时都会调用 React useEffect (with []) (React Router)

【急!】每次刚打开MyEclipse时都会出现问题 导致无法使用【在线等答案】

每次设置状态时都会调用 Flutter 函数

如何在 Flutter 中弹出时清除页面

每次刷新应用程序时都会触发 Flutter web Firebase onAuthStateChanges

我想创建 chrome 扩展,每次 youtube 播放视频时都会弹出