Created
November 19, 2024 01:40
-
-
Save Andrious/fbe53696ff3c4f7d37c61b9a4472d35d to your computer and use it in GitHub Desktop.
A StatefulWidget that takes in a Listenable
This file contains hidden or 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
import 'package:flutter/foundation.dart'; | |
import 'package:flutter/material.dart'; | |
// Widget builder allows for null | |
typedef MaybeBuildWidgetType = Widget? Function(BuildContext context); | |
/// Creates a widget that rebuilds when the given listenable calls | |
/// notifyListeners() function | |
class ListenableWidgetBuilder extends StatefulWidget { | |
/// The arguments is not required. | |
const ListenableWidgetBuilder({ | |
super.key, | |
this.listenable, | |
this.builder, | |
}); | |
/// Checked in State object if, in fact, a Listenable | |
final dynamic listenable; | |
/// Supply a Widget builder | |
final MaybeBuildWidgetType? builder; | |
/// Subclasses typically do not override this method. | |
@override | |
State createState() => _ListenableState(); | |
@override | |
void debugFillProperties(DiagnosticPropertiesBuilder properties) { | |
super.debugFillProperties(properties); | |
properties.add(DiagnosticsProperty<Listenable>('listenable', listenable)); | |
} | |
} | |
// | |
class _ListenableState extends State<ListenableWidgetBuilder> { | |
// | |
@override | |
void initState() { | |
super.initState(); | |
// May actually be a Listenable | |
if (widget.builder != null && widget.listenable is Listenable) { | |
builder = widget.builder!; | |
listenable = widget.listenable; | |
listenable?.addListener(_callBuild); | |
} else { | |
// A widget must be provided. Even if it's nothing | |
builder = (_) => const SizedBox.shrink(); | |
} | |
} | |
// Possibly not provided | |
Listenable? listenable; | |
// A Widget will be returned no matter what is provided. | |
late MaybeBuildWidgetType builder; | |
// Store the past widget displayed, and use it if builder returns null. | |
Widget? _widget; | |
@override | |
void didUpdateWidget(ListenableWidgetBuilder oldWidget) { | |
super.didUpdateWidget(oldWidget); | |
// Possibly a O(2) expense if oldWidget == widget | |
if (oldWidget.listenable is Listenable) { | |
oldWidget.listenable?.removeListener(_callBuild); | |
} | |
if (widget.listenable is Listenable) { | |
widget.listenable?.addListener(_callBuild); | |
} | |
} | |
@override | |
void dispose() { | |
_widget = null; | |
listenable?.removeListener(_callBuild); | |
listenable = null; | |
super.dispose(); | |
} | |
void _callBuild() { | |
if (mounted) { | |
setState(() { | |
// Call the build() function again | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
final widget = builder.call(context); | |
// The builder is allowed to return null. | |
if (widget == null) { | |
_widget ??= const SizedBox.shrink(); | |
} else { | |
_widget = widget; | |
} | |
return _widget!; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment