Skip to content

Instantly share code, notes, and snippets.

@jonathanduke
Last active March 20, 2024 19:44
Show Gist options
  • Save jonathanduke/c09640adacacdff649ebfa0436e5a055 to your computer and use it in GitHub Desktop.
Save jonathanduke/c09640adacacdff649ebfa0436e5a055 to your computer and use it in GitHub Desktop.
ValueListenableBuilder that wraps an Offstage widget and exposes whether it will be offstage before building completes
import 'package:flutter/material.dart';
typedef OffstageEvaluator<T> = bool Function(T value);
class OffstageValueListenableBuilder<T> extends ValueListenableBuilder<T> {
final Key? offstageKey;
final OffstageEvaluator<T> offstageEvaluator;
OffstageValueListenableBuilder({
super.key,
this.offstageKey,
required this.offstageEvaluator,
required super.valueListenable,
required ValueWidgetBuilder<T> builder,
super.child,
}) : super(
builder: (context, value, child) => _buildOffstage(
context,
offstageKey,
offstageEvaluator,
value,
builder,
child,
));
bool get offstage => offstageEvaluator(valueListenable.value);
static Widget _buildOffstage<T>(
BuildContext context,
Key? offstageKey,
OffstageEvaluator<T> offstageEvaluator,
T value,
ValueWidgetBuilder<T> builder,
Widget? child,
) {
final offstage = offstageEvaluator(value);
return Offstage(
key: offstageKey,
offstage: offstage,
child: builder(context, value, child),
);
}
}
import "package:flutter/material.dart";
import "offstage_value_listenable_builder.dart";
class SpacedListView extends StatelessWidget {
final double spacing;
final List<Widget> children;
const SpacedListView({
super.key,
required this.spacing,
required this.children,
});
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context, index) => children[index],
separatorBuilder: (context, index) =>
_buildSeparator(context, spacing, children[index + 1]),
itemCount: children.length,
);
}
Widget _buildSeparator(BuildContext context, double spacing, Widget widget) {
if (widget is OffstageValueListenableBuilder) {
return ValueListenableBuilder(
valueListenable: widget.valueListenable,
builder: (context, value, child) => widget.offstage
? const SizedBox.shrink()
: SizedBox(height: spacing),
);
} else if (widget is Offstage && widget.offstage) {
return const SizedBox.shrink();
}
return SizedBox(height: spacing);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment