Skip to content

Commit 94afb26

Browse files
committed
Dynamic lazy building ListView and GridView controls
1 parent 7d8b197 commit 94afb26

File tree

4 files changed

+165
-28
lines changed

4 files changed

+165
-28
lines changed

client/lib/controls/grid_view.dart

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,34 @@ class GridViewControl extends StatelessWidget {
2626

2727
final horizontal = control.attrBool("horizontal", false)!;
2828
final runsCount = control.attrInt("runsCount", 1)!;
29+
final maxExtent = control.attrDouble("maxExtent");
2930
final spacing = control.attrDouble("spacing", 10)!;
3031
final runSpacing = control.attrDouble("runSpacing", 10)!;
3132
final padding = parseEdgeInsets(control, "padding");
3233

33-
List<Widget> controls =
34-
children.map((c) => createControl(control, c.id, disabled)).toList();
34+
List<Control> visibleControls = children.where((c) => c.isVisible).toList();
35+
36+
var gridDelegate = maxExtent == null
37+
? SliverGridDelegateWithFixedCrossAxisCount(
38+
crossAxisCount: runsCount,
39+
mainAxisSpacing: spacing,
40+
crossAxisSpacing: runSpacing,
41+
childAspectRatio: 1)
42+
: SliverGridDelegateWithMaxCrossAxisExtent(
43+
maxCrossAxisExtent: maxExtent,
44+
mainAxisSpacing: spacing,
45+
crossAxisSpacing: runSpacing,
46+
childAspectRatio: 1);
3547

3648
return constrainedControl(
37-
GridView.count(
49+
GridView.builder(
3850
scrollDirection: horizontal ? Axis.horizontal : Axis.vertical,
39-
crossAxisCount: runsCount,
40-
mainAxisSpacing: spacing,
41-
crossAxisSpacing: runSpacing,
4251
padding: padding,
43-
children: controls,
52+
gridDelegate: gridDelegate,
53+
itemCount: visibleControls.length,
54+
itemBuilder: (context, index) {
55+
return createControl(control, visibleControls[index].id, disabled);
56+
},
4457
),
4558
parent,
4659
control);

client/lib/controls/list_view.dart

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flutter/material.dart';
12
import 'package:flutter/widgets.dart';
23

34
import '../models/control.dart';
@@ -40,20 +41,7 @@ class ListViewControl extends StatelessWidget {
4041
final spacing = control.attrDouble("spacing", 0)!;
4142
final padding = parseEdgeInsets(control, "padding");
4243

43-
List<Widget> controls = [];
44-
45-
bool firstControl = true;
46-
for (var ctrl in children.where((c) => c.isVisible)) {
47-
// spacer between displayed controls
48-
if (spacing > 0 && !firstControl) {
49-
controls.add(
50-
horizontal ? SizedBox(width: spacing) : SizedBox(height: spacing));
51-
}
52-
firstControl = false;
53-
54-
// displayed control
55-
controls.add(createControl(control, ctrl.id, disabled));
56-
}
44+
List<Control> visibleControls = children.where((c) => c.isVisible).toList();
5745

5846
if (autoScroll) {
5947
WidgetsBinding.instance!.addPostFrameCallback((_) {
@@ -62,13 +50,33 @@ class ListViewControl extends StatelessWidget {
6250
}
6351

6452
return constrainedControl(
65-
ListView.builder(
66-
controller: _controller,
67-
scrollDirection: horizontal ? Axis.horizontal : Axis.vertical,
68-
padding: padding,
69-
itemBuilder: (context, index) {
70-
return null;
71-
}),
53+
spacing > 0
54+
? ListView.separated(
55+
controller: _controller,
56+
scrollDirection: horizontal ? Axis.horizontal : Axis.vertical,
57+
padding: padding,
58+
itemCount: children.length,
59+
itemBuilder: (context, index) {
60+
return createControl(
61+
control, visibleControls[index].id, disabled);
62+
},
63+
separatorBuilder: (context, index) {
64+
return Divider(height: spacing);
65+
},
66+
)
67+
: ListView.builder(
68+
controller: _controller,
69+
scrollDirection: horizontal ? Axis.horizontal : Axis.vertical,
70+
padding: padding,
71+
itemCount: children.length,
72+
itemBuilder: (context, index) {
73+
return createControl(
74+
control, visibleControls[index].id, disabled);
75+
},
76+
prototypeItem: children.isNotEmpty
77+
? createControl(control, visibleControls[0].id, disabled)
78+
: null,
79+
),
7280
parent,
7381
control);
7482
}

sdk/python/flet/grid_view.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def __init__(
2727
#
2828
horizontal: bool = None,
2929
runs_count: int = None,
30+
max_extent: int = None,
3031
spacing: OptionalNumber = None,
3132
run_spacing: OptionalNumber = None,
3233
padding: PaddingValue = None,
@@ -47,6 +48,7 @@ def __init__(
4748
self.controls = controls
4849
self.horizontal = horizontal
4950
self.runs_count = runs_count
51+
self.max_extent = max_extent
5052
self.spacing = spacing
5153
self.run_spacing = run_spacing
5254
self.padding = padding
@@ -77,6 +79,16 @@ def runs_count(self):
7779
def runs_count(self, value: Optional[int]):
7880
self._set_attr("runsCount", value)
7981

82+
# max_extent
83+
@property
84+
def max_extent(self):
85+
return self._get_attr("maxExtent")
86+
87+
@max_extent.setter
88+
@beartype
89+
def max_extent(self, value: OptionalNumber):
90+
self._set_attr("maxExtent", value)
91+
8092
# spacing
8193
@property
8294
def spacing(self):
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import logging
2+
import os
3+
from datetime import datetime
4+
from time import sleep
5+
6+
import flet
7+
from flet import (
8+
Column,
9+
Container,
10+
GridView,
11+
Icon,
12+
IconButton,
13+
ListView,
14+
OutlinedButton,
15+
Page,
16+
Row,
17+
Text,
18+
TextField,
19+
Theme,
20+
alignment,
21+
border,
22+
border_radius,
23+
colors,
24+
icons,
25+
padding,
26+
)
27+
28+
# logging.basicConfig(level=logging.DEBUG)
29+
30+
# fetch all icon constants from icons.py module
31+
icons_list = []
32+
list_started = False
33+
for name, value in vars(icons).items():
34+
if name == "TEN_K":
35+
list_started = True
36+
if list_started:
37+
icons_list.append(value)
38+
39+
os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000"
40+
41+
42+
def main(page: Page):
43+
page.title = "Flet icons browser"
44+
45+
search_txt = TextField(expand=1, hint_text="Enter keyword and press search button")
46+
# search_results = ListView(expand=1, wrap=True, scroll="always")
47+
# search_results = ListView(expand=1, spacing=2)
48+
search_results = GridView(
49+
expand=1, runs_count=10, max_extent=100, spacing=5, run_spacing=5
50+
)
51+
52+
def display_icons(search_term: str):
53+
54+
# clean search results
55+
search_results.controls.clear()
56+
page.update()
57+
58+
# add matching icons
59+
for i in range(0, len(icons_list)):
60+
if search_term != "" and search_term in icons_list[i]:
61+
search_results.controls.append(
62+
Container(
63+
content=Column(
64+
[
65+
Icon(
66+
name=icons_list[i],
67+
),
68+
Text(
69+
value=icons_list[i],
70+
size=10,
71+
width=100,
72+
# selectable=True,
73+
text_align="center",
74+
color=colors.BLACK87,
75+
),
76+
],
77+
spacing=5,
78+
alignment="center",
79+
horizontal_alignment="center",
80+
),
81+
alignment=alignment.center,
82+
padding=padding.only(left=5, right=5),
83+
# border=border.all(1, colors.BLACK26),
84+
bgcolor="#f0f0f0",
85+
border_radius=border_radius.all(3),
86+
)
87+
)
88+
print("Icons found:", len(search_results.controls))
89+
if len(search_results.controls) == 0:
90+
search_results.controls.append(
91+
Text(f'No icons found with text "{search_term}".')
92+
)
93+
page.update()
94+
95+
def search_click(e):
96+
display_icons(search_txt.value)
97+
98+
page.add(
99+
Row([search_txt, IconButton(icon=icons.SEARCH, on_click=search_click)]),
100+
search_results,
101+
)
102+
103+
104+
flet.app(name="test1", port=8550, target=main, view=flet.FLET_APP)

0 commit comments

Comments
 (0)