根据当前查看的页面更改 AppBar 的颜色和文本

Posted

技术标签:

【中文标题】根据当前查看的页面更改 AppBar 的颜色和文本【英文标题】:Changing the color and text of AppBar based on the currently viewed page 【发布时间】:2017-07-26 12:36:44 【问题描述】:

我有一个 TabBarView 可以在我的应用程序的页面之间导航。有没有办法根据当前查看的页面更改/覆盖主 AppBar 的文本和颜色,而不是为每个页面分别创建一个 AppBar?

这就是我的页面的设置方式

我的路由在main函数中定义如下:

routes: <String, WidgetBuilder>
            "/Home": (BuildContext context) => new first.Home(),
            "/Support": (BuildContext context) => new second.Support(),

          

标签类

        class Tabs extends StatefulWidget 

          @override
          TabsState createState() => new TabsState();
        

    class TabsState extends State<Tabs> with SingleTickerProviderStateMixin 
      TabController controller;

      @override
      void initState() 
        super.initState();

        controller = new TabController(length: 5, vsync: this);

      

      @override
      void dispose() 
        controller.dispose();
        super.dispose();

      
      @override
      Widget build(BuildContext context) 

      return new Scaffold(
        appBar: new AppBar(
          centerTitle: true,
          title: new Text('App'), backgroundColor: Colors.blue,
          bottom: new TabBar(
              controller: controller,
              tabs: <Tab>[
                new Tab (icon: new Icon(Icons.home), text: 'Home',),
                            new Tab (icon: new Icon(Icons.mail), text:'Support'),
              ]),
        ),
        body: new TabBarView(
          controller: controller,
          children: <Widget>[
            new first.Home(),
            new second.Support(),

          ],
        ),
      );
          

【问题讨论】:

【参考方案1】:

如果您使用PageView 而不是TabBarView,您可以指定一个onPageChanged 函数,该函数允许您更改状态,从而重建小部件。

这是我正在处理的一些代码,应用栏中的标题已更改,但概念基本相同:

// Copyright 2017 <Abhi Agarwal>
// Refer to LICENSE

// Dart Imports

// Flutter Imports
import 'package:flutter/material.dart';

// Package Imports
import 'package:shared_preferences/shared_preferences.dart'
    show SharedPreferences;

// Local Imports
import '../calendar/calendar_view.dart' show CalendarView;
import '../error/error_screen.dart' show ErrorScreen;
import '../homework/homework_view.dart' show HomeworkView;
import '../loading/loading_screen.dart' show LoadingScreen;

import 'page.dart' show Page;

class MainView extends StatefulWidget 
  MainView(Key key, this.initialIndex = 0, SharedPreferences prefs)
      : pages = _makePagesList(prefs),
        super(key: key);
  final int initialIndex;
  final List<Page> pages;

  static List<Page> _makePagesList(SharedPreferences prefs) => <Page>[
        CalendarView.page(),
        new Page(
          page: new ErrorScreen(error: "Hello World"),
          title: "Schedule",
          iconData: Icons.schedule,
        ),
        HomeworkView.page(),
        new Page(
          page: new LoadingScreen(),
          title: "Settings",
          iconData: Icons.settings,
        ),
      ];

  @override
  _MainViewState createState() => new _MainViewState();


class _MainViewState extends State<MainView> 
  PageController _controller;
  int _index;

  @override
  void initState() 
    super.initState();
    _controller = new PageController(initialPage: widget.initialIndex);
    _index = widget.initialIndex;
  

  @override
  void dispose() 
    super.dispose();
    _controller.dispose();
  

  void _handlePageChange(int index) => setState(() => _index = index);

  void _navigateToPage(int index) => _controller.animateToPage(
        index,
        duration: const Duration(milliseconds: 300),
        curve: Curves.ease,
      );

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(
          widget.pages[_index].title,
          style: new TextStyle(
            fontFamily: Theme.of(context).textTheme.title.fontFamily,
          ),
        ),
        backgroundColor: Theme.of(context).primaryColor,
      ),
      bottomNavigationBar: new BottomNavigationBar(
        type: BottomNavigationBarType.shifting,
        items: widget.pages
            .map((Page page) => new BottomNavigationBarItem(
                  icon: new Icon(
                    page.iconData,
                    color: Theme.of(context).primaryColor,
                  ),
                  title: new Text(
                    page.title,
                    style: new TextStyle(
                      color: Theme.of(context).primaryColor,
                    ),
                  ),
                  backgroundColor: Theme.of(context).canvasColor,
                ))
            .toList(),
        onTap: _navigateToPage,
        currentIndex: _index,
      ),
      floatingActionButton: widget.pages[_index].useFab
          ? new FloatingActionButton(
              tooltip: widget.pages[_index].tooltip,
              child: widget.pages[_index].fab,
              onPressed: () => widget.pages[_index].onPressed(context),
            )
          : null,
      body: new PageView(
        controller: _controller,
        children: widget.pages.map((Page page) => page.page).toList(),
        onPageChanged: _handlePageChange,
      ),
    );
  

