Moved to https://github.com/AlexV525/dartpad_workshops/tree/main/implement_lazy_indexed_stack permanentely.
-
-
Save AlexV525/6067934cdcad26ab082010a926b58ad1 to your computer and use it in GitHub Desktop.
Nice Job!
I improved this approach with lazy build child and null safety and it works fine
import 'package:flutter/material.dart';
typedef LazyWidgetBuilder = Widget Function(BuildContext context);
class LazyIndexedStack extends StatefulWidget {
const LazyIndexedStack({
Key? key,
required this.index,
required this.children,
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.sizing = StackFit.loose,
}) : super(key: key);
final int index;
final List<LazyWidgetBuilder> children;
final AlignmentGeometry alignment;
final TextDirection? textDirection;
final StackFit sizing;
@override
_LazyIndexedStackState createState() => _LazyIndexedStackState();
}
class _LazyIndexedStackState extends State<LazyIndexedStack> {
late Map<int, bool> _innerWidgetMap;
late int index;
@override
void initState() {
super.initState();
index = widget.index;
_innerWidgetMap = Map<int, bool>.fromEntries(
List<MapEntry<int, bool>>.generate(
widget.children.length,
(int i) => MapEntry<int, bool>(i, i == index),
),
);
}
@override
void didUpdateWidget(LazyIndexedStack oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.index != widget.index) {
_changeIndex(widget.index);
}
}
void _activeCurrentIndex(int index) {
if (_innerWidgetMap[index] != true) {
_innerWidgetMap[index] = true;
}
}
void _changeIndex(int value) {
if (value == index) {
return;
}
setState(() {
index = value;
});
}
bool _hasInit(int index) {
final bool? result = _innerWidgetMap[index];
if (result == null) {
return false;
}
return result == true;
}
List<Widget> _buildChildren(BuildContext context) {
final List<Widget> list = <Widget>[];
for (int i = 0; i < widget.children.length; i++) {
if (_hasInit(i)) {
list.add(widget.children[i].call(context));
} else {
list.add(const SizedBox.shrink());
}
}
return list;
}
@override
Widget build(BuildContext context) {
_activeCurrentIndex(index);
return IndexedStack(
index: index,
children: _buildChildren(context),
alignment: widget.alignment,
sizing: widget.sizing,
textDirection: widget.textDirection,
);
}
}
Oh...I do have a null-safe version. I'll update it then.
Thanks for the code! Here is an alternate version, that accounts for the child list size changing. It also doesn't accept a null index at all, which cleans up the code a little:
import 'package:flutter/material.dart';
/// A lazy-loading [IndexedStack] that loads [children] accordingly.
class LazyIndexedStack extends StatefulWidget {
const LazyIndexedStack({
Key? key,
this.alignment = AlignmentDirectional.topStart,
this.textDirection,
this.sizing = StackFit.loose,
this.index = 0,
this.children = const [],
}) : super(key: key);
final AlignmentGeometry alignment;
final TextDirection? textDirection;
final StackFit sizing;
final int index;
final List<Widget> children;
@override
_LazyIndexedStackState createState() => _LazyIndexedStackState();
}
class _LazyIndexedStackState extends State<LazyIndexedStack> {
late List<bool> _activated = _initializeActivatedList();
List<bool> _initializeActivatedList() => List<bool>.generate(widget.children.length, (int i) => i == widget.index);
@override
void didUpdateWidget(covariant LazyIndexedStack oldWidget) {
if (oldWidget.children.length != widget.children.length) {
_activated = _initializeActivatedList();
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
// Mark current index as active
_activated[widget.index] = true;
final children = List.generate(_activated.length, (i) {
return _activated[i] ? widget.children[i] : const SizedBox.shrink();
});
return IndexedStack(
alignment: widget.alignment,
sizing: widget.sizing,
textDirection: widget.textDirection,
index: widget.index,
children: children,
);
}
}
Other tweaks:
- moved the buildChildren method inside of build, as its only 3 lines when using list.generate
- Removed the check for
_activatedList[widget.index]
, looking it up is likely slower than just storing it
Thanks for the code! Here is an alternate version, that accounts for the child list size changing. It also doesn't accept a null index at all, which cleans up the code a little
Hi @esDotDev. Thanks for the feedback!
I've setup a workshop with the implementation at https://github.com/AlexV525/dartpad_workshops/tree/main/implement_lazy_indexed_stack, and I guess I'll redirect the gist to the workshop recently. Can you review it and see if your updates are still working with the workshop version?
This works perfectly with bottom bar, thanks for sharing