Skip to content

Commit 79e284b

Browse files
authored
v1: fix TabBarView (#5586)
* fix: improve TabBarView height handling * add test for nested Tabs
1 parent 27cea68 commit 79e284b

6 files changed

Lines changed: 103 additions & 39 deletions

File tree

packages/flet/lib/src/controls/tabs.dart

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -157,35 +157,48 @@ class TabBarViewControl extends StatelessWidget {
157157

158158
// Find the TabController from the nearest TabsControl ancestor
159159
final tabsState = context.findAncestorStateOfType<_TabsControlState>();
160-
if (tabsState != null) {
161-
final tabController = tabsState._tabController;
160+
if (tabsState == null) {
161+
return const ErrorControl(
162+
"TabBarView must be used within a Tabs control");
163+
}
164+
165+
final tabController = tabsState._tabController;
166+
167+
Widget buildConstrainedTabView() {
168+
return ConstrainedControl(
169+
control: control,
170+
child: TabBarView(
171+
controller: tabController,
172+
clipBehavior:
173+
control.getClipBehavior("clip_behavior", Clip.hardEdge)!,
174+
viewportFraction: control.getDouble("viewport_fraction", 1.0)!,
175+
children: control.buildWidgets("controls"),
176+
));
177+
}
162178

163-
return LayoutBuilder(
164-
builder: (BuildContext context, BoxConstraints constraints) {
165-
if (constraints.maxHeight == double.infinity &&
166-
control.getDouble("height") == null &&
167-
control.getExpand("expand", 0)! <= 0) {
179+
// If expand property was set, we return the result directly.
180+
// Because having Expanded as direct child of LayoutBuilder is not allowed.
181+
if (control.getExpand("expand", 0)! > 0) {
182+
return buildConstrainedTabView();
183+
}
184+
185+
return LayoutBuilder(
186+
builder: (context, constraints) {
187+
final hasFixedHeight = control.getDouble("height") != null;
188+
final hasUnboundedHeight =
189+
constraints.maxHeight == double.infinity && !hasFixedHeight;
190+
191+
if (hasUnboundedHeight) {
168192
return const ErrorControl(
169-
"Error displaying TabBarView: height is unbounded.",
170-
description:
171-
"Set a fixed height, a non-zero expand, or/and place inside "
172-
"a control with bounded height.");
193+
"Error displaying TabBarView: height is unbounded.",
194+
description:
195+
"Set a fixed height, a non-zero expand, or place it inside a control with bounded height.",
196+
);
173197
}
174198

175-
return ConstrainedControl(
176-
control: control,
177-
child: TabBarView(
178-
controller: tabController,
179-
clipBehavior:
180-
control.getClipBehavior("clip_behavior", Clip.hardEdge)!,
181-
viewportFraction: control.getDouble("viewport_fraction", 1.0)!,
182-
children: control.buildWidgets("controls"),
183-
));
184-
});
185-
} else {
186-
return const ErrorControl(
187-
"TabBarView must be used within a Tabs control");
188-
}
199+
return buildConstrainedTabView();
200+
},
201+
);
189202
}
190203
}
191204

sdk/python/examples/controls/tabs/nested.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def main(page: ft.Page):
1818
ft.TabBarView(
1919
expand=True,
2020
controls=[
21+
ft.Text("Main Tab 1 content"),
2122
ft.Tabs(
2223
length=2,
2324
expand=True,
@@ -41,7 +42,6 @@ def main(page: ft.Page):
4142
],
4243
),
4344
),
44-
ft.Text("Main Tab 1 content"),
4545
],
4646
),
4747
],
14.3 KB
Loading
23.9 KB
Loading
Binary file not shown.

sdk/python/packages/flet/integration_tests/controls/test_tabs.py

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
@pytest.mark.asyncio(loop_scope="module")
8-
async def test_tabs_basic(flet_app: ftt.FletTestApp, request):
8+
async def test_basic(flet_app: ftt.FletTestApp, request):
99
await flet_app.assert_control_screenshot(
1010
name=request.node.name,
1111
expand_screenshot=True,
@@ -19,20 +19,71 @@ async def test_tabs_basic(flet_app: ftt.FletTestApp, request):
1919
ft.Tab(label="Tab 2", icon=ft.Icons.SETTINGS),
2020
]
2121
),
22-
ft.Container(
22+
ft.TabBarView(
2323
expand=True,
24-
content=ft.TabBarView(
25-
controls=[
26-
ft.Container(
27-
content=ft.Text("This is Tab 1"),
28-
alignment=ft.Alignment.CENTER,
29-
),
30-
ft.Container(
31-
content=ft.Text("This is Tab 3"),
32-
alignment=ft.Alignment.CENTER,
24+
controls=[
25+
ft.Container(
26+
content=ft.Text("This is Tab 1"),
27+
alignment=ft.Alignment.CENTER,
28+
),
29+
ft.Container(
30+
content=ft.Text("This is Tab 3"),
31+
alignment=ft.Alignment.CENTER,
32+
),
33+
],
34+
),
35+
],
36+
),
37+
),
38+
)
39+
40+
41+
@pytest.mark.asyncio(loop_scope="module")
42+
async def test_nesting(flet_app: ftt.FletTestApp, request):
43+
await flet_app.assert_control_screenshot(
44+
name=request.node.name,
45+
expand_screenshot=True,
46+
control=ft.Tabs(
47+
length=2,
48+
expand=True,
49+
selected_index=1,
50+
content=ft.Column(
51+
expand=True,
52+
controls=[
53+
ft.TabBar(
54+
tabs=[
55+
ft.Tab(label=ft.Text("Main Tab 1")),
56+
ft.Tab(label=ft.Text("Main Tab 2")),
57+
],
58+
),
59+
ft.TabBarView(
60+
expand=True,
61+
controls=[
62+
ft.Text("Main Tab 1 content"),
63+
ft.Tabs(
64+
length=2,
65+
expand=True,
66+
content=ft.Column(
67+
expand=True,
68+
controls=[
69+
ft.TabBar(
70+
secondary=True,
71+
tabs=[
72+
ft.Tab(label=ft.Text("SubTab 1")),
73+
ft.Tab(label=ft.Text("SubTab 2")),
74+
],
75+
),
76+
ft.TabBarView(
77+
expand=True,
78+
controls=[
79+
ft.Text("Nested Tab 1 content"),
80+
ft.Text("Nested Tab 2 content"),
81+
],
82+
),
83+
],
3384
),
34-
],
35-
),
85+
),
86+
],
3687
),
3788
],
3889
),

0 commit comments

Comments
 (0)