StatefulWidget Binder
A lightweight, type-safe Flutter package to bind controllers to StatefulWidgets with automatic lifecycle management and reactivity.
Features
- ๐ฏ Type-Safe: Full type-safe access to your controller within the
Stateclass. - ๐ Reactive: Automatically rebuilds when your controller notifies changes (if it's
Listenable). - ๐งน Clean Lifecycle: Automatically disposes controllers when widgets are removed from the tree.
- ๐ Encapsulated: Keeps core implementation details clean and private.
Getting started
Add stateful_widget_binder to your pubspec.yaml:
dependencies:
stateful_widget_binder: ^1.0.2
Usage
1. Define your Controller
Option A: Reactive Controller (Recommended)
Extend ListenableController for a fully reactive experience. The UI will automatically rebuild when notifyListeners() is called.
class CounterController extends ListenableController {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // Triggers UI update
}
}
Option B: Pure Disposable Controller
Implement or extend DisposableController if you don't need automatic UI rebuilds (e.g., for background services, loggers, or manually managed state).
class LogManager extends DisposableController {
@override
void dispose() {
print('Cleaning up resources...');
}
}
2. Create your Widget and State
Simply extend StatefulWidgetBinder for the widget and StateController for the state:
class CounterWidget extends StatefulWidgetBinder {
// Pass the controller through the constructor to the super class
const CounterWidget({super.key, required super.controller});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
// Specify the Widget and Controller types for type-safe access
class _CounterWidgetState extends StateController<CounterWidget, CounterController> {
@override
Widget build(BuildContext context) {
// The 'controller' getter is already typed as CounterController
return Scaffold(
body: Center(child: Text('Count: ${controller.count}')),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: const Icon(Icons.add),
),
);
}
}
Advanced Options
You can tune the lifecycle and reactivity behavior directly through the constructor:
CounterWidget(
controller: myController,
disposeController: false, // Default is true. Prevents calling controller.dispose() automatically.
rebuildOnNotify: false, // Default is true. Stops the UI from rebuilding on controller updates.
)
Additional information
This package is designed for developers who want a lightweight way to separate business logic from the UI without the overhead of heavy frameworks. It bridges the gap between pure StatefulWidget and high-level state management libraries.