Flutter MaterialPageRoute 导航到黑色背景的屏幕时如何解决?

Posted

技术标签:

【中文标题】Flutter MaterialPageRoute 导航到黑色背景的屏幕时如何解决?【英文标题】:How to solve it when Flutter MaterialPageRoute navigates to a screen with black background? 【发布时间】:2020-05-01 09:19:51 【问题描述】:

我第一次在我的一个项目中使用 Flutter,它是一个报纸应用程序。

当我尝试使用我的Drawer 中的MaterialPageRoutemain.dart 导航到newsfeed_for_other_category.dart 时出现问题。在该屏幕中,它显示新闻,但背景为黑色。但在我的main.dart 正文中调用的屏幕newsfeed_screen.dart 中,它完美显示。

我在下面发布代码。

ma​​in.dart

import 'package:flutter/material.dart';
import './SizeConfig.dart';
import './screens/newsfeed_screen.dart';
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
import 'factory/widget_factory.dart';
import 'widgets/top_news_widget.dart';
import 'package:splashscreen/splashscreen.dart';
import './widgets/drawer.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: 'Newspaper App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        //backgroundColor: Colors.lightGreenAccent,
      ),
      home: MyHomePage(title: 'The Business Standard'),
      routes: <String, WidgetBuilder> 
        '/screen1': (BuildContext context) => new NewsFeedScreen(216, 5, "Top News"),
        '/screen2' : (BuildContext context) => new NewsFeedScreen(4, 7, "National"),
        '/screen3' : (BuildContext context) => new NewsFeedScreen(13, 70, "International"),
        /*'/screen4' : (BuildContext context) => new Screen4()*/
      ,
    );
  


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

  final String title;

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


class _MyHomePageState extends State<MyHomePage> 
  int _counter = 0;
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: '_MainScreenKey');

  Widget build(BuildContext context) 
    return SplashScreen(
        seconds: 3,
        navigateAfterSeconds: AfterSplash(),
        title: Text(
          'The Business Standard',
          style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 20.0
          ),
        ),
        image: Image.asset(
            'assets/TBS_logo.jpg',
        ),
        backgroundColor: Colors.white,
        styleTextUnderTheLoader: TextStyle(),
        photoSize: 100.0,
        onClick: ()=>print("Flutter Egypt"),
        loaderColor: Colors.red
    );
  


class AfterSplash extends StatefulWidget 

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


class _AfterSplashState extends State<AfterSplash> 
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: '_MainScreenKey');

  @override
  Widget build(BuildContext context) 
    SizeConfig().init(context);
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        backgroundColor: Colors.white,
        title: Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Image.asset(
              'assets/TBS.png',
              fit: BoxFit.cover,
              height: 45,
            )
          ],
        ),
        leading: IconButton(
          icon: Icon(Icons.dehaze),
          color: Colors.black,
          onPressed: () => _scaffoldKey.currentState.openDrawer(),
        ),
      ),
      drawer: SideDrawer(),
      body: NewsFeedScreen(22, 71, "Sports"),
      bottomNavigationBar: CurvedNavigationBar(
        backgroundColor: const Color(0xFF2b4849),
        items: <Widget>[
          Icon(Icons.bookmark, size: 30,),
          Icon(Icons.perm_identity, size: 30,),
          Icon(Icons.settings, size: 30,),
        ],
        onTap: (index) 
          if(index == 2) 
            _scaffoldKey.currentState.showSnackBar(const SnackBar(
                content: const Text('Will open Settings menu')));
           else if(index == 0) 
            _scaffoldKey.currentState.showSnackBar(const SnackBar(
                content: const Text('Implement Bookmark function')));
           else 
            _scaffoldKey.currentState.showSnackBar(const SnackBar(
                content: const Text('Will show User profile and information')));
          
        ,
      ),
    );
  


newsfeed_for_other_category.dart,我正在导航的页面,这是黑色背景显示的地方。

import 'package:flutter/material.dart';
import '../SizeConfig.dart';
import '../widgets/headlines.dart';
import '../widgets/secondary_headlines.dart';
import '../widgets/listed_news.dart';
import '../models/NewsPost.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:developer';
import '../screens/newsPost_details.dart';
import '../screens/newsfeed_for_specific_category.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import '../transition_animation_routes/ScaleTransitionRoute.dart';
import '../widgets/top_news_widget.dart';

