Created
February 20, 2025 13:51
-
-
Save roipeker/69204d1e25767a686d26754f0a45848d to your computer and use it in GitHub Desktop.
Svg with basic theme support.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// make SVG behave like Icons. | |
import 'package:flutter/widgets.dart'; | |
import 'package:flutter_svg/svg.dart'; | |
import 'package:http/http.dart' as http; | |
import 'svg_icon_theme.dart'; | |
class SvgIcon extends StatelessWidget { | |
final double? size; | |
final Color? color; | |
final BoxFit? fit; | |
final Alignment? alignment; | |
final bool? allowDrawingOutsideViewBox; | |
final BytesLoader bytesLoader; | |
SvgIcon.asset( | |
String asset, { | |
String? package, | |
SvgTheme? theme, | |
super.key, | |
this.size, | |
this.color, | |
this.fit, | |
this.alignment, | |
this.allowDrawingOutsideViewBox, | |
}) : bytesLoader = SvgAssetLoader( | |
asset, | |
packageName: package, | |
theme: theme, | |
); | |
SvgIcon.network( | |
String url, { | |
Map<String, String>? headers, | |
http.Client? httpClient, | |
SvgTheme? theme, | |
super.key, | |
this.size, | |
this.color, | |
this.fit, | |
this.alignment, | |
this.allowDrawingOutsideViewBox, | |
}) : bytesLoader = SvgNetworkLoader( | |
url, | |
headers: headers, | |
theme: theme, | |
httpClient: httpClient, | |
); | |
SvgIcon.string( | |
String string, { | |
SvgTheme? theme, | |
super.key, | |
this.size, | |
this.color, | |
this.fit, | |
this.alignment, | |
this.allowDrawingOutsideViewBox, | |
}) : bytesLoader = SvgStringLoader(string, theme: theme); | |
@override | |
Widget build(BuildContext context) { | |
final iconThemeData = SvgIconTheme.maybeOf(context)?.data; | |
final effectiveSize = size ?? iconThemeData?.size; | |
final effectiveColor = color ?? iconThemeData?.color; | |
final effectiveFit = fit ?? iconThemeData?.fit; | |
final effectiveAlign = alignment ?? iconThemeData?.alignment; | |
final effectiveDrawingOutside = | |
allowDrawingOutsideViewBox ?? iconThemeData?.allowDrawingOutsideViewBox; | |
ColorFilter? filter; | |
if (effectiveColor != null) { | |
filter = ColorFilter.mode( | |
effectiveColor, | |
BlendMode.srcIn, | |
); | |
} | |
return SvgPicture( | |
bytesLoader, | |
key: key, | |
width: effectiveSize, | |
height: effectiveSize, | |
colorFilter: filter, | |
fit: effectiveFit ?? BoxFit.contain, | |
alignment: effectiveAlign ?? Alignment.center, | |
allowDrawingOutsideViewBox: effectiveDrawingOutside ?? false, | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:ui'; | |
import 'package:flutter/widgets.dart'; | |
class SvgIconThemeData { | |
const SvgIconThemeData({ | |
this.color, | |
this.size, | |
this.fit, | |
this.alignment, | |
this.allowDrawingOutsideViewBox, | |
}); | |
final Color? color; | |
final double? size; | |
final BoxFit? fit; | |
final Alignment? alignment; | |
final bool? allowDrawingOutsideViewBox; | |
const SvgIconThemeData.fallback() | |
: color = null, | |
size = null, | |
fit = null, | |
alignment = null, | |
allowDrawingOutsideViewBox = null; | |
SvgIconThemeData resolve(BuildContext context) => this; | |
factory SvgIconThemeData.fromIconTheme(IconThemeData iconThemeData) { | |
return SvgIconThemeData( | |
size: iconThemeData.size, | |
color: iconThemeData.color, | |
); | |
} | |
SvgIconThemeData merge(SvgIconThemeData? other) { | |
if (other == null) { | |
return this; | |
} | |
return copyWith( | |
size: other.size, | |
color: other.color, | |
fit: other.fit, | |
alignment: other.alignment, | |
allowDrawingOutsideViewBox: other.allowDrawingOutsideViewBox, | |
); | |
} | |
SvgIconThemeData copyWith({ | |
final Color? color, | |
final double? size, | |
final BoxFit? fit, | |
final Alignment? alignment, | |
final bool? allowDrawingOutsideViewBox, | |
}) { | |
return SvgIconThemeData( | |
color: color ?? this.color, | |
size: size ?? this.size, | |
fit: fit ?? this.fit, | |
alignment: alignment ?? this.alignment, | |
allowDrawingOutsideViewBox: allowDrawingOutsideViewBox ?? this.allowDrawingOutsideViewBox, | |
); | |
} | |
static SvgIconThemeData lerp(SvgIconThemeData? a, SvgIconThemeData? b, double t) { | |
if (identical(a, b) && a != null) { | |
return a; | |
} | |
return SvgIconThemeData( | |
size: lerpDouble(a?.size, b?.size, t), | |
color: Color.lerp(a?.color, b?.color, t), | |
alignment: Alignment.lerp(a?.alignment, b?.alignment, t), | |
fit: b?.fit, | |
allowDrawingOutsideViewBox: b?.allowDrawingOutsideViewBox, | |
); | |
} | |
@override | |
bool operator ==(Object other) => | |
identical(this, other) || | |
other is SvgIconThemeData && | |
runtimeType == other.runtimeType && | |
color == other.color && | |
size == other.size && | |
fit == other.fit && | |
alignment == other.alignment && | |
allowDrawingOutsideViewBox == other.allowDrawingOutsideViewBox; | |
@override | |
int get hashCode => Object.hash(color, size, fit, alignment, allowDrawingOutsideViewBox); | |
} | |
class SvgIconTheme extends InheritedWidget { | |
const SvgIconTheme({ | |
super.key, | |
required this.data, | |
required super.child, | |
}); | |
final SvgIconThemeData data; | |
static SvgIconTheme? maybeOf(BuildContext context) { | |
return context.dependOnInheritedWidgetOfExactType<SvgIconTheme>(); | |
} | |
static SvgIconThemeData of(BuildContext context) { | |
// final SvgIconTheme? result = maybeOf(context) ?? const SvgIconThemeData.fallback(); | |
final result = _getInheritedIconThemeData(context).resolve(context); | |
return result; | |
} | |
static SvgIconThemeData _getInheritedIconThemeData(BuildContext context) { | |
final theme = context.dependOnInheritedWidgetOfExactType<SvgIconTheme>(); | |
return theme?.data ?? const SvgIconThemeData.fallback(); | |
} | |
static Widget merge({ | |
Key? key, | |
required SvgIconThemeData data, | |
required Widget child, | |
}) { | |
return Builder( | |
builder: (BuildContext context) { | |
return SvgIconTheme( | |
key: key, | |
data: _getInheritedIconThemeData(context).merge(data), | |
child: child, | |
); | |
}, | |
); | |
} | |
Widget wrap(BuildContext context, Widget child) { | |
return SvgIconTheme(data: data, child: child); | |
} | |
@override | |
bool updateShouldNotify(SvgIconTheme oldWidget) => data != oldWidget.data; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment