拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Flutter 项目实战 底部导航 六

Flutter 项目实战 底部导航 六

白鹭 - 2022-03-25 2112 0 0

/ 生活中常部分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 案例下载

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *