利用FloatingActionButton实现底部凸起的导航栏

利用FloatingActionButton实现底部凸起的导航栏

FloatingActionButton就是如图样式的组件,简称FAB
请添加图片描述

属性名称属性值
child子视图,一般为 Icon,不推荐使用文字
tooltipFAB 被长按时显示,也是无障碍功能
backgroundColor背景颜色
elevation未点击的时候的阴影
hignlightElevation点击时阴影值,默认 12.0
onPressed点击事件回调
shape可以定义 FAB 的形状等
mini是否是 mini 类型默认 false

接下来我们要利用FloatingActionButton来实现一个如图样式的底部凸起的导航栏
请添加图片描述
请添加图片描述
如图可以看出,实际上就是将FloatingActionButton放在了我们导航栏中间的位置
准备的五个页面

CategoryPage.dart

// ignore_for_file: prefer_const_constructors_in_immutables, avoid_unnecessary_containers, prefer_const_constructors, prefer_const_literals_to_create_immutables

import 'package:flutter/material.dart';

class CategoryPage extends StatefulWidget {
  CategoryPage({Key? key}) : super(key: key);

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

class _CategoryPageState extends State<CategoryPage> {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          title: Row(
            children: [
              Expanded(child: TabBar(
                isScrollable: true,
              tabs: [         
              Tab(text: "热门"),
              Tab(text: "切换")
              ],
              )
            )
            ],
            ),
          // bottom: TabBar(
          //   tabs: [
          //     Tab(text: "热门"),
          //     Tab(text: "切换")
          //   ],
          // ),
        ),
        body: TabBarView(
          children: [
            ListView(
              children: [
                ListTile(
                  title: Text("第一个Tab"),
                ),
                ListTile(
                  title: Text("第一个Tab"),
                )
              ],
            ),
            ListView(
              children: [
                ListTile(
                  title: Text("第二个Tab"),
                ),
                ListTile(
                  title: Text("第二个Tab"),
                )
              ],
            )
          ],
          
          ),
      ),
    );
  }
}

EmailPage.dart

// ignore_for_file: avoid_unnecessary_containers, prefer_const_constructors, prefer_const_constructors_in_immutables

import 'package:flutter/material.dart';

class EmailPage extends StatefulWidget {
  EmailPage({Key? key}) : super(key: key);

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

class _EmailPageState extends State<EmailPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("这是邮件页面"),
    );
  }
}

HomePage.dart

// ignore_for_file: prefer_const_constructors_in_immutables, prefer_const_constructors

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  HomePage({Key? key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
      onPressed: (){
        Navigator.pushNamed(context, '/appbar');
      }, 
      child: Text("点击转跳"),
      ),
      ElevatedButton(
      onPressed: (){
        Navigator.pushNamed(context, '/tabBarController');
      }, 
      child: Text("点击转跳TabBarController"),
      ),
      ElevatedButton(
      onPressed: (){
        Navigator.pushNamed(context, '/tabBarController');
      }, 
      child: Text("点击转跳TabBarController"),
      )
      ],
    );
  }
}

SettingPage.dart

// ignore_for_file: prefer_const_literals_to_create_immutables

import 'package:flutter/material.dart';

class SettingPage extends StatefulWidget {
  SettingPage({Key? key}) : super(key: key);

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

class _SettingPageState extends State<SettingPage> {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          title: Text("我是设置页面"),
        )
      ],
    );
  }
}

AddPage.dart(这个页面对应的导航按钮会被FloatingActionButton遮住),给FloatingActionButton设置点击事件改变页面也可以达到页面切换的效果

// ignore_for_file: avoid_unnecessary_containers, prefer_const_constructors

import 'package:flutter/material.dart';

class AddPage extends StatelessWidget {
  const AddPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("这是添加页面"),
    );
  }
}

Tabs.dart

// ignore_for_file: prefer_final_fields, deprecated_member_use, prefer_const_literals_to_create_immutables, prefer_const_constructors

import 'package:flutter/material.dart';
import 'package:flutterapp/pages/User.dart';
import 'package:flutterapp/pages/tabs/add.dart';
import 'tabs/Category.dart';
import 'tabs/Email.dart';
import 'tabs/Home.dart';
import 'tabs/Setting.dart';
import '../pages/User.dart';

class Tabs extends StatefulWidget {
  const Tabs({Key? key}) : super(key: key);

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

class _TabsState extends State<Tabs> {
  int currentIndex = 0;
  List _pageList = [
    HomePage(),
    CategoryPage(),
    AddPage(),
    SettingPage(),
    EmailPage()
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Demo'),
      ),
      floatingActionButton: Container(
        height: 70,
        width: 70,
        padding: EdgeInsets.all(10),
        margin: EdgeInsets.only(top: 30),
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(35),
            color: Color.fromARGB(255, 250, 250, 250)),
        child: FloatingActionButton(
          onPressed: () {
            setState(() {
              currentIndex = 2;
            });
          },
          child: Icon(Icons.add),
          backgroundColor: currentIndex==2?Colors.yellow:Colors.blue,
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      drawer: Drawer(
        child: Column(
          children: [
            Row(
              children: [
                Expanded(
                    child: UserAccountsDrawerHeader(
                  accountEmail: Text("1658554314@qq.com"),
                  accountName: Text("sky"),
                  currentAccountPicture: CircleAvatar(
                      backgroundImage: NetworkImage(
                          "https://cdn.stocksnap.io/img-thumbs/960w/goose-flock_7EARMYLNXB.jpg")),
                  decoration: BoxDecoration(
                    image: DecorationImage(
                        image: NetworkImage(
                            "https://cdn.stocksnap.io/img-thumbs/960w/ice-nature_PHKM6CXBLQ.jpg"),
                        fit: BoxFit.cover),
                  ),
                  otherAccountsPictures: [
                    Image.network(
                        "https://cdn.stocksnap.io/img-thumbs/960w/flower-bloom_NZWKWLNPYX.jpg"),
                    Image.network(
                        "https://cdn.stocksnap.io/img-thumbs/960w/flower-bloom_KAKMFZ02RH.jpg"),
                  ],
                ))
              ],
            ),
            ListTile(
              leading: CircleAvatar(child: Icon(Icons.home)),
              title: Text("我的空间"),
            ),
            //设置分割线
            Divider(),
            ListTile(
              leading: CircleAvatar(child: Icon(Icons.people)),
              title: Text("用户中心"),
              onTap: () {
                Navigator.of(context).pop();
                Navigator.of(context)
                    .push(MaterialPageRoute(builder: (BuildContext context) {
                  return UserPage();
                }));
              },
            ),
            Divider(),
            ListTile(
              leading: CircleAvatar(child: Icon(Icons.settings)),
              title: Text("设置中心"),
            )
          ],
        ),
      ),
      endDrawer: Drawer(
        child: Text("右侧边栏"),
      ),
      body: _pageList[currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: currentIndex,
        onTap: (int index) {
          setState(() {
            currentIndex = index;
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: "首页",
          ),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.add), label: "添加"),
          BottomNavigationBarItem(icon: Icon(Icons.mail), label: "邮件"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
        ],
      ),
    );
  }
}

把相关代码再摆出来方便查看

/*按钮摆放的位置和APPBar同级,因为不能设置floatingActionButton大小,
因此在外面嵌套一个Container来设置大小,我们也可以通过margin: EdgeInsets.only(top: 30),
改变来只遮住图案不遮住文字(我们这里把文字图案都遮住了)*/
 floatingActionButton: Container(
        height: 70,
        width: 70,
        padding: EdgeInsets.all(10),
        margin: EdgeInsets.only(top: 30),
        //把Container设置为圆形
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(35),
            color: Color.fromARGB(255, 250, 250, 250)),
        child: FloatingActionButton(
          onPressed: () {
            setState(() {
              currentIndex = 2;
            });
          },
          child: Icon(Icons.add),
          //点击时改变按钮颜色
          backgroundColor: currentIndex==2?Colors.yellow:Colors.blue,
        ),
      ),
      //设置floatingActionButton位置在底部中间
      floatingActionButtonLocation:  FloatingActionButtonLocation.centerDocked,

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Uniapp实现底部导航栏凸起可以通过自定义组件和flex布局来实现。 1. 创建自定义组件 在Uniapp项目中创建一个自定义组件,组件中包含一个`tab-bar`容器和几个`tab-item`,示例代码如下: ```html <template> <div class="tab-bar"> <div class="tab-item" :class="{active: activeIndex === 0}" @click="handleTabClick(0)"> <img src="/static/home.png" alt=""> <span>首页</span> </div> <div class="tab-item" :class="{active: activeIndex === 1}" @click="handleTabClick(1)"> <img src="/static/category.png" alt=""> <span>分类</span> </div> <div class="tab-item" :class="{active: activeIndex === 2}" @click="handleTabClick(2)"> <img src="/static/cart.png" alt=""> <span>购物车</span> </div> <div class="tab-item" :class="{active: activeIndex === 3}" @click="handleTabClick(3)"> <img src="/static/user.png" alt=""> <span>我的</span> </div> <div class="tab-item-center" @click="handleTabClick(-1)"> <img src="/static/center.png" alt=""> </div> </div> </template> <script> export default { props: { activeIndex: { type: Number, default: 0 } }, methods: { handleTabClick(index) { this.$emit('tab-click', index) } } } </script> <style> .tab-bar { display: flex; justify-content: space-between; align-items: center; background-color: #fff; height: 60px; padding: 0 20px; box-shadow: 0 -4px 4px rgba(0, 0, 0, 0.1); } .tab-item { display: flex; flex-direction: column; justify-content: center; align-items: center; font-size: 12px; color: #666; } .tab-item.active { color: #2d8cf0; } .tab-item img { width: 24px; height: 24px; margin-bottom: 6px; } .tab-item-center { position: absolute; left: 50%; transform: translate(-50%, -50%); width: 60px; height: 60px; border-radius: 50%; background-color: #2d8cf0; display: flex; justify-content: center; align-items: center; box-shadow: 0 4px 4px rgba(0, 0, 0, 0.1); } .tab-item-center img { width: 32px; height: 32px; } </style> ``` 2. 使用自定义组件 在需要使用底部导航栏的页面中,引入自定义组件并使用`flex`布局,示例代码如下: ```html <template> <div class="page"> <div class="content"> <!-- 页面内容 --> </div> <TabBar :active-index="activeIndex" @tab-click="handleTabClick" /> </div> </template> <script> import TabBar from '@/components/tab-bar' export default { components: { TabBar }, data() { return { activeIndex: 0 } }, methods: { handleTabClick(index) { if (index === -1) { // 中间凸起部分被点击 // 处理逻辑 } else { // 底部导航栏被点击 // 处理逻辑 } } } } </script> <style> .page { display: flex; flex-direction: column; height: 100%; } .content { flex: 1; } </style> ``` 以上代码中,将自定义组件`TabBar`作为页面的底部导航栏,使用`flex`布局将页面内容和底部导航栏放在同一个容器中,可以实现底部导航栏凸起的效果。 需要注意的是,自定义组件中的`tab-item-center`元素使用了绝对定位,需要手动调整其位置和样式。在页面中处理底部导航栏被点击的事件,可以通过`$emit`方法将事件传递给父组件处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值