Flutter 基于AppBar自定义导航栏基类

这篇博客介绍了如何在Flutter中基于AppBar自定义导航栏,详细解析了AppBar的使用,并提供了具体的代码实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Flutter 基于AppBar自定义导航栏基类

效果图

请添加图片描述

AppBar 详解

AppBar({
    Key key,
    this.leading, //widget类型,即可任意设计样式,表示左侧leading区域,通常为icon,如返回icon
    this.automaticallyImplyLeading = true, // 如果leading!=null,该属性不生效;如果leading==null且为true,左侧leading区域留白;如果leading==null且为false,左侧leading区域扩展给title区域使用
    this.title,//widget类型,即可任意设计样式,表示中间title区域,通常为标题栏
    this.actions,// List<Widget>类型,即可任意设计样式,表示右侧actions区域,可放置多个widget,通常为icon,如搜索icon、菜单icon
    this.flexibleSpace,
    this.bottom, //PreferredSizeWidget类型,appbar底部区域,通常为Tab控件
    this.elevation, //阴影高度,默认为4
    this.shape,//ShapeBorder 类型,表示描边形状
    this.backgroundColor, //Color类型,背景色 
    this.brightness,//Brightness类型,表示当前appbar主题是亮或暗色调,有dark和light两个值,可影响系统状态栏的图标颜色
    this.iconTheme, //IconThemeData类型,可影响包括leading、title、actions中icon的颜色、透明度,及leading中的icon大小。
    this.actionsIconTheme,
    this.textTheme,// TextTheme类型,文本主题样式,可设置appbar中文本的许多样式,如字体大小、颜色、前景色、背景色等...
    this.primary = true,//true时,appBar会以系统状态栏高度为间距显示在下方;false时,会和状态栏重叠,相当于全屏显示。
    this.centerTitle, // boolean 类型,表示标题是否居中显示
    this.titleSpacing = NavigationToolbar.kMiddleSpacing,//title区域水平方向与leading和actions的间距(padding)
    this.toolbarOpacity = 1.0,//toolbar区域透明度
    this.bottomOpacity = 1.0,//bottom区域透明度
  }

代码实现

比较简单,直接上代码

import 'package:flutter/material.dart';

const double _elevation = 0;
const double _titleFontSize = 18.0;
const double _textFontSize = 16.0;
const double _itemSpace = 15.0; // 右侧item内间距
const double _imgWH = 22.0; // 右侧图片宽高
const double _rightSpace = 5.0; // 右侧item右间距

// 默认颜色
const Color _bgColor = Color(0xFF3BB815);
const Color _bgDarkColor = Color(0xFF0A0A0A);
const Color _titleColor = Colors.white;
// 状态栏字体颜色,当backgroundColor透明或者是白色,状态栏字体为黑色,暗黑模式为白色
const Brightness _brightness = Brightness.light;

/// 导航条基类
class BaseAppBar extends StatefulWidget implements PreferredSizeWidget {
  const BaseAppBar(
    this.title, {
    Key? key,
    this.rightText,
    this.rightImgPath,
    this.leftWidget,
    this.titleWidget,
    this.rightWidgets,
    this.bgColor,
    this.brightness = _brightness,
    this.elevation: _elevation,
    this.bottomWidget,
    this.flexibleSpace,
    this.leftItemCallBack,
    this.rightItemCallBack,
  }) : super(key: key);

  final String title; // 标题文字
  final String? rightText; // 右侧按钮文字
  final String? rightImgPath; // 右侧按钮图片路径,优先级高于rightText
  final Widget? leftWidget; // 左侧Widget,为空显示返回按钮
  final Widget? titleWidget; // 标题Widget,优先级高于title
  final List<Widget>? rightWidgets; // 优先级高于rightText和rightImgPath
  final Color? bgColor; // 背景颜色,默认主题色,设置的颜色优先级高于暗黑模式
  final Brightness brightness;
  final double elevation;
  final PreferredSizeWidget? bottomWidget;
  final Widget? flexibleSpace;
  final Function? leftItemCallBack;
  final Function? rightItemCallBack;

  @override
  State<BaseAppBar> createState() => _BaseAppBarState();

  @override
  Size get preferredSize => Size.fromHeight(
      kToolbarHeight + (bottomWidget?.preferredSize.height ?? 0.0));
}

class _BaseAppBarState extends State<BaseAppBar> {
  @override
  Widget build(BuildContext context) {
    return _appBar();
  }

  Widget _appBar() {
    // 默认颜色
    Color titleAndIconColor = _titleColor;
    Color bgColor = widget.bgColor ?? _bgColor;
    var brightness = widget.brightness;

    // 如果背景透明或者是白色,设置字体和图标、状态栏字体为黑色
    // if (widget.bgColor == Colors.transparent ||
    //     widget.bgColor == Colors.white ||
    //     widget.bgColor == KColors.kNavWhiteBgColor) {
    //   titleAndIconColor = Colors.black;
    //   brightness = Brightness.dark;
    // } else {
    //   brightness = Brightness.light;
    // }

    // TODO: 通过ThemeProvider进行主题管理
    // final provider = Provider.of<ThemeProvider>(context);
    // final bool isDark = context.jhIsDark;
    // // 设置的颜色优先级高于暗黑模式
    // bgColor = widget.bgColor ?? (isDark ? _bgDarkColor : provider.getThemeColor());
    // if (isDark) {
    titleAndIconColor = _titleColor;
    // }

    // 标题
    var titleWidget = widget.titleWidget ??
        Text(widget.title,
            style:
                TextStyle(fontSize: _titleFontSize, color: titleAndIconColor),
            maxLines: 2);

    // 左侧
    var backWidget = IconButton(
//      icon: Icon(Icons.arrow_back_ios,color: _color),
      icon: ImageIcon(
        AssetImage('assets/images/common/ic_nav_back_white.png'),
        color: titleAndIconColor,
      ),
      iconSize: 18,
      padding: const EdgeInsets.fromLTRB(0, 0, 10, 0),
      onPressed: () {
        if (widget.leftItemCallBack == null) {
          _popThis(context);
        } else {
          widget.leftItemCallBack!();
        }
      },
    );
    var leftWidget = widget.leftWidget ?? backWidget;

    // 右侧
    Widget rightWidget = Text('');
    if (widget.rightText != null) {
      rightWidget = InkWell(
        child: Container(
          margin: EdgeInsets.all(_itemSpace),
          color: Colors.transparent,
          child: Center(
            child: Text(widget.rightText!,
                style: TextStyle(
                    fontSize: _textFontSize, color: titleAndIconColor)),
          ),
        ),
        onTap: () => widget.rightItemCallBack?.call(),
      );
    }
    if (widget.rightImgPath != null) {
      rightWidget = IconButton(
        icon: Image.asset(widget.rightImgPath!,
            width: _imgWH, height: _imgWH, color: titleAndIconColor),
        onPressed: () => widget.rightItemCallBack?.call(),
      );
    }
    var actions = [
      Row(
        mainAxisAlignment: MainAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[rightWidget, SizedBox(width: _rightSpace)],
      ),
    ];
    var rightWidgets = widget.rightWidgets ?? actions;

    return AppBar(
      title: titleWidget,
      centerTitle: true,
      backgroundColor: bgColor,
      // systemOverlayStyle: JhStatusBarUtils.getStatusBarStyle(isDark: isDark, brightness: brightness),
      bottom: widget.bottomWidget,
      elevation: widget.elevation,
      leading: leftWidget,
      actions: rightWidgets,
      flexibleSpace: widget.flexibleSpace,
    );
  }
}

void _popThis(BuildContext context) {
  if (Navigator.of(context).canPop()) {
    FocusManager.instance.primaryFocus?.unfocus();
    Navigator.of(context).pop();
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白昼lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值