| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- 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,
- );
- }
- }
|