class NewsfeedForOtherCategory extends StatefulWidget 
  int categoryId;
  int childrenCategoryId;
  String categoryName;

  NewsfeedForOtherCategory(this.categoryId, this.childrenCategoryId, this.categoryName);
  @override
  _NewsfeedForOtherCategoryState createState() => _NewsfeedForOtherCategoryState(this.categoryId, this.childrenCategoryId, this.categoryName);


class _NewsfeedForOtherCategoryState extends State<NewsfeedForOtherCategory> 
  int categoryId;
  int childrenCategoryId;
  String categoryName;

  _NewsfeedForOtherCategoryState(this.categoryId, this.childrenCategoryId, this.categoryName);

  bool _isRequestSent = false;
  List<NewsPost> newsPostList = [];

  @override
  Widget build(BuildContext context) 
    SizeConfig().init(context);

    if(!_isRequestSent) 
      _sendRequest();
    

    return Container(
      alignment: Alignment.center,
      child: !_isRequestSent
          ? CircularProgressIndicator()
          : Container(
        child: ListView.builder(
            itemCount: newsPostList.length,
            scrollDirection: Axis.vertical,
            itemBuilder: (BuildContext context, int index) 
              return _getNewsPostWidgets(index);
            
        ),
      ),
    );
  

  void _sendRequest() async 
    String url = "https://tbsnews.net/json/category/news/"+this.categoryId.toString()+"/"+this.childrenCategoryId.toString()+"";
    http.Response response = await http.get(url);
    List<dynamic> decode = json.decode(response.body);
    log('response: $response');
    List results = decode[0]['items'];
    for (var jsonObject in results) 
      var post = NewsPost.getNewsPostFromAPI(jsonObject);
      newsPostList.add(post);
      print(post);
    
    setState(() => _isRequestSent = true);
  

  Widget _getNewsPostWidgets(int index) 
    var newsPost = newsPostList[index];

    if(index < this.newsPostList.length) 
      if(index == 0) 
        return GestureDetector(
            onTap: () 
              Navigator.push(
                  context,
                  ScaleTransitionRoute(
                      page: NewsPostDetails(newsPostList, index)
                  )
              );
            ,
            child: Column(
              children: <Widget>[
                Container(
                  padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
                  //constraints: BoxConstraints(minWidth: double.infinity, maxWidth: double.infinity),
                  constraints: BoxConstraints.expand(
                      width: double.infinity,
                      height: 40
                  ),
                  color: const Color(0xFF2b4849),
                  child: Text(
                    this.categoryName,
                    style: TextStyle(
                        fontSize: 33,
                        color: Colors.white
                    ),
                  ),
                ),
                BlockHeadline(newsPost)
              ],
            )
        );
      
      else 
        return GestureDetector(
          onTap: () 
            Navigator.push(
                context,
                ScaleTransitionRoute(
                    page: NewsPostDetails(newsPostList, index)
                )
            );
          ,
          child: ListedNews(newsPost),
        );
      
    
    else 
      return Container(
        color: const Color(0xFF2b4849),
        child: index == 3 ? FlatButton(
          child: Text(
            "Load More",
            style: TextStyle(
                color: Colors.white
            ),
          ),
          onPressed: () 
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => NewsFeedForSpecificCategory(newsPostList)
                )
            );
          ,
        ) : Container(),
      );
    
  

  openNewsPostDetails(List<NewsPost> newsPostList, int index) 
    Navigator.push(
        context,
        ScaleTransitionRoute(
            page: NewsPostDetails(newsPostList, index)
        )
    );
  

drawer.dart

import 'package:flutter/material.dart';
import '../SizeConfig.dart';
import '../screens/newsfeed_for_other_category.dart';

