Flutter如何实现带曲线效果的双色顶部AppBar
Flutter实现双色AppBar与曲线衔接效果

实现思路
不需要引入任何第三方依赖,用Flutter原生渲染能力即可完成,拆分为两个核心模块处理:
- 双色顶部栏:放弃原生仅支持单一背景的
AppBar组件,直接通过自绘路径绘制两个不同颜色的区域,上层叠放返回按钮、标题、操作菜单等交互元素,灵活度远高于改造默认AppBar - 曲线衔接效果:通过二阶贝塞尔曲线绘制自然弧形分界,让两个色块从顶部栏平滑过渡到内容区域,避免生硬的直角分割
核心实现代码
import 'package:flutter/material.dart'; class CurveEffectPage extends StatelessWidget { const CurveEffectPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ // 页面主体内容 Positioned.fill( child: Column( children: [ // 预留顶部栏+曲线的高度占位 const SizedBox(height: 120), Expanded( child: ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: 20, itemBuilder: (context, index) => Card( elevation: 1, margin: const EdgeInsets.only(bottom: 12), child: ListTile(title: Text('内容项 $index')), ), ), ) ], ), ), // 自定义双色AppBar+曲线装饰层 Positioned( top: 0, left: 0, right: 0, child: SizedBox( height: 120, child: CustomPaint( painter: DualColorAppBarPainter( primaryColor: const Color(0xFF2563EB), secondaryColor: const Color(0xFFEFF6FF), ), // 顶部栏交互元素,加SafeArea避开状态栏 child: const SafeArea( bottom: false, child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(Icons.arrow_back, color: Colors.white, size: 24), Text( '页面标题', style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600 ), ), Icon(Icons.more_vert, color: Colors.white, size: 24) ], ), ), ), ), ), ) ], ), ); } } // 自绘双色区域与曲线的画笔 class DualColorAppBarPainter extends CustomPainter { final Color primaryColor; final Color secondaryColor; DualColorAppBarPainter({required this.primaryColor, required this.secondaryColor}); @override void paint(Canvas canvas, Size size) { const appBarHeight = 56.0; // 标准AppBar高度 // 绘制左侧主色区域 final primaryPaint = Paint()..color = primaryColor; final primaryPath = Path() ..lineTo(size.width * 0.68, 0) // 贝塞尔曲线控制点,修改参数可调整弧度 ..quadraticBezierTo(size.width * 0.72, appBarHeight + 18, size.width * 0.38, appBarHeight + 25) ..lineTo(0, appBarHeight + 25) ..close(); canvas.drawPath(primaryPath, primaryPaint); // 绘制右侧辅色区域 final secondaryPaint = Paint()..color = secondaryColor; final secondaryPath = Path() ..moveTo(size.width * 0.68, 0) ..lineTo(size.width, 0) ..lineTo(size.width, appBarHeight) // 与主色区域衔接的贝塞尔曲线 ..quadraticBezierTo(size.width * 0.72, appBarHeight + 18, size.width * 0.38, appBarHeight + 25) ..close(); canvas.drawPath(secondaryPath, secondaryPaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }
自定义调整说明
- 弧度修改:调整
quadraticBezierTo方法中的控制点坐标、终点Y轴偏移值,即可得到不同弯曲程度的曲线,数值越大弧形下坠感越强 - 分色比例:修改路径中的宽度比例参数(如
size.width * 0.68),可以调整两个颜色在顶部栏的占比 - 适配注意:如果曲线装饰层下方有可点击交互组件,把
CustomPaint替换为ClipPath裁剪两个色块容器,避免装饰层拦截手势事件;深色模式下只需要根据主题状态传入对应颜色即可适配
内容的提问来源于stack exchange,提问作者Mateusz Ptak
相关产品推荐
相关产品推荐

