import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; /// 币种图标组件:图标已在 app 启动时通过 coinCacheProvider 预缓存, /// 切换到行情页时命中缓存直接显示。加载失败时显示字母占位。 class CoinIcon extends StatelessWidget { const CoinIcon({ super.key, required this.symbol, this.iconUrl = '', this.size = 40, this.borderRadius, this.shape = BoxShape.rectangle, }); final String symbol; final String iconUrl; final double size; /// 圆角半径,仅在 [shape] 为 [BoxShape.rectangle] 时生效 final double? borderRadius; /// [BoxShape.circle] 或 [BoxShape.rectangle](默认矩形+圆角) final BoxShape shape; @override Widget build(BuildContext context) { final letter = symbol.isNotEmpty ? symbol[0].toUpperCase() : '?'; final cs = Theme.of(context).colorScheme; final fontSize = size * 0.42; Widget letterWidget = SizedBox( width: size, height: size, child: Center( child: Text( letter, style: TextStyle( color: cs.onSurface.withAlpha(153), fontSize: fontSize, fontWeight: FontWeight.w700, ), ), ), ); if (iconUrl.isEmpty) return _clip(letterWidget); // Key 随 URL 变化,避免从行情等错误来源切回空 icon 时仍短暂显示旧图 return _clip( CachedNetworkImage( key: ValueKey('$symbol|$iconUrl'), imageUrl: iconUrl, width: size, height: size, fit: BoxFit.cover, errorWidget: (_, __, ___) => letterWidget, ), ); } Widget _clip(Widget child) { if (shape == BoxShape.circle) { return ClipOval(child: child); } final radius = borderRadius ?? size * 0.3; return ClipRRect( borderRadius: BorderRadius.circular(radius), child: child, ); } }