import 'package:flutter/material.dart'; /// 一组圆角卡片式列表项,行间自动加分隔线。 /// /// 容器用 [Material] 而不是 `Container`:`InkWell` 的水波纹画在最近的 /// `Material` 祖先上,普通容器会让墨水落到外层 Scaffold,圆角裁剪失效, /// 按住时就变成直角矩形。 class GroupedListSection extends StatelessWidget { const GroupedListSection({ required this.tiles, this.dividerIndent = 58, super.key, }); final List tiles; /// 分隔线左侧缩进,默认与图标后的文字对齐。 final double dividerIndent; @override Widget build(BuildContext context) { final ColorScheme colors = Theme.of(context).colorScheme; return Material( color: colors.surfaceContainerLow, borderRadius: BorderRadius.circular(20), clipBehavior: Clip.antiAlias, child: Column( children: [ for (final (int index, Widget tile) in tiles.indexed) ...[ tile, if (index != tiles.length - 1) Divider( height: 1, thickness: 1, indent: dividerIndent, color: colors.outlineVariant.withValues(alpha: 0.6), ), ], ], ), ); } } /// 分组列表里的一行:图标 + 标题(+ 可选副标题)+ 右侧箭头。 class GroupedListTile extends StatelessWidget { const GroupedListTile({ required this.icon, required this.title, this.subtitle, this.onTap, this.trailing, super.key, }); final IconData icon; final String title; final String? subtitle; final VoidCallback? onTap; /// 右侧自定义内容;不传且有 [onTap] 时显示箭头。 final Widget? trailing; @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final ColorScheme colors = theme.colorScheme; final String? subtitle = this.subtitle; final Widget? trailing = this.trailing; return InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 18), child: Row( children: [ Icon(icon, size: 22, color: colors.primary), const SizedBox(width: 18), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: theme.textTheme.bodyLarge, maxLines: 1, overflow: TextOverflow.ellipsis, ), if (subtitle != null) ...[ const SizedBox(height: 2), Text( subtitle, style: theme.textTheme.bodySmall?.copyWith( color: colors.onSurfaceVariant, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ], ), ), if (trailing != null) trailing else if (onTap != null) Icon( Icons.chevron_right_rounded, size: 22, color: colors.onSurfaceVariant, ), ], ), ), ); } }