Flutter实现底部菜单栏+页面切换(BottomNavigationBar+PageVIew)

需求:实现底部主页+我的两个菜单栏,实现和页面联动点击/滑动切换

需求:底部实现两个菜单 首页+我的,和页面实现滑动/点击切换联动

1:底部菜单栏?第一时间就想到了 Scaffold部件的属性 bottomNavigationBar,

bottomNavigationBar的实现需要 
BottomNavigationBar:需要实现 items,接受的是 BottomNavigationBarItem(属性 tips:icon 菜单图标,title 菜单名字),这里我们需要两个两个菜单,那么就实现两个 BottomNavigationBar。如下:
bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(
               Icons.home,
                Colors.grey,
            ),
            title: Text(
              "Banner",
              style:
                  TextStyle(color:   Colors.grey  ),
            ),
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.contact_mail,
              color:   Colors.grey,
            ),
            title: Text(
              "Icon",
              style:
                  TextStyle(color:  Colors.grey  ),
            ),
          ),
        ]

这里有一个问题,菜单的图标和名字颜色点击要高亮区别怎么办?我们要实现两个页面,那么已知总数量=2,那不是可以根据索引来区别设置高亮么?所以 定义一个当前索引变量。

int current = 0;

菜单代码根据索引切换渲染高亮/默认:

bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(
              current != 0 ? Icons.home_outlined : Icons.home,
              color: current == 0 ? Colors.orange : Colors.grey,
            ),
            title: Text(
              "首页",
              style:
                  TextStyle(color: current != 0 ? Colors.grey : Colors.orange),
            ),
          ),
          BottomNavigationBarItem(
            icon: Icon(
              current != 1 ? Icons.contact_mail_outlined : Icons.contact_mail,
              color: current == 1 ? Colors.orange : Colors.grey,
            ),
            title: Text(
              "我的",
              style:
                  TextStyle(color: current != 1 ? Colors.grey : Colors.orange),
            ),
          ),
        ]

运行之后发现,点击菜单无改变?稍等~因为我们没有加点击事件处理啊,

BottomNavigationBar里面已经提供一个 onTap给我们了,返回一个当前点击了那个菜单的索引。让我们来实现它:
 onTap: (position) {
          setState(() {
            current = position;
          });
        }

这里加了一个引用 setState,用于通知改变。到了这一步,我们已经实现了菜单的点击切换高亮/默认了,还剩下最后一步,和页面的联动.

2:ViewPage联动? 我们先来实现 PageView,这里需要用到三个属性 

controller 控制器 用与控制初始化切换那个页面
scrollDirection 方向  Axis.horizontal 横向  纵向 vertical
children 存放实现的页面内容,这里我们需要创建两个即可
onPageChanged 页面滑动事件,返回当前页面索引,同步更新上文定义的 current即可和菜单联动.

具体代码如下:

body: Padding(
          padding: EdgeInsets.all(15),
          child: PageView(
            controller:coller ,
            scrollDirection: Axis.horizontal,
            children: [
              ClipRRect(
                  borderRadius: BorderRadius.circular(15),
                  child: GestureDetector(
                    child: Opacity(
                        opacity: 0.3,
                        child: Image(
                          image: AssetImage("images/me_record.jpeg"),
                          fit: BoxFit.cover,
                        )),
                    onTap: () {
                      print('当前头像是本人~');
                    },
                  )),
              PhysicalModel(
                  color: Colors.orange,
                  borderRadius: BorderRadius.circular(15),
                  child: Column(
                    children: [
                      Image.network(
                          "https://www.baidu.com/img/flexible/logo/pc/result.png"),
                      Padding(
                        padding: EdgeInsets.only(left: 10, top: 10, right: 10),
                        child: Center(
                          child: Text(
                            "纵里寻他千百度,暮然回首,那人却在灯火阑珊处~~~",
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      )
                    ],
                  )),
            ],
            onPageChanged: (position) {
              setState(() {
                current = position;
              });
            },
          ),
        ));

运行之后,发现菜单点击后 页面跟着联动了,但是 页面滑动,菜单没跟着联动?为什么?

问题在于 菜单的 ontap事件处理,虽然更新了 current ,但是并没有告知PageView切换到指定页面啊,所以需要使用它的控制器,告知 我们切换了菜单,页面需要跟着改动,如下图:
 

 coller.animateToPage(current, duration: Duration(milliseconds:200), curve: Curves.ease);

控制器的 

animateToPage 需要三个参数 索引 时间  曲线

完整代码如下:
 

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

class PageFUl_ extends StatefulWidget {
  @override
  _PageFUlState createState() => _PageFUlState();
}

class _PageFUlState extends State<PageFUl_> {
  int current = 0;
  PageController coller;
  @override
  void initState() {

    super.initState();
    coller  =  PageController(initialPage: current);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text("功能切换页面"),
          leading: GestureDetector(
            onTap: () {
              Navigator.pop(context);
            },
            child: Icon(Icons.arrow_back),
          ),
        ),
        bottomNavigationBar: BottomNavigationBar(
          items: [
            BottomNavigationBarItem(
              icon: Icon(
                current != 0 ? Icons.home_outlined : Icons.home,
                color: current == 0 ? Colors.orange : Colors.grey,
              ),
              title: Text(
                "首页",
                style: TextStyle(
                    color: current != 0 ? Colors.grey : Colors.orange),
              ),
            ),
            BottomNavigationBarItem(
              icon: Icon(
                current != 1 ? Icons.contact_mail_outlined : Icons.contact_mail,
                color: current == 1 ? Colors.orange : Colors.grey,
              ),
              title: Text(
                "我的",
                style: TextStyle(
                    color: current != 1 ? Colors.grey : Colors.orange),
              ),
            ),
          ],
          onTap: (position) {
            setState(() {
              current = position;
              coller.animateToPage(current, duration: Duration(milliseconds:200), curve: Curves.ease);
            });
          },
        ),
        body: Padding(
          padding: EdgeInsets.all(15),
          child: PageView(
            controller:coller ,
            scrollDirection: Axis.horizontal,
            children: [
              ClipRRect(
                  borderRadius: BorderRadius.circular(15),
                  child: GestureDetector(
                    child: Opacity(
                        opacity: 0.3,
                        child: Image(
                          image: AssetImage("images/me_record.jpeg"),
                          fit: BoxFit.cover,
                        )),
                    onTap: () {
                      print('当前头像是本人~');
                    },
                  )),
              PhysicalModel(
                  color: Colors.orange,
                  borderRadius: BorderRadius.circular(15),
                  child: Column(
                    children: [
                      Image.network(
                          "https://www.baidu.com/img/flexible/logo/pc/result.png"),
                      Padding(
                        padding: EdgeInsets.only(left: 10, top: 10, right: 10),
                        child: Center(
                          child: Text(
                            "纵里寻他千百度,暮然回首,那人却在灯火阑珊处~~~",
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      )
                    ],
                  )),
            ],
            onPageChanged: (position) {
              setState(() {
                current = position;
              });
            },
          ),
        ));
  }
}

 


版权声明:本文为hua_9527原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。