UI Components and Integration¶
SpWML provides several ways to integrate with Flutter, depending on your needs.
SpWMLView (Recommended for Screens)¶
Added in version 46.4.0. This is the most efficient way to build a complete screen. It automatically handles the lifecycle of the StateManager and supports asynchronous asset loading.
@override
Widget build(BuildContext context) {
return SpWMLView(
pathBuilder: (_) => "assets/layout.spwml",
onSetup: (context, builder, scope) {
final btn = builder.getSID("myButton") as BtnElement;
btn.setCallback(() {
// Your logic
});
},
);
}
SpWML (Basic Widget)¶
Use this when you want to display a SpWML string immediately as a widget. Since the SpWML class inherits from StatelessWidget, you can use it directly in the widget tree. However, this class cannot control the state. If you want to include buttons or other elements, you will need either SpWMLView or SpWMLBuilder.
// Simple usage
child: SpWML("(h1)Example text")
SpWMLDialog¶
Makes it easy to create complex, stateful dialogs without defining new classes. This class replaces the content portion of a Flutter alert dialog with SpWML.
If you need a more aesthetically pleasing dialog, you can use SpWMLView and wrap it in a Dialog. Bottom sheets and other elements can be customized in a similar way.
SpWMLBuilder b = SpWMLBuilder(layout);
b.setStateManager(Manager class stored in class variables etc.);
// or b.setManager(the manager class you want to use);
showDialog(
context: context,
builder: (context) {
return SpWMLDialog(
b,
const Text('Dialog title'),
width: 320, // The dialog width
cancelBtnCallback: (close) {
close();
},
okBtnCallback: (close) {
close();
},
);
});
Advanced: SpWMLBuilder¶
The SpWMLBuilder is the core engine. Use it directly for manual manipulations, such as replacing blocks with custom Flutter widgets before building.
SpWMLBuilder b = SpWMLBuilder(layout);
// Embedding Flutter widgets into SpWML "block"
b.replace("target_sid", MyCustomWidget());
// Replace children for multiple child elements like col or row
b.replaceUnderStructure("parent_sid", [Widget1(), Widget2()]);
Widget compiledWidget = b.build(context);
Interacting with Elements from Code¶
Except for stateless SpWML, elements can be accessed and modified via their sid regardless of the component being used.
// Get element by sid
BtnElement delBtn = builder.getElement("deleteButton") as BtnElement;
// Modify parameters directly
delBtn.setBGColor(Colors.red);
delBtn.textParams.p.isSelectable = true;
Note
Accessing element.params is not recommended as it is for internal use. Please use spwmlParams, elParams, or specific params like textParams.
State Management and Serialization¶
SpWML manages the state of UI elements (such as text field inputs or switch states) using the simple_managers package.
With SpWMLView (Automatic Management)¶
In SpWMLView, state management is handled automatically. You don’t need to manually create a StateManager. Use onInit to set initial values and scope.sm in onSetup to access the manager for serialization.
return SpWMLView(
pathBuilder: (_) => "assets/layout.spwml",
onInit: (sm) {
// 1. Pre-set values before UI build
sm.tfm.setText("user_name", "Taro Yamada");
},
onSetup: (context, builder, scope) {
// 2. Access the manager via scope.sm for serialization
final manager = scope.sm;
final Map<String, dynamic> json = manager.toDict(); // Save all states to JSON
// 3. Set callbacks for buttons
final btn = builder.getElement("saveBtn") as BtnElement;
btn.setCallback(() => print("Saved!"));
},
);
With SpWMLBuilder (Manual Management)¶
If you are using SpWMLBuilder directly, you must provide a StateManager instance yourself and manage its lifecycle.
// In your State Class
final manager = StateManager();
@override
void dispose() {
manager.dispose(); // Important: Manually dispose the manager
super.dispose();
}
@override
Widget build(BuildContext context) {
SpWMLBuilder b = SpWMLBuilder(layout);
b.setStateManager(manager); // Link the manager to the builder
return b.build(context);
}