在Flutter中如何样式化BottomNavigationBar

111

我正在尝试使用Flutter,并试图更改应用中BottomNavigationBar的颜色,但我只能实现更改BottomNavigationItem(图标和文本)的颜色。

以下是我声明BottomNavigationBar的地方:

class _BottomNavigationState extends State<BottomNavigationHolder>{

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: null,
      body: pages(),
      bottomNavigationBar:new BottomNavigationBar(
        items: <BottomNavigationBarItem>[
          new BottomNavigationBarItem(
              icon: const Icon(Icons.home),
              title: new Text("Home")
          ),
          new BottomNavigationBarItem(
              icon: const Icon(Icons.work),
              title: new Text("Self Help")
          ),
          new BottomNavigationBarItem(
              icon: const Icon(Icons.face),
              title: new Text("Profile")
          )
        ],
        currentIndex: index,
        onTap: (int i){setState((){index = i;});},
        fixedColor: Colors.white,
      ),
    );
  }

早些时候,我曾试图通过在我的主应用程序主题中将canvasColor编辑为绿色来解决问题,但它却破坏了整个应用程序的颜色方案。

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        canvasColor: Colors.green
      ),
      home: new FirstScreen(),
    );
  }
}

我也想改变底部导航栏的很多东西,最终我只是复制了所有底部导航栏的代码并更改了我想要的内容。我想这就是Flutter的主要优点之一,即开放性和易于操作。我做了这个:https://pbs.twimg.com/media/DPkoxKWX0AEg9tF.jpg:large - Rene
13个回答

159

无法直接指定BottomNavigationBar的背景颜色,但可以更改canvasColor来达到目的。一种不会影响整个应用程序的实现方法是将BottomNavigationBar包装在具有所需canvasColorTheme中。

示例:

  bottomNavigationBar: new Theme(
    data: Theme.of(context).copyWith(
        // sets the background color of the `BottomNavigationBar`
        canvasColor: Colors.green,
        // sets the active color of the `BottomNavigationBar` if `Brightness` is light
        primaryColor: Colors.red,
        textTheme: Theme
            .of(context)
            .textTheme
            .copyWith(caption: new TextStyle(color: Colors.yellow))), // sets the inactive color of the `BottomNavigationBar`
    child: new BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      currentIndex: 0,
      items: [
        new BottomNavigationBarItem(
          icon: new Icon(Icons.add),
          title: new Text("Add"),
        ),
        new BottomNavigationBarItem(
          icon: new Icon(Icons.delete),
          title: new Text("Delete"),
        )
      ],
    ),
  ),

非常感谢您,先生。完美地解决了问题。您知道如何更改底部导航栏上未激活图标的颜色吗? - spongyboss
4
实际上,残障色是从textThemecaption中提取的。我已经更新了我的答案,以展示如何实现它。希望这有所帮助! - Hemanth Raj
@WitVault 你可以在底部导航栏后面叠加一个渐变容器,并使底部导航栏具有透明颜色。我自己没有尝试过,希望你能试一试。 - Hemanth Raj
为什么类型转换无法正常工作?你会如何进行主题设置? - dmorawetz
将类型更改为固定类型可以解决所有问题。无需包装在主题小部件或任何其他东西中。与主题相关的属性已经在底部导航小部件中可用,因此您不需要Theme小部件。 - jashgopani
显示剩余4条评论

142

BottomNavigationBar 可以是固定的或者移动的(切换)。

如果有3项则为固定状态,4项或更多项目则变为移动状态。我们可以通过设置BottomNavigationBar.type参数来覆盖此行为。

  • 固定的 BottomNavigationBar

    输入图像描述

BottomNavigationBar(
  type: BottomNavigationBarType.fixed, // Fixed 
  backgroundColor: Colors.black, // <-- This works for fixed
  selectedItemColor: Colors.greenAccent,
  unselectedItemColor: Colors.grey,
  items: [
    BottomNavigationBarItem(
      icon: Icon(Icons.call),
      label: 'Call',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.message),
      label: 'Message',
    ),
  ],
)

  • BottomNavigationBar 进行位移:

    enter image description here

BottomNavigationBar(
  type: BottomNavigationBarType.shifting, // Shifting
  selectedItemColor: Colors.white,
  unselectedItemColor: Colors.grey,
  items: [
    BottomNavigationBarItem(
      icon: Icon(Icons.call),
      label: 'Call',
      backgroundColor: Colors.blue, // <-- This works for shifting
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.message),
      label: 'Message',
      backgroundColor: Colors.green, // <-- This works for shifting
    ),
  ],
)

可以了,谢谢。顺便提醒一下,在BottomNavigationBarItem中别忘了移除图标颜色。 - DomonLee
这应该是被接受的答案。 - Simran Sharma

85

被接受的答案并不完全正确。然而,BottomNavigationBar确实有一个名为backgroundColor的属性。根据文档说明:

如果类型为BottomNavigationBarType.shifting,并且项目具有BottomNavigationBarItem.backgroundColor设置,则项目的背景颜色将溅泼并覆盖此颜色。

这意味着BottomNavigation的背景颜色将被各个项目的背景色覆盖,因为默认类型是BottomNavigationBarType.shifting

要解决这个问题,只需要在声明的BottomNavigationbar小部件中添加以下属性。

type: BottomNavigationBarType.fixed,

注意:如果您确实想要移动效果,您将需要为每个项目声明颜色,或者包装允许覆盖子小部件背景颜色的小部件。

例如像Container小部件。


1
我将 type: BottomNavigationBarType.shifting 更改为 type: BottomNavigationBarType.fixed。这对我有用,谢谢。 - Wilmer
1
我遇到了一个问题,当我添加了4个子元素后,backgroundColor会自动更改为白色。将navBar类型设置为fixed后,它停止了自动更改。 - KingJinho

19

如果类型固定,可以通过设置backgroundColor属性来更改颜色。

BottomNavigationBar(
          backgroundColor: Colors.red,
          type: BottomNavigationBarType.fixed,
          items: [
            BottomNavigationBarItem(
                icon:Icon(Icons.home, color: Color.fromARGB(255, 255, 255, 255)),
                title: new Text('Home'),),
            BottomNavigationBarItem(
                icon: Icon(Icons.work,color: Color.fromARGB(255, 255, 255, 255)),
                title: new Text('Self Help'),),
            BottomNavigationBarItem(
                icon:Icon(Icons.face, color: Color.fromARGB(255, 255, 255, 255)),
                title: new Text('Profile'),),
          ]
        )

如果类型正在转换,它会在bottomNavigationBarItem内使用颜色。

BottomNavigationBar(
          backgroundColor: Colors.red,
          type: BottomNavigationBarType.shifting,
          items: [
            BottomNavigationBarItem(
                icon:Icon(Icons.home, color: Color.fromARGB(255, 255, 255, 255)),
                title: new Text('Home'),
                backgroundColor: Colors.red),
            BottomNavigationBarItem(
                icon: Icon(Icons.work,color: Color.fromARGB(255, 255, 255, 255)),
                title: new Text('Self Help'),
                backgroundColor: Colors.blue),
            BottomNavigationBarItem(
                icon:Icon(Icons.face, color: Color.fromARGB(255, 255, 255, 255)),
                title: new Text('Profile'),
                backgroundColor: Colors.amber),
          ]

        )

尽管我已经设置了backgroundColor属性,但它并没有应用该颜色,BottomNavigationBarItem widget内的背景色会覆盖它。

源自这里


title现已被弃用,建议使用label代替,并且label接受一个字符串作为参数。 - MSpeed

12

设置以下属性可更改背景选中未选中颜色

bottomNavigationBar: BottomNavigationBar(
        backgroundColor: Colors.blue,
        selectedItemColor: Colors.black,
        unselectedItemColor: Colors.white,
        type: BottomNavigationBarType.fixed,
        ...
)

1
类型:BottomNavigationBarType.fixed,这个属性非常重要。 - herbert ichama

10

您可以直接从Theme中设置BottomNavigationBar的样式,例如:

ThemeData(
    bottomNavigationBarTheme: BottomNavigationBarThemeData(
        backgroundColor: Colors.grey[900],
        elevation: 10,
        selectedLabelStyle: TextStyle(
            color: Color(0xFFA67926), fontFamily: 'Montserrat', fontSize: 14.0
        ),
        unselectedLabelStyle: TextStyle(
            color: Colors.grey[600], fontFamily: 'Montserrat', fontSize: 12.0
        ),
        selectedItemColor: Color(0xFFA67926),
        unselectedItemColor: Colors.grey[600],
        showUnselectedLabels: true,
    ),
)

这是使用主题的正确方法。谢谢! - falconforce

6

title已被废弃。现在我们使用label代替。
对于label,我们可以使用相应的属性:selectedLabelStyle, unselectedLabelStyle
例如:

