FlutterGen
Test Article
Copy from https://github.com/FlutterGen/flutter_gen
The Flutter code generator for your assets, fonts, colors, … — Get rid of all String-based APIs.
Inspired by SwiftGen.
Motivation.
Using asset path string directly is not safe.
# pubspec.yaml
flutter:
assets:
- assets/images/profile.jpg
❌ Bad
What would happen if you made a typo?
Widget build(BuildContext context) {
return Image.asset('assets/images/profile.jpeg');
}
// The following assertion was thrown resolving an image codec:
// Unable to load asset: assets/images/profile.jpeg
⭕️ Good
We want to use it safely.
Widget build(BuildContext context) {
return Assets.images.profile.image();
}
Installation
Run fluttergen
after the configuration pubspec.yaml
.
Use this package as an executable
Using a Homebrew Formula
- Install FlutterGen
$ brew install FlutterGen/tap/fluttergen
- Use FlutterGen
$ fluttergen -h
$ fluttergen -c example/pubspec.yaml
Using a Dart command-line
- Install FlutterGen
$ pub global activate flutter_gen
$ export PATH="$PATH":"$HOME/.pub-cache/bin"
- Use FlutterGen
$ fluttergen -h
$ fluttergen -c example/pubspec.yaml
Use this package as a part of build_runner
- Add build_runner and FlutterGen to your package's pubspec.yaml file:
dev_dependencies:
build_runner:
flutter_gen_runner:
- Install FlutterGen
$ flutter pub get
- Use FlutterGen
$ flutter packages pub run build_runner build
Configuration file
FlutterGen generates dart files based on the key flutter
and flutter_gen
of pubspec.yaml
.
# pubspec.yaml
# ...
flutter_gen:
output: lib/gen/ # Optional (default: lib/gen/)
lineLength: 80 # Optional (default: 80)
integrations:
flutter_svg: true
colors:
inputs:
- assets/color/colors.xml
flutter:
uses-material-design: true
assets:
- assets/images/
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: assets/fonts/Raleway-Italic.ttf
style: italic
Available Parsers
Assets
Just follow the doc Adding assets and images#Specifying assets to specify assets, then FlutterGen will generate related dart files.
No other specific configuration is required.
Ignore duplicated.
# pubspec.yaml
flutter:
assets:
- assets/images/
- assets/images/chip3/chip.jpg
- assets/images/chip4/chip.jpg
- assets/images/icons/paint.svg
- assets/json/fruits.json
- pictures/ocean_view.jpg
These configurations will generate assets.gen.dart
under the lib/gen/
directory by default.
Usage Example
FlutterGen generates Image class if the asset is Flutter supported image format.
Example results of assets/images/chip.jpg
:
-
Assets.images.chip
is an implementation ofAssetImage class
. -
Assets.images.chip.image(...)
returnsImage class
. -
Assets.images.chip.path
just returns the path string.
Widget build(BuildContext context) {
return Image(image: Assets.images.chip);
}
Widget build(BuildContext context) {
return Assets.images.chip.image(
width: 120,
height: 120,
fit: BoxFit.scaleDown,
);
Widget build(BuildContext context) {
// Assets.images.chip.path = 'assets/images/chip3/chip3.jpg'
return Image.asset(Assets.images.chip.path);
}
If you are using SVG images with flutter_svg you can use the integration feature.
# pubspec.yaml
flutter_gen:
integrations:
flutter_svg: true
flutter:
assets:
- assets/images/icons/paint.svg
Widget build(BuildContext context) {
return Assets.images.icons.paint.svg(
width: 120,
height: 120
);
}
In other cases, the asset is generated as String class.
// If don't use the Integrations.
final svg = SvgPicture.asset(Assets.images.icons.paint);
final json = await rootBundle.loadString(Assets.json.fruits);
FlutterGen also support generating other style of Assets
class:
# pubspec.yaml
flutter_gen:
assets:
# Assets.imagesChip
# style: camel-case
# Assets.images_chip
# style: snake-case
# Assets.images.chip (default style)
# style: dot-delimiter
flutter:
assets:
- assets/images/chip.png
The root directory will be omitted if it is either assets
or asset
.
assets/images/chip3/chip.jpg => Assets.images.chip3.chip
assets/images/chip4/chip.jpg => Assets.images.chip4.chip
assets/images/icons/paint.svg => Assets.images.icons.paint
assets/json/fruits.json => Assets.json.fruits
pictures/ocean_view.jpg => Assets.pictures.oceanView
<details><summary>Example of code generated by FlutterGen</summary>
<p>
/// GENERATED CODE - DO NOT MODIFY BY HAND
/// *****************************************************
/// FlutterGen
/// *****************************************************
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter/services.dart';
class $PicturesGen {
const $PicturesGen();
AssetGenImage get chip5 => const AssetGenImage('pictures/chip5.jpg');
}
class $AssetsImagesGen {
const $AssetsImagesGen();
AssetGenImage get chip1 => const AssetGenImage('assets/images/chip1.jpg');
AssetGenImage get chip2 => const AssetGenImage('assets/images/chip2.jpg');
$AssetsImagesChip3Gen get chip3 => const $AssetsImagesChip3Gen();
$AssetsImagesChip4Gen get chip4 => const $AssetsImagesChip4Gen();
$AssetsImagesIconsGen get icons => const $AssetsImagesIconsGen();
AssetGenImage get logo => const AssetGenImage('assets/images/logo.png');
AssetGenImage get profile => const AssetGenImage('assets/images/profile.jpg');
}
class $AssetsJsonGen {
const $AssetsJsonGen();
String get fruits => 'assets/json/fruits.json';
}
class $AssetsImagesChip3Gen {
const $AssetsImagesChip3Gen();
AssetGenImage get chip3 =>
const AssetGenImage('assets/images/chip3/chip3.jpg');
}
class $AssetsImagesChip4Gen {
const $AssetsImagesChip4Gen();
AssetGenImage get chip4 =>
const AssetGenImage('assets/images/chip4/chip4.jpg');
}
class $AssetsImagesIconsGen {
const $AssetsImagesIconsGen();
SvgGenImage get fuchsia =>
const SvgGenImage('assets/images/icons/fuchsia.svg');
SvgGenImage get kmm => const SvgGenImage('assets/images/icons/kmm.svg');
SvgGenImage get paint => const SvgGenImage('assets/images/icons/paint.svg');
}
class Assets {
Assets._();
static const $AssetsImagesGen images = $AssetsImagesGen();
static const $AssetsJsonGen json = $AssetsJsonGen();
static const $PicturesGen pictures = $PicturesGen();
}
class AssetGenImage extends AssetImage {
const AssetGenImage(String assetName)
: _assetName = assetName,
super(assetName);
final String _assetName;
Image image({
ImageFrameBuilder frameBuilder,
ImageLoadingBuilder loadingBuilder,
ImageErrorWidgetBuilder errorBuilder,
String semanticLabel,
bool excludeFromSemantics = false,
double width,
double height,
Color color,
BlendMode colorBlendMode,
BoxFit fit,
AlignmentGeometry alignment = Alignment.center,
ImageRepeat repeat = ImageRepeat.noRepeat,
Rect centerSlice,
bool matchTextDirection = false,
bool gaplessPlayback = false,
bool isAntiAlias = false,
FilterQuality filterQuality = FilterQuality.low,
}) {
return Image(
image: this,
frameBuilder: frameBuilder,
loadingBuilder: loadingBuilder,
errorBuilder: errorBuilder,
semanticLabel: semanticLabel,
excludeFromSemantics: excludeFromSemantics,
width: width,
height: height,
color: color,
colorBlendMode: colorBlendMode,
fit: fit,
alignment: alignment,
repeat: repeat,
centerSlice: centerSlice,
matchTextDirection: matchTextDirection,
gaplessPlayback: gaplessPlayback,
isAntiAlias: isAntiAlias,
filterQuality: filterQuality,
);
}
String get path => _assetName;
}
class SvgGenImage {
const SvgGenImage(this._assetName);
final String _assetName;
SvgPicture svg({
bool matchTextDirection = false,
AssetBundle bundle,
String package,
double width,
double height,
BoxFit fit = BoxFit.contain,
AlignmentGeometry alignment = Alignment.center,
bool allowDrawingOutsideViewBox = false,
WidgetBuilder placeholderBuilder,
Color color,
BlendMode colorBlendMode = BlendMode.srcIn,
String semanticsLabel,
bool excludeFromSemantics = false,
Clip clipBehavior = Clip.hardEdge,
}) {
return SvgPicture.asset(
_assetName,
matchTextDirection: matchTextDirection,
bundle: bundle,
package: package,
width: width,
height: height,
fit: fit,
alignment: alignment,
allowDrawingOutsideViewBox: allowDrawingOutsideViewBox,
placeholderBuilder: placeholderBuilder,
color: color,
colorBlendMode: colorBlendMode,
semanticsLabel: semanticsLabel,
excludeFromSemantics: excludeFromSemantics,
clipBehavior: clipBehavior,
);
}
String get path => _assetName;
}
</p>
</details>
Fonts
Just follow the doc Use a custom font to specify fonts, then FlutterGen will generate related dart files.
No other specific configuration is required.
Ignore duplicated.
# pubspec.yaml
flutter:
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: assets/fonts/Raleway-Italic.ttf
style: italic
- family: RobotoMono
fonts:
- asset: assets/fonts/RobotoMono-Regular.ttf
- asset: assets/fonts/RobotoMono-Bold.ttf
weight: 700
These configurations will generate fonts.gen.dart
under the lib/gen/
directory by default.
Usage Example
Text(
'Hi there, I\'m FlutterGen',
style: TextStyle(
fontFamily: FontFamily.robotoMono,
fontFamilyFallback: const [FontFamily.raleway],
),
<details><summary>Example of code generated by FlutterGen</summary>
<p>
/// GENERATED CODE - DO NOT MODIFY BY HAND
/// *****************************************************
/// FlutterGen
/// *****************************************************
class FontFamily {
FontFamily._();
static const String raleway = 'Raleway';
static const String robotoMono = 'RobotoMono';
}
</p>
</details>
Colors
FlutterGen supports generating colors from XML format files.
Ignore duplicated.
# pubspec.yaml
flutter_gen:
colors:
inputs:
- assets/color/colors.xml
- assets/color/colors2.xml
FlutterGen generates MaterialColor class
if the element has the attribute type="material"
, otherwise a normal Color class will be generated.
<color name="milk_tea">#F5CB84</color>
<color name="cinnamon" type="material">#955E1C</color>
These configurations will generate colors.gen.dart
under the lib/gen/
directory by default.
Usage Example
Text(
'Hi there, I\'m FlutterGen',
style: TextStyle(
color: ColorName.denim,
),
<details><summary>Example of code generated by FlutterGen</summary>
<p>
/// GENERATED CODE - DO NOT MODIFY BY HAND
/// *****************************************************
/// FlutterGen
/// *****************************************************
import 'package:flutter/painting.dart';
import 'package:flutter/material.dart';
class ColorName {
ColorName._();
static const Color black = Color(0xFF000000);
static const Color black30 = Color(0x4D000000);
static const Color black40 = Color(0x66000000);
static const Color black50 = Color(0x80000000);
static const Color black60 = Color(0x99000000);
static const MaterialColor crimsonRed = MaterialColor(
0xFFCF2A2A,
<int, Color>{
50: Color(0xFFF9E5E5),
100: Color(0xFFF1BFBF),
200: Color(0xFFE79595),
300: Color(0xFFDD6A6A),
400: Color(0xFFD64A4A),
500: Color(0xFFCF2A2A),
600: Color(0xFFCA2525),
700: Color(0xFFC31F1F),
800: Color(0xFFBD1919),
900: Color(0xFFB20F0F),
},
);
static const Color gray410 = Color(0xFF979797);
static const Color gray70 = Color(0xFFEEEEEE);
static const Color white = Color(0xFFFFFFFF);
static const MaterialColor yellowOcher = MaterialColor(
0xFFDF9527,
<int, Color>{
50: Color(0xFFFBF2E5),
100: Color(0xFFF5DFBE),
200: Color(0xFFEFCA93),
300: Color(0xFFE9B568),
400: Color(0xFFE4A547),
500: Color(0xFFDF9527),
600: Color(0xFFDB8D23),
700: Color(0xFFD7821D),
800: Color(0xFFD27817),
900: Color(0xFFCA670E),
},
);
}
</p>
</details>
Issues
Please file FlutterGen specific issues, bugs, or feature requests in our issue tracker.
Plugin issues that are not specific to FlutterGen can be filed in the Flutter issue tracker.
Contributing
We are looking for co-developers.
If you wish to contribute a change to any of the existing plugins in this repo,
please review our contribution guide
and open a pull request.
Milestone
- Documentation (English proofreading)
- Assets generation
- Fonts generation
-
Colors generation
- Support xml
- Support change output path
-
Support hierarchical generation
'assets/image/home/label.png' => Assets.image.home.label
'assets/image/detail/label.png' => Assets.image.detail.label - Platforms channels generation
Discussion