Flutter 项目实战 底部导航 六

/ 生活中常部分app底部导航样式 /

        从智能手机的普及我们的生活 , 手机已经为我们生活提供了方便 . 购买手机后系统默认安装了很多款app , 随便点开一款手机app 进入应用首页映入眼帘的就是底部导航 . 可以说手机app为我们生活提供了方便 , 同时app里面的底部导航为我们更好的使用应用 . 市面上的app底部导航切换样式都差不多 (分底部Tab 导航栏 和 舵式导航栏) .  点击底部导航选项可以切换到不同功能模块的 , 让用户在使用的时候更加清楚要导航的功能 .

底部Tab(今日头条&微信&美团&网易云音乐)

舵式导航栏(微博&闲鱼)

/ app底部导航构造 /

导航选项纯图标

 

  

 导航纯文本

 

 导航图文混排

/ Flutter 实现底部导航 /

BottomNavigationBarItem

服务于 BottomNavigationBar . 包括属性icon (选项图标)、title (选项包括文本的widget被弃用)、label (导航栏文本值)、backgroundColor、tooltip (长按时选项顶部弹出提示 , 长按选项时选项样式不会发生改变)

 在flutter sdk 大于1.19.0的版本上使用该参数 , 抛出如下异常 : 

backgroundColor  选项有渐变和移动效果状态下的背景颜色

BottomNavigationBar 参数 BottomNavigationBarType 是 BottomNavigationBarType.shifting 生效. 会覆盖导航栏BottomNavigationBar背景颜色 . 访问B站查看效果

tooltip 长按选项弹出提示 访问B站查看效果

BottomNavigationBar

底部导航 可以自定义 选项文本、图标样式 . 长按点击弹出提示 . 可以使用flutter自带的icon 切换图标的样式 .

 items / BottomNavigationBarItem 集合

 flutter自带的Icon

class StartPage extends StatefulWidget {
  StartPage({Key? key, this.title}) : super(key: key);

  final String? title;

  @override
  _StartPageState createState() => _StartPageState();
}

class _StartPageState extends State<StartPage> {
  GlobalKey<StackWState> _stackGk = GlobalKey<StackWState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        bottomNavigationBar: BotNavBar(
          stackValue: (int currentIndex, List<int> tabInt) {
            _stackGk.currentState!.changeStack(currentIndex, tabInt);
          },
        ),
        body: StackWidget(
          key: _stackGk,
        ));
  }
}
import 'package:flutter/cupertino.dart';
import 'package:flutter_bottom_navigator/base/presenter/IPresenter.dart';
import 'package:flutter_bottom_navigator/base/view/BaseView.dart';
import 'package:flutter_bottom_navigator/base/view/IView.dart';

class StackWidget extends BaseView {
  final int? currentIndex;
  final List<int>? tabInt;

  StackWidget({this.currentIndex, this.tabInt, Key? key}) : super(key: key);

  @override
  BaseViewState<IPresenter<IView>, BaseView> getState() {
    return StackWState();
  }
}

class StackWState extends BaseViewState<IPresenter, StackWidget> {
  int _currentIndex = 0;
  List<int>? _tabInt;

  final List<Widget> _children = [
    Center(
      child: Text('Page1'),
    ),
    Center(
      child: Text('Page2'),
    ),
  ];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _tabInt = widget.tabInt == null ? [0] : widget.tabInt;
  }

  void changeStack(int currentIndex, List<int> tabInt) {
    setState(() {});
    _currentIndex = currentIndex;
    _tabInt = tabInt;
  }

  //Page的显示和隐藏
  _child(int _index) {
    return Offstage(
      offstage: !(_currentIndex == _index),
      child: _tabInt!.contains(_index) ? _children[_index] : Container(),
    );
  }

  @override
  buildWidget() {
    // TODO: implement buildWidget
    return Stack(
      children: <Widget>[
        _child(0),
        _child(1),
      ],
    );
  }
}
import 'package:flutter/material.dart';

class BotNavBar extends StatefulWidget {
  final ValueChanged? stackValue;

  BotNavBar({Key? key, this.stackValue}) : super(key: key);

  @override
  _BotNavBarState createState() => _BotNavBarState();
}

class _BotNavBarState extends State<BotNavBar> {
  List<int> tabInt = [0];
  int _currentIndex = 0;

  late var _tabImages;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _tabImages = [
      _singleTabImage('home'),
      _singleTabImage('type'),
      _singleTabImage('mine'),
    ];
  }

  BottomNavigationBarItem _singleBotNavItem(_index) {
    return BottomNavigationBarItem(
        icon: _getTabIcon(
          _index,
        ),
        backgroundColor: Colors.red,
        tooltip: '$_index tooltips',
        //title: Text('$_index title'),
        label: '$_index label');
  }

  _singleTabImage(_labelPng) {
    return [
      Icon(Icons.message),
      Icon(Icons.message),
    ];
  }

  Widget _getTabIcon(int curIndex) {
    if (curIndex == _currentIndex) {
      return _tabImages[curIndex][0];
    }
    return _tabImages[curIndex][1];
  }

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      onTap: _onTabTapped,
      currentIndex: _currentIndex,
      backgroundColor: Colors.white,
      selectedItemColor: Colors.blue,
      unselectedItemColor: Color(0xffAFB1BD),
      elevation: 6.0,
      selectedIconTheme: IconThemeData(color: Colors.green),
      unselectedIconTheme: IconThemeData(color: Colors.red),
      selectedLabelStyle: TextStyle(inherit: true),
      //fixedColor: Colors.blue,
      showUnselectedLabels: true,
      showSelectedLabels: true,
      mouseCursor: SystemMouseCursors.move,
      enableFeedback: false,
      items: [
        _singleBotNavItem(0),
        _singleBotNavItem(1),
      ],
    );
  }

  _onTabTapped(int index) {
    setState(() {});
    _currentIndex = index;
    if (!tabInt.contains(index)) {
      tabInt.add(index);
    }
    if (widget.stackValue != null) {
      widget.stackValue!(_currentIndex, tabInt);
    }
  }
}

typedef ValueChanged = void Function(
  int currentIndex,
  List<int> tabInt,
);

 自定义Icon

 

创建assets 文件夹来存储要读取的自定义图标

 在 pubspec.yaml 文件里面配置图片的依赖

  _singleTabImage(_labelPng) {
    return [
      Image.asset(
        'assets/${_labelPng}_b_select.png',
        width: 40.0,
        height: 40.0,
      ),
      Image.asset(
        'assets/${_labelPng}_b_normal.png',
        width: 40.0,
        height: 40.0,
      )
    ];
  }

elevation / 导航栏阴影Z坐标

 

selectedLabelStyle / unselectedLabelStyle

导航栏选中文本的样式 (字体颜色、背景颜色、字体权重、字体阴影 、…...) 

导航栏选中文本的样式 (字体颜色、背景颜色、字体权重、字体阴影 、……)

showSelectedLabels / showUnselectedLabels

是否显示选中时的文本 /  是否显示未选中时的文本

 

GlobalKey 实现导航局部刷新

StartPage 包含了 内容区域  (StackWidget) 和底部导航 (BotNavBar) . 当首次进入应用时 , 会渲染内容容区域和底部导航 . 当我们需要切换其它导航时 , 要做到切换导航重新渲染内容区域和底部导航而不执行内容区域和底部导航的父控件StartPage的build函数,需要用到GlobalKey来实现点击导航刷新内容区域而不执行StartPage的build函数 .

class _StartPageState extends State<StartPage> {
  GlobalKey<StackWState> _stackGk = GlobalKey<StackWState>();

  @override
  Widget build(BuildContext context) {
    print('StartPage _build');
    return Scaffold(
        bottomNavigationBar: BotNavBar(
          stackValue: (int currentIndex, List<int> tabInt) {
            _stackGk.currentState!.changeStack(currentIndex, tabInt);
          },
        ),
        body: StackWidget(
          key: _stackGk,
        ));
  }
}

 

flutter_bottom_navigator 案例下载

  • 137
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

️ 邪神

你自己看着办,你喜欢打赏我就赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值