Flutter初学者之普通底部导航栏及自定义不规则底部导航栏的实现

5,030 阅读4分钟

 2020年,在这个不平凡的一年里,作为一名Android开发者,随着Flutter高热度的来临,深深体会到了Android市场的饱和,更何况我这种懒得要死菜狗子,只能被迫学习,于是近日学习了Flutter,准备做一些功能性的Flutter项目,一方面便于学习,另一方面也便于自己后期对Flutter项目的开发,狗哥写的文章适合初学者及其想快速上手的同胞们学习参考,废话少说,今天我们一起来制作APP的底部导航栏吧!

普通底部导航栏

首先请先看效果图 

废话不多说上代码

我们首先看下main.dart代码

void main() {
  runApp(MyApp());
}

///自定义组件 StatelessWidget(无状态组件)
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter底部导航栏",
      home: Scaffold(
        // appBar: AppBar(
        //   title: Text("Flutter底部导航栏"),
        // ),  
        bottomNavigationBar: BottomNavigationWidget(),
      ),
      theme: ThemeData.light(),
    );
  }
}

main( )方法是Flutter 程序的主入口 ,MaterialApp 组件一般配合 Scaffold 组件一起使用,一般主要是用来搭建APP 的框架,比如AppBar , BottmNavigationBar 等,这里我们主要做底部导航栏;Scaffold 组件中有自带的 bottomNavigationBar 属性就是用来设置底部导航栏的,这里我们去自定义一个组件,其实就相当于写一个类,然后在类里面去去实现底部导航栏的操作,最终赋值在 bottomNavigationBar 这个属性上,因为 Flutter 中万物皆为组件,也称为Flutter开发为组件式开发,这里我们自定义了 BottomNavigationWidget 组件

以下是我们自定义的 BottomNavigationWidget 组件代码。

import 'package:flutter/material.dart';
import 'bottom_navigation/home_screen.dart';
import 'bottom_navigation/email_screen.dart';
import 'bottom_navigation/pages_screen.dart';
import 'bottom_navigation/airplay_screen.dart';

///底部导航栏制做,
class BottomNavigationWidget extends StatefulWidget {
  @override
  _BottomNavigationWidgetState createState() => _BottomNavigationWidgetState();
}

class _BottomNavigationWidgetState extends State<BottomNavigationWidget> {
  ///定义底部导航栏字体的颜色
  final _BottomNavigationColor = Colors.blue;
  ///需要点击的item索引
  int _currentIndex = 0;
  ///定义装有 4 个页面组件用到的 List ,所以范型用的 Widget
  List<Widget> mList = List();

  ///重写StatefulWidget抽象类中的initState()方法,用于初始化的操作
  @override
  void initState() {
    ///使用 List 的 ..add()方法,写法比逐个去 mList.add()要简单
    mList
      ..add(HomeScreen())
      ..add(EmailScreen())
      ..add(PagesScreen())
      ..add(AirplayScreen());
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: mList[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        ///这是添加的4个item
        items: [          BottomNavigationBarItem(
              icon: Icon(
                Icons.home,
                color: _BottomNavigationColor,
              ),
              title: Text(
                "home",
                style: TextStyle(color: _BottomNavigationColor),
              )),
          BottomNavigationBarItem(
              icon: Icon(
                Icons.email,
                color: _BottomNavigationColor,
              ),
              title: Text(
                "email",
                style: TextStyle(color: _BottomNavigationColor),
              )),
          BottomNavigationBarItem(
              icon: Icon(
                Icons.pages,
                color: _BottomNavigationColor,
              ),
              title: Text(
                "pages",
                style: TextStyle(color: _BottomNavigationColor),
              )),
          BottomNavigationBarItem(
              icon: Icon(
                Icons.airplay,
                color: _BottomNavigationColor,
              ),
              title: Text(
                "airplay",
                style: TextStyle(color: _BottomNavigationColor),
              ))
        ],
        ///item的索引赋值
        currentIndex: _currentIndex,
        ///item点击事件
        onTap: (int index) {
          setState(() {
            ///当前索引等于点击后的item索引
            _currentIndex = index;
          });
        },
      ),
    );
  }
}

