Normally, I use a separate class with an object declared on the top of the widget. I wish to know what is the problem with that architecture.
I came across an entire package in Flutter, WidgetView, which needs to declare a dependency, then make a state object, and then do the same thing.
Why not just a simple class for achieving the same. like below
class NewAccountComponent extends StatelessWidget {
final NewAccountComponentLogic logic = NewAccountComponentLogic();
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Enter a Unique Account Number'),
titlePadding: EdgeInsets.all(20.0),
content: TextFormField(
controller: logic.controller,
onPressed: () => logic.clearTextFormField(),
),
),
}
class NewAccountComponentLogic {
static String accountNumber;
static bool existsAccountNumber;
TextEditingController controller = TextEditingController();
clearTextFormField() {
controller.text = '';
accountNumber = '';
}
You can separate widget logic and presentation in many ways. One that I've seen (and that you mention) is using the WidgetView pattern. You can do it without any dependency:
For Stateless widgets:
abstract class StatelessView<T1> extends StatelessWidget {
final T1 widget;
const StatelessView(this.widget, {Key key}) : super(key: key);
@override
Widget build(BuildContext context);
}
For Stateful widgets:
abstract class WidgetView<T1, T2> extends StatelessWidget {
final T2 state;
T1 get widget => (state as State).widget as T1;
const WidgetView(this.state, {Key key}) : super(key: key);
@override
Widget build(BuildContext context);
}
// Note it's a StatefulWidget because accountNumber mutates
class NewAccountComponent extends StatefulWidget {
@override
_NewAccountComponentState createState() => _NewAccountComponentState();
}
class _NewAccountComponentState extends State<NewAccountComponent> {
String accountNumber;
bool existsAccountNumber;
final TextEditingController controller = TextEditingController();
clearTextFormField() {
controller.text = '';
accountNumber = '';
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Enter a Unique Account Number'),
titlePadding: EdgeInsets.all(20.0),
content: TextFormField(
controller: controller,
onSaved: (value) => clearTextFormField(),
),
);
}
}
Stateful
class NewAccountComponent extends StatefulWidget {
@override
_NewAccountComponentController createState() => _NewAccountComponentController();
}
// State suffix renamed to Controller
// This class has all widget logic
class _NewAccountComponentController extends State<NewAccountComponent> {
String accountNumber;
bool existsAccountNumber;
final TextEditingController controller = TextEditingController();
clearTextFormField() {
controller.text = '';
accountNumber = '';
}
// In build, returns a new instance of your view, sending the current state
@override
Widget build(BuildContext context) => _NewAccountComponentView(this);
}
// View extends of WidgetView and has a current state to access widget logic
// with widget you can access to StatefulWidget parent
class _NewAccountComponentView
extends WidgetView<NewAccountComponent, _NewAccountComponentController> {
_NewAccountComponentView(_NewAccountComponentController state): super(state);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Enter a Unique Account Number'),
titlePadding: EdgeInsets.all(20.0),
content: TextFormField(
controller: state.controller,
onSaved: (value) => state.clearTextFormField(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
final String textContent = "Hello!";
const MyStatelessWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Text(textContent),
);
}
}
to:
// Widget and logic controller are unit
class MyStatelessWidget extends StatelessWidget {
final String textContent = "Hello!";
const MyStatelessWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) => _MyStatelessView(this);
}
// The view is separately
class _MyStatelessView extends StatelessView<MyStatelessWidget> {
_MyStatelessView(MyStatelessWidget widget) : super(widget);
@override
Widget build(BuildContext context) {
return Container(
child: Text(widget.textContent),
);
}
}
References:
Flutter: WidgetView — A Simple Separation of Layout and Logic
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With