flutter-APP根页面

337 阅读3分钟

实现效果

image.png

展示页面内容

  1. 定义页面组件(首页、分类、购物车、我的)
  2. 定义页面列表,存放首页、分类、购物车、我的这四个页面组件
  3. 读取页面组件,并赋值给Scaffold组件的body属性(默认读取并展示首页)

image.png

展示底部导航

  1. 将BottomNavigationBar组件设置给Scaffold组件的bottomNavigationBar属性
  2. 将四个BottomNavigationBarItem组件存放到BottomNavigationBar组件的items属性

image.png

注意点:

  1. items属性元素个数必须大于或等于2个
  2. items属性元素个数如果大于3个,则底部导航样式要使用type属性调整为fixed

处理交互-使用底部导航切换页面内容

  1. 切换底部导航
    • 先监听底部导航的点击事件,并获取点击的Item索引
    • 再将获取的Item索引赋值给BottomNavigationBar组件的currentIndex属性
    • 最后刷新底部导航,更新currentIndex属性的值
  2. 切换页面内容
    • 使用Item索引值从页面列表中读取出对应的页面组件展示即可

image.png

image.png

处理交互-优化底部导航交互效果

  1. 去除点击和长按时的背景色
    • 使用Theme组件可以自定义组件主题样式
    • 自定义底部导航的主题样式,设置点击和长按时的背景色为透明色
  2. 统一选中和未选中状态的字号
    • 选中状态的字号:selectedFontSize属性
    • 未选中状态的字号:unselectedFontSize属性

优化底部导航图标和文字

  1. 准备底部导航设计稿图标
    • 存放底部导航图标到assets文件目录
    • 指定底部导航图标加载路径
  2. 展示底部导航设计稿图标
    • 选中状态的图标: activeIcon属性
    • 未选中状态的图标:icon属性
  3. 设置选中和未选中状态的文字颜色
    • 选中状态的颜色:selectedItemColor属性
    • 未选中状态的颜色:unselectedItemColor属性

解决切换底部导航Item时图标闪动的问题

  1. 问题:底部导航初次切换Item时,图标会闪一下,再次切换就正常
  2. 原因:
    • Image组件在加载新图时,默认会先将旧图清空,在新图展示前,会有一段空白内容
    • 如果加载新图有延迟,则空白内容就会明显展示出来,此时就会看到图标闪动的画面
  3. 解决办法:
    • gaplessPlayback属性: 控制Image组件在加载新图时是否清空旧图
      • false:加载新图时,先将旧图清空,在新图展示前,会有一段空白内容
      • true:加载新图时,不清空旧图,直到新图展示出来为止

image.png

完整代码 root_page.dart

import 'package:erabbit_app/pages/cart/cart_page.dart';
import 'package:erabbit_app/pages/home/home_page.dart';
import 'package:erabbit_app/pages/category/category_page.dart';
import 'package:erabbit_app/pages/mine/mine_page.dart';
import 'package:flutter/material.dart';

class RootPage extends StatefulWidget {
  @override
  _RootPageState createState() => _RootPageState();
}

class _RootPageState extends State<RootPage> {
  // 页面列表
  List pages = [HomePage(), CategoryPage(), CartPage(), MinePage()];
  // 当前item的索引
  int _currentIndex = 0; // _ 私有

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 页面内容
      body: pages[_currentIndex],
      // 底部导航
      // Theme组件 可以自定义组件主题样式
      bottomNavigationBar: Theme(
        // 指定新的主题样式
        data: ThemeData(
          splashColor: Colors.transparent, // 点击时 颜色透明
          highlightColor: Colors.transparent, // 长按时 颜色透明
        ),
        child: BottomNavigationBar(
          // 指定当前选择的item
          currentIndex: _currentIndex,
          // 监听底部导航点击事件
          onTap: (int index) {
            // 将当期索引值赋值给currentIndex
            setState(() {
              _currentIndex = index;
            });
          },
          selectedFontSize: 10.0, // 选中时 文字字号
          unselectedFontSize: 10.0, // 未选中时 文字字号
          selectedItemColor: Color(0xff3cceaf), // 选中状态文字颜色
          unselectedItemColor: Color(0xff383838), // 未选中状态 文字颜色

          // type: BottomNavigationBarType.shifting, // 默认
          type: BottomNavigationBarType.fixed, // 解决items元素超过三个时的样式问题
          items: [
            BottomNavigationBarItem(
              icon: Image.asset(
                'assets/home_nor.png',
                gaplessPlayback: true,
              ),
              activeIcon: Image.asset(
                'assets/home_sel.png',
                gaplessPlayback: true,
              ),
              label: '首页',
            ),
            BottomNavigationBarItem(
              icon: Image.asset(
                'assets/category_nor.png',
                gaplessPlayback: true,
              ),
              activeIcon: Image.asset(
                'assets/category_sel.png',
                gaplessPlayback: true,
              ),
              label: '分类',
            ),
            BottomNavigationBarItem(
              // icon: Icon(Icons.shopping_cart),
              icon: Image.asset(
                'assets/cart_nor.png',
                gaplessPlayback: true,
              ),
              activeIcon: Image.asset(
                'assets/cart_sel.png',
                gaplessPlayback: true,
              ),
              label: '购物车',
            ),
            BottomNavigationBarItem(
              // icon: Icon(Icons.person),
              icon: Image.asset(
                'assets/mine_nor.png',
                gaplessPlayback: true,
              ),
              activeIcon: Image.asset(
                'assets/mine_sel.png',
                gaplessPlayback: true,
              ),
              label: '我的',
            ),
          ],
        ),
      ),
    );
  }
}