class SideDrawer extends StatelessWidget 

  @override
  Widget build(BuildContext context) 
    SizeConfig().init(context);
    return SizedBox(
      width: SizeConfig.safeBlockHorizontal*50,
      child: Theme(
        data: Theme.of(context).copyWith(canvasColor: const Color(0xFF2b4849)),
        child: Drawer(
          child: ListView(
            children: <Widget>[
              ListTile(
                title: Text(
                  'Top News',
                  style: TextStyle(
                      fontSize: 20,
                      color: Colors.white
                  ),
                ),
                onTap: () 
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (BuildContext context) => NewsfeedForOtherCategory(216, 5, "Top News")
                      )
                  );
                ,
              ),
            ],
          ),
        ),
      ),
    );
  

在我的主屏幕中,在main.dart 中的AfterSplashState 小部件的主体中调用newsfeed_screen.dart,如下所示,这就是它应该的样子。

但是在我使用drawer 导航到的屏幕NewsfeedForOtherCategory 中看起来像下面的黑色背景。

我也尝试使用Navigator.of(context, rootNavigator: true).pushNamed('/route')pushReplacementNamed() 代替MaterialPageRoute。但是没用。

这是我找到的相关question,我尝试了他们提供的解决方案,但对我不起作用。

还要提一下,我正在导航的页面没有 MaterialApp 小部件,只有 main.dart 有它。所以应该没有问题。

我使用的是 Ubuntu 16.04 机器。

你的一些线索将是无价的。非常感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

NewsfeedForOtherCategory 页面是黑色的,因为它没有 Material 容器。 您可以简单地用Material 小部件或Scaffold(它具有一些附加功能,如抽屉、浮动操作按钮)来包装它。

从您的屏幕截图中,我可以看到通知栏溢出了一些小部件。您可以在MaterialScaffoldbody 内部使用SafeArea 来克服这个问题。

【讨论】:

非常感谢您对实际问题的解释。干杯!【参考方案2】:

用脚手架将主容器包裹在NewsfeedForOtherCategory 中,您就有了解决方案。

    ...
    return Scaffold(
      body: Container(
          alignment: Alignment.center,
          child: !_isRequestSent
              ? CircularProgressIndicator()
              : Container(
            child: ListView.builder(
                itemCount: newsPostList.length,
                scrollDirection: Axis.vertical,
                itemBuilder: (BuildContext context, int index) 
                  return _getNewsPostWidgets(index);
                
            ),
          ),
        );
    );
    ...

【讨论】:

非常感谢你的朋友!向你致敬:-D【参考方案3】:

在 NewsfeedForOtherCategory 小部件的构建功能中, 试着把你有的东西包在一个脚手架里。 喜欢:

    return Scaffold(
              body: Container(
                alignment: Alignment.center,
                child: !_isRequestSent
                    ? CircularProgressIndicator()
                    : Container(
                        child: ListView.builder(
                            itemCount: newsPostList.length,
                            scrollDirection: Axis.vertical,
                            itemBuilder: (BuildContext context, int index) 
                              return _getNewsPostWidgets(index);
                            ),
                      ),
              ),
            ),

【讨论】:

【参考方案4】:

当我们在两个屏幕之间导航时,两个屏幕父级都应该是支架

如果你不想使用脚手架,你也可以使用容器颜色属性

尝试将您的容器包装在 NewsfeedForOtherCategory 屏幕中的脚手架中 像这样

...
 @override
  Widget build(BuildContext context) 
    return Scaffold(
              body: Container(
               
              ),
            );

...

或者你可以像这样设置容器颜色为白色

...
 @override
  Widget build(BuildContext context) 
    return  Container(
               color: Colors.white,
            child: 
            //enter code here
             
            );

...

【讨论】:

以上是关于Flutter MaterialPageRoute 导航到黑色背景的屏幕时如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Flutter 中的通知导航到应用程序中的特定 MaterialPageRoute

在 Flutter 中的 MaterialPageRoute 之后尝试 showDialogue 时出现“'context != null': is not true”错误?

Flutter MaterialPageRoute 不会在原生 iOS navigatorViewController 上导航

Flutter:类型 'Future<dynamic>' 不是类型 'Widget' 的子类型 // MaterialPageRoute<dynamic>(null))

flutter页面跳转 Route 使用汇总

Flutter 页面路由过渡动画