bottomNavigationBar: BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          selectedItemColor: Theme.of(context).accentColor,
          selectedFontSize: 0,
          unselectedFontSize: 0,
          iconSize: 22,
          elevation: 0,
          backgroundColor: Colors.transparent,
          selectedIconTheme: IconThemeData(size: 28),
          unselectedItemColor: Theme.of(context).focusColor.withOpacity(1),
          selectedLabelStyle: Theme.of(context).textTheme.bodyText1.merge(TextStyle(fontSize: 12)),
          unselectedLabelStyle: Theme.of(context).textTheme.button.merge(TextStyle(fontSize: 11)),
          showUnselectedLabels: true,
          currentIndex: widget.currentTabIdx,
          onTap: (int i) {
            this._selectTab(i);
          },
          showSelectedLabels: true,
          // this will be set when a new tab is tapped
          items: [
            BottomNavigationBarItem(
              icon: SvgPicture.asset(IMAGE_ASSETS_ICONS_HOME) ,
              activeIcon: SvgPicture.asset(IMAGE_ASSETS_ICONS_HOME, color: Theme.of(context).accentColor),
              label: 'Home',
            ),
            BottomNavigationBarItem(
                label: 'Categories',
              icon: SvgPicture.asset(IMAGE_ASSETS_ICONS_CATEGORY),
              activeIcon: SvgPicture.asset(IMAGE_ASSETS_ICONS_CATEGORY, color: Theme.of(context).accentColor) ,
            ),
            BottomNavigationBarItem(
              icon: SvgPicture.asset(IMAGE_ASSETS_ICONS_ORDER_HISTORY, ) ,
              activeIcon: SvgPicture.asset(IMAGE_ASSETS_ICONS_ORDER_HISTORY, color: Theme.of(context).accentColor ) ,
              label: 'Order History',
            ),
            BottomNavigationBarItem(
              icon: SvgPicture.asset(IMAGE_ASSETS_ICONS_CART,) ,
              activeIcon: SvgPicture.asset(IMAGE_ASSETS_ICONS_CART, color: Theme.of(context).accentColor) ,
              label: 'Cart',
            ),
          ],

这正是我正在寻找的确切答案。我想要为标签设置样式,使用了这个答案后,我成功做到了。 - Noah

4

只需按照下面给出的代码根据您的需求自定义即可。您只需要使用Theme将NavigationBar的父级设置,然后设置canvasColor以更改背景颜色。

      bottomNavigationBar: Theme(
    data: Theme.of(context).copyWith(
      canvasColor: kOrangeMaterialColor
    ),
    child: BottomNavigationBar(
      type: BottomNavigationBarType.shifting,
      currentIndex: _currentIndex,
      onTap: _onTapItem,

      items: [
        BottomNavigationBarItem(icon: Icon(Icons.home,
        color: kWhiteColor,),
        label: ''),
        BottomNavigationBarItem(icon: Icon(Icons.notifications,
        color: kWhiteColor,),
        label: ''),
        // BottomNavigationBarItem(icon: Icon(Icons.favorite_border,
        // color: kWhiteColor,),
       // label: ''),
        BottomNavigationBarItem(icon: Icon(Icons.account_circle,
        color: kWhiteColor,),
        label: ''),
        BottomNavigationBarItem(icon: Icon(Icons.settings,
        color: kWhiteColor,),
        label: ''),
      ],
    ),
  ),

4
尝试将BottomNavigationBar包装在Container中,然后设置其color
示例:
@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: pages(),
      bottomNavigationBar:new Container(
        color: Colors.green,
        child: BottomNavigationBar(
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
                icon: const Icon(Icons.home),
                title: Text("Home")
            ),
            BottomNavigationBarItem(
                icon: const Icon(Icons.work),
                title: Text("Self Help")
            ),
            BottomNavigationBarItem(
                icon: const Icon(Icons.face),
                title: Text("Profile")
            )
          ],
        currentIndex: index,
        onTap: (int i){setState((){index = i;});},
        fixedColor: Colors.white,
        ),
      );
    );
  };

如果您只是将其设置为null,请不要设置appBar。它可能具有默认值。 - Alex Jone

3
你可以使用以下代码:
BottomNavigationBar (
backgroundColor: Colors.red,
type: BottomNavigationBarType.fixed
)

或者使用Theme小部件包装BottomNavigation并更改canvasColor

Theme(
    data: Theme.of(context).copyWith(canvasColor: Colors.green),
    child: BottomNavigationBar(
      // add your code ...
        )
      ],
    ),
  ),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接