import 'package:wonders/common_libs.dart'; /// Decouples the scrollable area from the size of the PageView itself. /// Helps simplify the layout of the underlying view and can create a better UX with screen-readers. /// /// Internally it creates a stack with an invisible PageView on the bottom to handle scrolling, /// then drives a second PageController (follower) which is passed to the `builder` so a nested PageView can /// be created to hold the content itself. /// /// Scrolling of the nested PageView will then be driven by the outer one. /// class StackedPageViewBuilder extends StatefulWidget { const StackedPageViewBuilder({ Key? key, this.initialIndex = 0, required this.pageCount, required this.builder, this.onInit, }) : super(key: key); final int initialIndex; final int pageCount; final Widget Function(BuildContext builder, PageController controller, PageController follower) builder; final void Function(PageController controller, PageController follower)? onInit; @override State createState() => _StackedPageViewBuilderState(); } class _StackedPageViewBuilderState extends State { late final _controller = PageController(initialPage: widget.initialIndex); late final _follower = PageController(initialPage: widget.initialIndex); @override void initState() { super.initState(); _controller.addListener(_handleControllerChanged); widget.onInit?.call(_controller, _follower); } @override void dispose() { _controller.dispose(); _follower.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ Positioned.fill( child: ExcludeSemantics( child: PageView.builder( itemCount: widget.pageCount, controller: _controller, itemBuilder: (_, __) => Container(color: Colors.transparent), ), ), ), widget.builder(context, _controller, _follower), ], ); } void _handleControllerChanged() => _follower.jumpTo(_controller.position.pixels); }