Flutter如何在自定义AppBar中间定位Widget并将头像放入预留圆形凹槽
Flutter自定义AppBar凹槽嵌入头像解决方案
核心问题梳理
- 你之前将Stack放在AppBar的actions区域,actions是AppBar右侧的操作容器,本身宽度受限,Positioned的坐标是相对于父Stack而非整个屏幕,自然无法定位到AppBar中间位置
- 错误使用全屏幕高度
MediaQuery.of(context).size.height作为Positioned的top值,会直接把头像移出可视区域 - CustomShapeBorder的Path逻辑错误,重复添加椭圆且未设置挖空规则,无法得到正确的凹槽效果
完整修改代码
import 'package:flutter/material.dart'; class ProfileAppBar extends StatelessWidget implements PreferredSizeWidget { final String? name; const ProfileAppBar({super.key, this.name}); // 调整AppBar高度,预留凹槽空间 @override Size get preferredSize => Size.fromHeight(kToolbarHeight + 10); @override Widget build(BuildContext context) { final double width = MediaQuery.of(context).size.width; final double appBarHeight = preferredSize.height; // 外层用Stack承载AppBar和定位头像 return Stack( clipBehavior: Clip.none, // 允许子组件超出Stack边界显示 children: [ // 底层自定义凹槽形状的AppBar AppBar( shape: const CustomShapeBorder(), leading: Row( children: [ IconButton( icon: const Icon(Icons.home), onPressed: () { Navigator.pushReplacementNamed(context, "/home"); }, ), ], ), title: Text(name ?? 'Username'), actions: <Widget>[ IconButton( iconSize: 30, icon: const Icon(Icons.settings), alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), onPressed: () { const profileRoute = "/profile"; bool isNewRouteSameAsCurrent = false; Navigator.popUntil(context, (route) { if (route.settings.name == profileRoute) { isNewRouteSameAsCurrent = true; } return true; }); if (!isNewRouteSameAsCurrent) { Navigator.pushReplacementNamed(context, profileRoute); } }, ) ], ), // 顶层定位头像,刚好嵌入凹槽 Positioned( left: width / 2 - 30, // 屏幕宽度一半减去头像半径,水平居中 top: appBarHeight - 30, // AppBar高度减去头像半径,纵向适配凹槽 child: CircleAvatar( backgroundImage: const AssetImage("assets/images/person.jpeg"), radius: 30, key: const Key("1"), ), ) ], ); } } class CustomShapeBorder extends ContinuousRectangleBorder { const CustomShapeBorder(); @override Path getOuterPath(Rect rect, {TextDirection? textDirection}) { Path path = Path(); // 绘制AppBar基础矩形 path.addRect(Rect.fromLTWH(0, 0, rect.width, rect.height)); // 添加底部中间的圆形挖空区域 path.addOval( Rect.fromCircle( center: Offset(rect.width / 2, rect.height), radius: 40, ), ); // 奇偶填充规则,叠加区域会被挖空形成凹槽 path.fillType = PathFillType.evenOdd; return path; } }
内容的提问来源于stack exchange,提问作者Kiko
相关产品推荐
相关产品推荐

