katana_listenables 1.2.0 katana_listenables: ^1.2.0 copied to clipboard
The base part of the package that allows Listenable values to be grouped together and treated as a ChangeNotifier.
Katana Listenables
[YouTube] | [Packages] | [Twitter] | [LinkedIn]
Motivation #
You may want to manage multiple TextEditingControllers, ValueNotifiers, and other controllers that inherit these ChangeNotifiers when creating widgets.
It would then generally look something like the following.
- Define multiple ChangeNotifier inherited classes in State
- Create a class inheriting from ChangeNotifier for use in the state management package and addListener for all
I have created the following package to simplify the above implementation.
- Create a class inheriting from ChageNotofier with a simple description
- Monitor its parameters by passing an object inheriting from ChageNotofier as a parameter.
- When a change occurs in a monitored ChageNotifier, the change is propagated to its own object.
For example, the following statement is used
@listenables
class ControllerGroup with _$ControllerGroup, ChangeNotifier {
factory ControllerGroup({
required TextEditingController emailTextEditingController,
required TextEditingController passwordTextEditingController,
required FocusNode focusNode,
ValueNotifier<bool> checkTerms,
}) = _ControllerGroup;
}
When build_runner is run with this, a class inheriting from ChangeNotifier (Listenable) given as an argument is automatically generated.
If you load this in riverpod, for example, as follows…
final controllerProvider = ChangeNotifierProvider((_) {
return ControllerGroup(
emailTextEditingController: TextEdigingController(),
passwordTextEditingController: TextEdigingController(),
focusNode: FocusNode(),
checkTerms: ValueNotifier(false),
);
});
class TestPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref){
final controller = ref.watch(controllerProvider);
~~~~
controller.emailTextEditingController.text = "New Text"; // At this time, the controller is also notified of the change and the widget is updated again.
~~~~
}
}
When the contents of emailTextEditingController
defined in the controller
are updated, the change notification is propagated to the controller
as well.
Since the controller is also a ChangeNotifier, changes can be monitored by addListener
, etc.
Installation #
Import the following package for code generation using build_runner.
flutter pub add katana_listenables
flutter pub add --dev build_runner
flutter pub add --dev katana_listenables_builder
Implementation #
Make a Class #
Create a class as follows
Add part '(filename).listenable.dart';
.
Annotate the defined class with @listenables
and mixin _$(defined class name)
and ChangeNotifier
.
The constructor is created in the factory
and defines classes that inherit from ChangeNotifier and Listenable that you want to use in the parameters.
(Required values are marked "required
"; if "required" is not marked, leave it as it is.)
After the constructor, write = _ (the name of the defined class)
.
// controller.dart
import 'package:flutter/material.dart';
import 'package:katana_listenables/katana_listenables.dart';
part 'controller.listenable.dart';
@listenables
class ControllerGroup with _$ControllerGroup, ChangeNotifier {
factory ControllerGroup({
required TextEditingController emailTextEditingController,
required TextEditingController passwordTextEditingController,
required FocusNode focusNode,
ValueNotifier<bool> checkTerms,
}) = _ControllerGroup;
}
Code Generation #
Automatic code generation is performed by entering the following command.
flutter pub run build_runner build --delete-conflicting-outputs
How to use #
Since the created class inherits from ChangeNotifier, it can be used in the same way as a general ChangeNotifier.
- For State
class TestPage extends StatefulWidget {
@override
State<StatefulWidget> createState => TestPageState();
}
class TestPageState extends State<TestPage> {
final controller = ControllerGroup(
emailTextEditingController: TextEdigingController(),
passwordTextEditingController: TextEdigingController(),
focusNode: FocusNode(),
checkTerms: ValueNotifier(false),
);
@override
void initState(){
super.initState();
controller.addListener(_handledOnUpdate);
}
void _handledOnUpdate(){
setState((){});
}
@override
void dispose(){
super.dispose();
controller.removeListener(_handledOnUpdate);
controller.dispose();
}
@override
Widget build(BuildContext context, WidgetRef ref){
final controller = ref.watch(controllerProvider);
~~~~
controller.emailTextEditingController.text = "New Text"; // At this time, the controller is also notified of the change and the widget is updated again.
~~~~
}
}
- For riverpod
final controllerProvider = ChangeNotifierProvider((_) {
return ControllerGroup(
emailTextEditingController: TextEdigingController(),
passwordTextEditingController: TextEdigingController(),
focusNode: FocusNode(),
checkTerms: ValueNotifier(false),
);
});
class TestPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref){
final controller = ref.watch(controllerProvider);
~~~~
controller.emailTextEditingController.text = "New Text"; // At this time, the controller is also notified of the change and the widget is updated again.
~~~~
}
}
Additional Usage #
Adding Methods #
To add a method, use the following writing style.
(defined class name). _();
constructor must be added.
// controller.dart
import 'package:flutter/material.dart';
import 'package:katana_listenables/katana_listenables.dart';
part 'controller.listenable.dart';
@listenables
class ControllerGroup with _$ControllerGroup, ChangeNotifier {
factory ControllerGroup({
required TextEditingController emailTextEditingController,
required TextEditingController passwordTextEditingController,
required FocusNode focusNode,
ValueNotifier<bool> checkTerms,
}) = _ControllerGroup;
ControllerGroup._(); // Additional Required
bool checked {
return checkTerms?.value ?? false;
}
}