因为我们需要定义的组件是可变化的,所以我们继承了 StatefulWidget 组件 ,这里简单说下StatelessWdiget组件和 StatefulWidget 组件的区别。

  • StatelessWdiget 组件:无状态的组件,复用某种组件。
  • StatefulWidget 组件:有状态的组件,数据处理,逻辑处理。

这里我们就把一般App 使用的底部导航栏功能实现了,顺便还带有选中之后放大的效果。

自定义不规则底部导航栏

老规矩,先上效果图

一般我们做APP的都知道,很多APP 底部导航栏采用这样的样式,如果用原生开发还是比较费劲的,但是用Flutter 开发还是很便捷的,原理大概就是将 Flutter 中的 FloatActionButton 悬浮按钮融合到底部导航栏中去实现,上代码!

这里我们还是采用刚开始那段入口代码,只是我们的 bottomNavigationBar 属性实现的组件我们去单独定义,将这个自定义底部导航栏的功能单独写一个组件。

import 'dart:ui';
import 'package:flutter/material.dart';
import 'flutter/BottomAppBarDemo.dart';
import 'flutter/BottomNavigationWidget.dart';
import 'study/study.dart';

void main() {
  runApp(MyApp());
}

///自定义组件 StatelessWidget(无状态组件)
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter底部导航栏",
      home: Scaffold(
        // appBar: AppBar(
        //   title: Text("Flutter底部导航栏"),
        // ),
        ///自定义的BottomAppBarDemo组件
        bottomNavigationBar: BottomAppBarDemo(),
      ),
      theme: ThemeData.light(),
    );
  }
}

来我们看自定义的 BottomAppBarDemo 组件。

import 'package:flutter/material.dart';
import 'bottom_navigation/each_view.dart';

///自定义不规则底部导航栏
class BottomAppBarDemo extends StatefulWidget {
  @override
  _BottomAppBarDemoState createState() => _BottomAppBarDemoState();
}

class _BottomAppBarDemoState extends State<BottomAppBarDemo> {
  List<Widget> _eachView;
  int _index = 0;

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

    _eachView = List();
    _eachView
      ..add(EachViewState("Home"))
      ..add(EachViewState("email"))
      ..add(EachViewState("pages"))
      ..add(EachViewState("airplay"));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _eachView[_index],
      floatingActionButton: FloatingActionButton(
        ///响应事件,push 生成新的页面,即点击中间的按钮跳转的页面
        onPressed: () {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (BuildContext context) {
            return EachViewState("这是新的页面");
          }));
        },

        ///长按
        tooltip: "狗哥最帅",
        child: Icon(
          Icons.add,
          color: Colors.white,
        ),
      ),
      bottomNavigationBar: BottomAppBar(
        color: Colors.white,
        shape: CircularNotchedRectangle(),
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            IconButton(
              icon: Icon(Icons.home),
              color: Colors.blue,
              onPressed: () {
                setState(() {
                  //手动赋值索引
                  _index = 0;
                });
              },
            ),
            IconButton(
              icon: Icon(Icons.email),
              color: Colors.blue,
              onPressed: () {
                setState(() {
                  _index = 1;
                });
              },
            ),
            IconButton(
              icon: Icon(Icons.av_timer),
              color: Colors.blue,
              onPressed: () {
                setState(() {
                  _index = 2;
                });
              },
            ),
            IconButton(
              icon: Icon(Icons.dashboard),
              color: Colors.blue,
              onPressed: () {
                setState(() {
                  _index = 3;
                });
              },
            )
          ],
        ),
      ),

      ///将FloatActionButton 与 BottomAppBar 融合到一起
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}

这里主要用到的 FloatActionButton 组件与底部导航栏融合的代码为:

  ///将FloatActionButton 与 BottomAppBar 融合到一起
  floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

这就是 Flutter 中两种不同的底部导航栏功能的实现,以后狗哥将不定时间发文 Flutter  各种功能的实现及其原理,写到这里已是深夜,大佬们看到这里,如果觉得不错也可以支持下狗哥,给狗哥的文章点个 star ,毕竟这是狗哥的第一偏 Flutter 文章!代码如果有不合理的地方也可以指出来互相交流!