import 'package:flutter/material.dart'; import '../models/category.dart'; /// 分类 emoji 宫格(手动记账页与账单编辑页共用) /// /// 这是纯同步组件:分类列表的加载/错误/空态由调用方用 AsyncValue.when 处理, /// 组件本身不关心 type 之类的业务参数。 class CategoryPickerGrid extends StatelessWidget { const CategoryPickerGrid({ super.key, required this.categories, required this.selectedId, required this.onSelect, this.crossAxisCount = 5, this.emptyText = '暂无分类', }); final List categories; final int? selectedId; final ValueChanged onSelect; final int crossAxisCount; final String emptyText; @override Widget build(BuildContext context) { if (categories.isEmpty) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.8), borderRadius: BorderRadius.circular(14), ), child: Text(emptyText, style: const TextStyle(color: Color(0xFF8D6E63))), ); } return GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, mainAxisSpacing: 10, crossAxisSpacing: 6, childAspectRatio: 0.85, ), itemCount: categories.length, itemBuilder: (context, i) => _item(categories[i]), ); } Widget _item(Category category) { final active = selectedId == category.id; return GestureDetector( onTap: () => onSelect(category.id), child: Column( children: [ AnimatedContainer( duration: const Duration(milliseconds: 150), width: 52, height: 52, decoration: BoxDecoration( shape: BoxShape.circle, color: active ? const Color(0xFFC8956E) : Colors.white, border: Border.all( color: active ? const Color(0xFF5D4037) : const Color(0xFFE0C9A6), ), ), alignment: Alignment.center, child: Text(category.icon, style: const TextStyle(fontSize: 24)), ), const SizedBox(height: 4), Text( category.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 12, color: active ? const Color(0xFF5D4037) : const Color(0xFF8D6E63), fontWeight: active ? FontWeight.bold : FontWeight.normal, ), ), ], ), ); } }