Last active
July 5, 2024 06:52
-
-
Save PlugFox/629202b0a7bcde8de3a7503bd33308bc to your computer and use it in GitHub Desktop.
Controlled Stateful Widget
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Controlled Stateful Widget | |
* https://gist.github.com/PlugFox/629202b0a7bcde8de3a7503bd33308bc | |
* https://dartpad.dev?id=629202b0a7bcde8de3a7503bd33308bc | |
* Mike Matiunin <plugfox@gmail.com>, 05 July 2024 | |
*/ | |
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
void main() { | |
final controller = Controller(); | |
runApp( | |
MaterialApp( | |
home: Scaffold( | |
body: SafeArea( | |
child: Center( | |
child: Controlled( | |
controller: controller, | |
), | |
), | |
), | |
), | |
), | |
); | |
Timer.periodic(const Duration(seconds: 5), (_) => controller.showSnackBar()); | |
} | |
final class Controller with ChangeNotifier { | |
Controller({int? value}) : _value = value ?? 0; | |
/// Current value | |
int get value => _value; | |
int _value = 0; | |
/// Increment value | |
void increment() { | |
_value++; | |
notifyListeners(); | |
} | |
/// Show snack bar with current value | |
void showSnackBar() { | |
if (_showSnackBar == null) throw Exception('Is not set to widget'); | |
_showSnackBar?.call(); | |
} | |
void Function()? _showSnackBar; | |
} | |
class Controlled extends StatefulWidget { | |
const Controlled({ | |
this.controller, | |
super.key, | |
}); | |
final Controller? controller; | |
static Controller? maybeOf(BuildContext context) => | |
context.findAncestorStateOfType<_ControlledState>()?._controller; | |
@override | |
State<Controlled> createState() => _ControlledState(); | |
} | |
class _ControlledState extends State<Controlled> { | |
Controller? _controller; | |
@override | |
void initState() { | |
super.initState(); | |
_controller = (widget.controller ?? Controller()) | |
..addListener(_onChanged) | |
.._showSnackBar = _showSnackBar; | |
} | |
@override | |
void didUpdateWidget(covariant Controlled oldWidget) { | |
super.didUpdateWidget(oldWidget); | |
if (!identical(widget.controller, oldWidget.controller)) { | |
_controller | |
?.._showSnackBar = null | |
..removeListener(_onChanged); | |
_controller = (widget.controller ?? Controller(value: _controller?.value)) | |
.._showSnackBar = _showSnackBar | |
..addListener(_onChanged); | |
} | |
} | |
@override | |
void dispose() { | |
_controller | |
?.._showSnackBar = null | |
..removeListener(_onChanged); | |
super.dispose(); | |
} | |
void _onChanged() { | |
if (!mounted) return; | |
setState(() {}); | |
} | |
void _showSnackBar() { | |
if (!mounted) return; | |
ScaffoldMessenger.maybeOf(context) | |
?..clearSnackBars() | |
..showSnackBar( | |
SnackBar( | |
content: Text('Value: ${_controller?.value ?? 0}'), | |
duration: const Duration(seconds: 2), | |
), | |
); | |
} | |
@override | |
Widget build(BuildContext context) => ElevatedButton.icon( | |
icon: const Icon(Icons.add), | |
label: Text('${_controller?.value ?? 0}'), | |
onPressed: () => _controller?.increment(), | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment