Inflaters
Inflaters are responsible for dynamically constructing Flutter widgets from XML markup at runtime. They parse attributes and child elements, then generate the corresponding widget instances.
For example, this XML:
constructs the following widgets:
You can create inflaters for any class with a public constructor — not just widgets.
For example, BoxDecoration and TextStyle are helper classes that style widgets,
and they work the same way.
Defining an Inflater Spec
Create an inflater spec file (e.g., lib/xwidget/inflater_spec.dart):
import 'package:flutter/material.dart';
// Best Practice: Keep declarations in alphabetical order. It makes it much
// easier to quickly determine what has been added and what is missing.
const inflaters = [
AppBar,
Center,
Column,
Container,
FloatingActionButton,
Icon,
MaterialApp,
Padding,
Row,
Scaffold,
SizedBox,
Text,
TextStyle,
ThemeData,
];
Then reference it in xwidget_config.yaml:
How It Works
For each class in the inflaters list, the generator:
- Analyzes the class constructors using the Dart analyzer to discover all parameters.
- Generates an Inflater subclass that maps XML attributes to constructor arguments.
- Generates a
parseAttribute()method that converts string attribute values to the correct Dart types using configured parsers. - Generates a
registerXWidgetInflaters()function that registers all inflaters with XWidget. - Generates an XSD schema element for each widget with its attributes, enabling IDE code completion in XML fragments.
What to Include
Important
Only specify widgets that you actually use in your UI. Specifying unused widgets will bloat your app size because the generated inflater holds a static reference to each widget's constructor, which prevents tree-shaking from eliminating it.
Include:
- Flutter widgets you reference in XML fragments (e.g.,
Scaffold,Column,Text) - Non-widget classes used as attribute values (e.g.,
TextStyle,ThemeData,EdgeInsets) - Custom widgets annotated with
@InflaterDef
Do not include:
- Widgets only used in Dart code (they don't need inflaters)
- Utility classes, mixins, or abstract classes without constructors
Multiple Spec Files
You can split specifications across multiple files:
inflaters:
sources: [
"lib/xwidget/inflater_spec.dart",
"lib/xwidget/inflater_spec_material.dart",
"lib/xwidget/inflater_spec_custom.dart",
]
Include Files
Include files let you inject custom Dart code directly into the generated inflaters output. This is useful for helper functions or custom parsers that inflaters reference:
The contents of include files (excluding import statements) are copied verbatim into the generated output.
Constructor Exclusions
Exclude specific constructor arguments that should not be settable from XML:
inflaters:
constructor_exclusions: [
"CachedNetworkImage:imageRenderMethodForWeb",
"MyWidget:internalCallback",
]
The format is ClassName:argumentName. Use * for the class name to match any class
(e.g., *:debugLabel excludes debugLabel from all widgets).
Constructor Argument Defaults
Override default values for constructor arguments:
inflaters:
constructor_arg_defaults:
"Text:data": "XWidgetUtils.joinStrings(text)"
"WidgetSpan:alignment": "PlaceholderAlignment.middle"
"*:colorBlendMode": "BlendMode.srcIn"
The format is ClassName:argumentName. Use * for the class name to apply to all classes.
Constructor Argument Parsers
Define how string attribute values are parsed into Dart types. The generator uses these to
build the parseAttribute() method for each inflater:
inflaters:
constructor_arg_parsers:
# Parse by type name
"bool": "parseBool(value)"
"double": "parseDouble(value)"
"int": "parseInt(value)"
"Color": "parseColor(value)"
"EdgeInsets": "parseEdgeInsets(value)"
# Parse by attribute name (any class)
"*:width": "parseDouble(value)"
"*:height": "parseDouble(value)"
# Parse by class:attribute
"MyWidget:customProp": "parseCustomProp(value)"
The lookup priority is:
ClassName:argumentName— most specific*:argumentName— any class, specific argumentArgumentType— by type name
Enum types are automatically parsed without configuration.
Writing a Custom Parser
If XWidget's built-in parsers don't cover your type, write your own. A parser is a
function that takes a String? value and returns the parsed type:
Alignment? parseAlignment(String? value) {
if (value != null && value.isNotEmpty) {
switch (value) {
case 'topLeft': return Alignment.topLeft;
case 'topCenter': return Alignment.topCenter;
case 'topRight': return Alignment.topRight;
case 'centerLeft': return Alignment.centerLeft;
case 'center': return Alignment.center;
case 'centerRight': return Alignment.centerRight;
case 'bottomLeft': return Alignment.bottomLeft;
case 'bottomCenter': return Alignment.bottomCenter;
case 'bottomRight': return Alignment.bottomRight;
default: throw Exception("Invalid alignment value: $value");
}
}
return null;
}
Once you've created your parser:
- Register it in
xwidget_config.yamlunderconstructor_arg_parsers. - Add the import for the Dart file containing your parser under
imports, or place your parser in an include file to have it copied directly into the generated output.
Additional Imports
Sometimes the generator cannot resolve all required imports automatically (e.g., for types used in default values). Add them manually: