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}