// Author: fruit.com.cn import 'dart:math' as math; import 'package:flutter/material.dart'; /// 首页右上角搜索/礼物图标的自定义样式: /// 搜索为粗线条放大镜(Material 图标无法调线条粗细),礼物为 emoji 红金礼盒。 /// 粗线条白色放大镜,圆环在左上、手柄朝右下。 class SearchGlyph extends StatelessWidget { const SearchGlyph({super.key, required this.size, required this.color}); final double size; final Color color; @override Widget build(BuildContext context) { return CustomPaint( size: Size.square(size), painter: _SearchPainter(color: color), ); } } class _SearchPainter extends CustomPainter { const _SearchPainter({required this.color}); final Color color; @override void paint(Canvas canvas, Size size) { final stroke = size.width * 0.09; final paint = Paint() ..color = color ..style = PaintingStyle.stroke ..strokeWidth = stroke ..strokeCap = StrokeCap.round; final circleDiameter = size.width * 0.7; final direction = math.pi / 4; // 图形只占画布左上角,先平移让它视觉居中,否则会比文字基线偏高。 final drawnExtent = circleDiameter / 2 + (circleDiameter / 2 + size.width * 0.12) * math.sin(direction) + stroke / 2; final centering = (size.width - drawnExtent) / 2; canvas.translate(centering, centering); final center = Offset(circleDiameter / 2, circleDiameter / 2); canvas.drawCircle(center, circleDiameter / 2 - stroke / 2, paint); final start = center + Offset.fromDirection(direction, circleDiameter / 2 - stroke * 0.2); final end = center + Offset.fromDirection(direction, circleDiameter / 2 + size.width * 0.12); canvas.drawLine(start, end, paint); } @override bool shouldRepaint(covariant _SearchPainter oldDelegate) => oldDelegate.color != color; } /// YMB 品牌礼盒静态图标,使用玫红礼盒与金色丝带。 class GiftGlyph extends StatelessWidget { const GiftGlyph({super.key, required this.size}); final double size; @override Widget build(BuildContext context) { return CustomPaint(size: Size.square(size), painter: _GiftPainter()); } } class _GiftPainter extends CustomPainter { const _GiftPainter(); static const double _designSize = 26; @override void paint(Canvas canvas, Size size) { canvas.save(); canvas.scale(size.width / _designSize); _paintBox(canvas); _paintRibbon(canvas); _paintBow(canvas); canvas.restore(); } void _paintBox(Canvas canvas) { final body = RRect.fromRectAndRadius( const Rect.fromLTRB(4, 13, 22, 23), const Radius.circular(2), ); canvas.drawRRect( body, Paint() ..shader = const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFFFF5C82), Color(0xFFEF315D)], ).createShader(const Rect.fromLTRB(4, 13, 22, 23)), ); canvas.drawRRect( RRect.fromRectAndRadius( const Rect.fromLTRB(3, 10, 23, 14), const Radius.circular(1.5), ), Paint() ..shader = const LinearGradient( colors: [Color(0xFFFF7190), Color(0xFFF52E5C)], ).createShader(const Rect.fromLTRB(3, 10, 23, 14)), ); } void _paintRibbon(Canvas canvas) { final ribbon = Paint() ..shader = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFFFFFFA8), Color(0xFFFFD52F), Color(0xFFFFB900)], ).createShader(const Rect.fromLTRB(10.5, 10, 15.5, 23)); canvas.drawRect(const Rect.fromLTRB(10.5, 13, 15.5, 23), ribbon); canvas.drawRect(const Rect.fromLTRB(3, 10.5, 23, 14), ribbon); canvas.drawLine( const Offset(11, 14), const Offset(11, 22), Paint() ..color = const Color(0xFFFFFFAE) ..strokeWidth = 0.6, ); } void _paintBow(Canvas canvas) { final gold = Paint() ..shader = const LinearGradient( colors: [Color(0xFFFFFFA8), Color(0xFFFFD52F), Color(0xFFFFB900)], ).createShader(const Rect.fromLTRB(5, 1, 21, 12)); final tails = Path() ..moveTo(11.8, 7) ..lineTo(15, 7) ..lineTo(17, 13) ..lineTo(14.1, 12) ..lineTo(12.6, 14) ..lineTo(10.8, 8) ..close(); canvas.drawPath(tails, gold); final bow = Path() ..moveTo(13, 7) ..cubicTo(5.2, 0, 5.2, 4.8, 7.5, 6.7) ..cubicTo(9, 8, 11.5, 8, 13, 7) ..cubicTo(14.5, 8, 17, 8, 18.5, 6.7) ..cubicTo(20.8, 4.8, 20.8, 0, 13, 7) ..close(); canvas.drawPath(bow, gold); canvas.drawCircle(const Offset(13, 7), 1.55, gold); } @override bool shouldRepaint(covariant _GiftPainter oldDelegate) => false; }