flutter 实现底部导航栏带未读消息提示

1,201 阅读1分钟

利用stack实现底部导航栏BottomNavigationBarItem里面的icon,初步的实现是利用stack里面的Positioned组件对园点进行定位,部分代码如下

BottomNavigationBarItem(
            icon: Stack(
              children: <Widget>[
                Icon(Icons.message),
                Positioned(
                  top: 5.0,
                  right: 1.0,
                  child: Offstage(
                    offstage: false,
                    child: Container(
                      width: 12.0,
                      height: 12.0,
                      decoration: BoxDecoration(
                        color: Colors.red,
                        shape: BoxShape.circle,
                      ),
                      child: Text(
                        '$_counter',
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          fontSize: 10.0,
                        ),
                      ),
                    ),
                  ),
                )
              ],
            ),
            title: Text('消息'),
          )

效果图如下 微信截图_20200324104438.png

效果不是很理想,因为是stack默认的属性配置所以这样的小圆点只能在icon上方而不能越过边界展示。通过查看stack源码

Stack({
    Key key,
    this.alignment = AlignmentDirectional.topStart,
    this.textDirection,
    this.fit = StackFit.loose,
    this.overflow = Overflow.clip,
    List<Widget> children = const <Widget>[],
  }) : super(key: key, children: children);

其中设置overflow 属性值为Overflow.visible 则超出部分也可显示。

 BottomNavigationBarItem(
            icon: Stack(
              overflow: Overflow.visible,
              children: <Widget>[
                Icon(Icons.message),
                Positioned(
                  top: -5.0,
                  right: -1.0,
                  child: Offstage(
                    offstage: false,
                    child: Container(
                      width: 12.0,
                      height: 12.0,
                      decoration: BoxDecoration(
                        color: Colors.red,
                        shape: BoxShape.circle,
                      ),
                      child: Text(
                        '$_counter',
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          fontSize: 10.0,
                        ),
                      ),
                    ),
                  ),
                )
              ],
            ),
            title: Text('消息'),
          )

效果如下 微信截图_20200324105120.png

完整代码如下

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: 0,
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('首页'),
          ),
          BottomNavigationBarItem(
            icon: Stack(
              overflow: Overflow.visible,
              children: <Widget>[
                Icon(Icons.message),
                Positioned(
                  top: -5.0,
                  right: -1.0,
                  child: Offstage(
                    offstage: false,
                    child: Container(
                      width: 12.0,
                      height: 12.0,
                      decoration: BoxDecoration(
                        color: Colors.red,
                        shape: BoxShape.circle,
                      ),
                      child: Text(
                        '$_counter',
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          fontSize: 10.0,
                        ),
                      ),
                    ),
                  ),
                )
              ],
            ),
            title: Text('消息'),
          )
        ],
      ),
    );
  }
}