You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中使用CustomPainter设计指定形状的AppBar

实现自定义弧形AppBar的解决方案

针对你遇到的问题,直接嵌套原生AppBar会受限于其内部布局约束(leading区域宽度固定、title区域起始位置受限),更灵活的方式是直接基于PreferredSizeWidget构建完整的自定义AppBar,通过分层布局实现设计效果:

完整代码实现

1. 自定义AppBar组件

import 'package:flutter/material.dart';

class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  final String title;

  const CustomAppBar({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: preferredSize.height,
      child: Stack(
        children: [
          // 背景层:绘制左侧弧形背景
          Positioned.fill(
            child: CustomPaint(
              painter: _AppBarBackgroundPainter(),
            ),
          ),
          // 内容层:返回按钮
          Align(
            alignment: Alignment.centerLeft,
            child: Padding(
              padding: const EdgeInsets.only(left: 16),
              child: IconButton(
                icon: const Icon(Icons.arrow_back, color: Colors.white),
                onPressed: () => Navigator.pop(context),
              ),
            ),
          ),
          // 内容层:标题文本
          Align(
            alignment: Alignment.center,
            child: Text(
              title,
              style: const TextStyle(
                color: Colors.black,
                fontSize: 18,
                fontWeight: FontWeight.w600,
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  Size get preferredSize => const Size.fromHeight(kToolbarHeight + 10);
}

2. 背景形状绘制器

class _AppBarBackgroundPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = const Color(0xff55847A);

    // 构建弧形路径,适配AppBar尺寸
    final path = Path();
    path.moveTo(0, size.height); // 起点:左下角
    path.lineTo(0, 0); // 到左上角
    // 二次贝塞尔曲线构建弧形,可根据设计图调整控制点坐标
    path.quadraticBezierTo(
      size.width * 0.3,
      0,
      size.width * 0.45,
      size.height * 0.5,
    );
    path.quadraticBezierTo(
      size.width * 0.6,
      size.height,
      size.width,
      size.height,
    );
    path.lineTo(size.width, size.height); // 回到右下角
    path.close(); // 闭合路径

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

3. 使用方式

在Scaffold中直接引用:

Scaffold(
  appBar: CustomAppBar(title: "Dashboard"),
  body: const Center(child: Text("页面内容")),
);

关键问题说明

  1. 为什么不用原生AppBar嵌套?
    原生AppBar的leading区域有固定宽度限制(默认最大56px),无法容纳超出范围的自定义形状;title区域从leading之后开始布局,无法将形状对齐到AppBar最左侧。直接基于PreferredSizeWidget构建容器,用Stack分层布局,完全摆脱原生布局约束。

  2. CustomPainter参数解析

    • Canvas:绘制操作的画布,所有图形都绘制在这个画布上
    • Size:当前CustomPaint组件的尺寸,这里对应AppBar的宽高,用相对比例(如size.width * 0.3)计算坐标,可适配不同屏幕
    • Path:用于构建复杂自定义形状,quadraticBezierTo通过两个控制点调整弧形弧度,你可以修改控制点的数值来匹配设计图的弧形效果
    • Paint:设置画笔颜色、填充/描边样式等属性

内容的提问来源于stack exchange,提问作者Sibghat ullah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:42:43