Skip to content

Instantly share code, notes, and snippets.

@PlugFox
Last active July 5, 2024 06:52
Show Gist options
  • Save PlugFox/629202b0a7bcde8de3a7503bd33308bc to your computer and use it in GitHub Desktop.
Save PlugFox/629202b0a7bcde8de3a7503bd33308bc to your computer and use it in GitHub Desktop.
Controlled Stateful Widget
/*
* 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