main
  1import 'dart:collection';
  2
  3import 'package:flutter/material.dart';
  4import 'package:inline_tab_view/inline_tab_view.dart';
  5
  6/// A resizing view that associates a tab-bar and child widgets.
  7class FormSwitcher extends StatefulWidget {
  8  /// Create a resizing view that associates a tab-bar and child widgets-
  9  const FormSwitcher({super.key,
 10    required this.subForms,
 11    this.controller,
 12  });
 13
 14  /// List of (tab title, tab content) pairs.
 15  final List<(Widget, Widget)> subForms;
 16  
 17  /// Controller to use to control the switcher from code. 
 18  final FormSwitcherController? controller;
 19
 20  @override
 21  State<FormSwitcher> createState() => _FormSwitcherState();
 22}
 23
 24class _FormSwitcherState extends State<FormSwitcher>
 25    with TickerProviderStateMixin {
 26  late final TabController controller;
 27
 28  @override
 29  void initState() {
 30    super.initState();
 31    controller = TabController(length: widget.subForms.length, vsync: this);
 32    widget.controller?._initialize(controller);
 33  }
 34
 35  @override
 36  void dispose() {
 37    controller.dispose();
 38    super.dispose();
 39  }
 40
 41  @override
 42  Widget build(BuildContext context) {
 43    assert(widget.subForms.isNotEmpty);
 44    if (widget.subForms.length == 1) {
 45      return widget.subForms[0].$2;
 46    }
 47    return Column(
 48      mainAxisSize: MainAxisSize.min,
 49      children: [
 50        TabBar.secondary(
 51          controller: controller,
 52          tabs: [
 53            for (final f in widget.subForms)
 54              Padding(
 55                padding: EdgeInsets.all(8.0),
 56                child: f.$1,
 57              ),
 58          ],
 59        ),
 60        InlineTabView(
 61          controller: controller,
 62          children: [
 63            for (final f in widget.subForms)
 64              Padding(
 65                padding: EdgeInsets.only(top: 8.0),
 66                child: f.$2,
 67              ),
 68          ],
 69        ),
 70      ],
 71    );
 72  }
 73}
 74
 75/// Allows controlling a [FormSwitcher] from code.
 76class FormSwitcherController {
 77  final Queue<Function> _pendingActions = Queue();
 78
 79  TabController? _controller;
 80
 81  /// Add a reference to a TabController to control.
 82  /// 
 83  /// This does not mean this object is responsible for destroying it.
 84  void _initialize(TabController controller) {
 85    assert(_controller == null, 'FormSwitcherController was initialized twice');
 86    _controller = controller;
 87    while (_pendingActions.isNotEmpty) {
 88      _pendingActions.removeFirst().call();
 89    }
 90  }
 91
 92  /// Animates to viewing the page at the specified index as soon as possible.
 93  void animateTo(int index) {
 94    if (_controller == null) {
 95      _pendingActions.add(() => animateTo(index));
 96    } else {
 97      _controller!.animateTo(index);
 98    }
 99  }
100}