【讨论】:

我不明白 Page 类到底是做什么的? 这个方法还有什么作用? CalendarView.page() 不要担心页面类,它只是为每个“页面”保存一些数据。 CalendarView.page() 是一个静态方法,返回我为 CalendarView 创建的页面。 对不起,我有点困惑。我没有看到您将页面设置为路线,我只有两个页面要在它们之间导航,您能否向我展示一个使用 PageView 的更简化示例以便理解? 我的错,我误解了你的问题。【参考方案2】:

我修改了这段代码以添加对文本和颜色更改的支持

https://flutter.io/catalog/samples/tabbed-app-bar/

对于代码的丑陋,我深表歉意。我所做的只是将所有类更改为有状态小部件,添加一个 setstate 图标选择器,更改小部件以便有一个 onPressed 回调

  import 'package:flutter/material.dart';

  class MainApp extends StatefulWidget 
    MainApp(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
    TabbedAppBarSample createState() => new TabbedAppBarSample();
  
  class TabbedAppBarSample extends State<MainApp> 
    Choice _choice;
    initState()
      super.initState();
      _choice = choices[0];
    
    void _select(var c)
      setState(()
        _choice = c;
      );

    

    @override
    Widget build(BuildContext context) 
      return new MaterialApp(
        home: new DefaultTabController(

          length: choices.length,
          child: new Scaffold(
            appBar: new AppBar(
              //dynamically create appbar colors
              backgroundColor: new Color(_choice.color),
              title: new Text(_choice.title),
              bottom: new TabBar(
                isScrollable: true,
                tabs: choices.map((Choice choice) 
                   //change to iconbutton
                  return new IconButton(
                    icon: new Icon(choice.icon),
                    onPressed: ()_select(choice);,
                  );
                ).toList(),
              ),
            ),
            body:
            new TabBarView(
              children: choices.map((Choice choice) 
                return new Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: new ChoiceCard(choice: choice),
                );
              ).toList(),
            ),
          ),
        ),
      );
    
  

  class Choice 
    const Choice( this.title, this.icon, this.color);
    final String title;
    final IconData icon;
    final num color;
  

  const List<Choice> choices = const <Choice>[
    const Choice(title: 'CAR', icon: Icons.directions_car, color:  0xFFE0F7FA),
    const Choice(title: 'BICYCLE', icon: Icons.directions_bike, color: 0x00ff0000),
    const Choice(title: 'BOAT', icon: Icons.directions_boat, color: 0xFF42A5F5),
    const Choice(title: 'BUS', icon: Icons.directions_bus, color: 0x0),
    const Choice(title: 'TRAIN', icon: Icons.directions_railway, color: 0xFFEFFFFF),
    const Choice(title: 'WALK', icon: Icons.directions_walk, color: 0x0000ff00),
  ];
  class ChoiceCard extends StatefulWidget 
    ChoiceCard(Key key, this.choice) : super(key: key);
    final Choice choice;
    @override
    _ChoiceCard createState() => new _ChoiceCard();
  
  class _ChoiceCard extends State<ChoiceCard> 


    @override
    Widget build(BuildContext context) 
      final TextStyle textStyle = Theme.of(context).textTheme.display1;

      return new Card(
        color: Colors.white,
        child: new Center(
          child: new Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              new Icon(widget.choice.icon, size: 128.0, color: textStyle.color),
              new Text(widget.choice.title, style: textStyle),
            ],
          ),
        ),
      );
    
  

  void main() 
    runApp(new MainApp());
  

我有点恼火,因为我上面的代码与操作所需的实际答案相似。我上面的代码和 op 想要的唯一区别是我将 on 更改添加到 tabcontroller 而不是按钮本身

这里是代码

 import 'package:flutter/material.dart';
 void main() 
   runApp(new MyApp());
 
 class MyApp extends StatelessWidget
   Widget build(BuildContext context) 
     return new MaterialApp(
       title: 'Nothing',
       theme: new ThemeData(
         primarySwatch: Colors.blue,
       ),
       home: new Tabs(),
     );
   

 
 class Tabs extends StatefulWidget 
   @override
   TabsState createState() => new TabsState();
 
 class TabsState extends State<Tabs> with SingleTickerProviderStateMixin 
   TabController controller;
   //create internal state
   Choice _choice;
   @override
   void initState() 
     super.initState();
     //try to make the length to
     controller = new TabController(length: 5, vsync: this);
     //add listener to add change index callback
     //https://docs.flutter.io/flutter/material/TabController-class.html
     controller.addListener(_select);
     _choice = choices[0];

   
   @override
   void dispose() 
     controller.dispose();
     super.dispose();
   

   void _select()
     setState(()
       _choice = choices[controller.index];
     );

   
   @override
   Widget build(BuildContext context) 
     return new Scaffold(
         appBar: new AppBar(
           centerTitle: true,
           title: new Text(_choice.title), backgroundColor: new Color(_choice.color),
           bottom: new TabBar(
               controller: controller,
               tabs: <Tab>[
                 new Tab( icon: new Icon(choices[0].icon), text: 'Home',),
                 new Tab (icon: new Icon(choices[1].icon), text:'Support'),
               ]),
         ),
         body: new TabBarView(
           controller: controller,
           children: <Widget>[
             //dummy page
             new MyHomePage(),
             new  Center( child: new Text('dummy page 2')),

           ],
         ),
     );
   
 
 class Choice 
   const Choice( this.title, this.icon, this.color);
   final String title;
   final IconData icon;
   final num color;
 
 //create a list
 const List<Choice> choices = const <Choice>[
   const Choice(title: 'Home', icon: Icons.home, color:  0x0),
   const Choice(title: 'Support', icon: Icons.mail, color: 0xFF42A5F5),

 ];


 class MyHomePage extends StatefulWidget 
   @override
   _MyHomePageState createState() => new _MyHomePageState();
 
 class _MyHomePageState extends State<MyHomePage> 
   @override
   Widget build(BuildContext context) 
     return new Center(
       child: new Text('dummy page'),
     );
   
 

【讨论】:

这与定义路线和导航到它们有何不同,每个选择都被视为实际路线/页面吗? 下一次,写下你正在使用导航和路由类来浏览你的页面。如果您想要量身定制的解决方案,我有点需要查看您的代码。我刚刚使用标签栏示例向您展示了如何通过设置全局父状态来更改材质颜色。每个 ChoiceCard 都是一个小部件,但如果您愿意,它可以像一个新页面一样工作。您只需要更改 ChoiceCard 类并添加 case 语句以返回构建中的页面。如果您使用的是 tabbar 小部件,您可以通过设置 state 来更改 onpressed 回调以找出您当前所在的页面 嗯,我更新了我的代码。我的代码和你需要的代码差别不大。我添加了一些额外的行,以便您可以构建它并查看 感谢先生的大力帮助。【参考方案3】:

只需通过 if-else 检查或切换选项卡的当前索引并执行您的操作

switch (_tabController.index) 
              case 0:
                // Do something for Tab 1
                break;
              case 1:
                // Do something for Tab 1
                break;
              case 2:
                // Do something for Tab 1
                break;
              case 3:
                // Do something for Tab 1
                break;
              case 4:
                // Do something for Tab 1
                break;
            

每次对应用栏进行更改时,您都需要执行此检查。 这可能不是最好的方法,但确实有效。

【讨论】:

以上是关于根据当前查看的页面更改 AppBar 的颜色和文本的主要内容,如果未能解决你的问题,请参考以下文章

更改 Google Place Picker Appbar 文本颜色

Flutter:不使用AppBar时如何在Android和iOS上更改状态栏文本颜色[重复]

如何更改 Material-UI AppBar 的明暗主题颜色?

如何在 Ios 上更改状态栏文本颜色

Flutter-如何在深色模式下更改状态栏文字颜色?

无法在 AppBar 上更改颜色