浏览代码

Taak 94 + 95a: P-Uitgaan naar een responsieve grid met lege-lijst-beeld

94 - PUitgaantabelKaartComponent gebruikte een PagedListView en toonde
daardoor ook op een tablet van 1280 dp een enkele kolom, terwijl Home en
beide horeca-overzichten al op 1/1/2/3 staan. Nu een PagedMasonryGridView
met Cross Axis Count als Responsive Value 1/1/2/3; shrinkWrap uit.
Infinite scroll en pull-to-refresh zijn ongeschonden door de Replace
gekomen, de page-binding is opnieuw aan Next Page Index gehangen.

Op PUitgaanPage moest daarvoor de scroll-structuur om: een masonry-grid
rendert niets in een SingleChildScrollView (leeg grijs vlak, geen fout).
De Column staat nu op niet-scrollend en het lijstcomponent op Expanded,
net als op Home. Gevolg voor de gebruiker: slider en advertentie staan
vast bovenaan en alleen de lijst scrollt.

FlutterFlow weigert die twee stappen in elke volgorde ("Invalid Action");
de uitweg was de Container eerst een vaste hoogte geven, dan de scroll
eraf, dan Expanded. Die tijdelijke hoogte is daarbij vanzelf vervallen -
de export heeft 0 height-waarden.

95a - Empty List Widget op datzelfde component (logo800px, gecentreerd),
zodat een lege lijst niet langer een leeg vlak is. De zes provincie-
horeca-tabs volgen nog (95b).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob 16 小时之前
父节点
当前提交
d9c4ccb323

+ 27 - 27
lib/uitgaanspaginas/p_uitgaan_page/p_uitgaan_page_widget.dart

@@ -155,32 +155,32 @@ class _PUitgaanPageWidgetState extends State<PUitgaanPageWidget>
             elevation: 2.0,
           ),
         ),
-        body: SingleChildScrollView(
-          child: Column(
-            mainAxisSize: MainAxisSize.max,
-            children: [
-              wrapWithModel(
-                model: _model.pUitgaanSliderComponentModel,
-                updateCallback: () => safeSetState(() {}),
-                child: Builder(builder: (_) {
-                  return DebugFlutterFlowModelContext(
-                    rootModel: _model.rootModel,
-                    child: PUitgaanSliderComponentWidget(
-                      townid: widget!.plaats,
-                      displayid: widget!.services,
-                    ),
-                  );
-                }),
-              ),
-              Padding(
-                padding: EdgeInsetsDirectional.fromSTEB(0.0, 15.0, 0.0, 0.0),
-                child: FlutterFlowAdBanner(
-                  showsTestAd: true,
-                  iOSAdUnitID: 'ca-app-pub-2431417692812232/5511582981',
-                  androidAdUnitID: 'ca-app-pub-2431417692812232/6657143691',
-                ),
+        body: Column(
+          mainAxisSize: MainAxisSize.max,
+          children: [
+            wrapWithModel(
+              model: _model.pUitgaanSliderComponentModel,
+              updateCallback: () => safeSetState(() {}),
+              child: Builder(builder: (_) {
+                return DebugFlutterFlowModelContext(
+                  rootModel: _model.rootModel,
+                  child: PUitgaanSliderComponentWidget(
+                    townid: widget!.plaats,
+                    displayid: widget!.services,
+                  ),
+                );
+              }),
+            ),
+            Padding(
+              padding: EdgeInsetsDirectional.fromSTEB(0.0, 15.0, 0.0, 0.0),
+              child: FlutterFlowAdBanner(
+                showsTestAd: true,
+                iOSAdUnitID: 'ca-app-pub-2431417692812232/5511582981',
+                androidAdUnitID: 'ca-app-pub-2431417692812232/6657143691',
               ),
-              Padding(
+            ),
+            Expanded(
+              child: Padding(
                 padding: EdgeInsets.all(10.0),
                 child: Container(
                   decoration: BoxDecoration(),
@@ -199,8 +199,8 @@ class _PUitgaanPageWidgetState extends State<PUitgaanPageWidget>
                   ),
                 ),
               ),
-            ],
-          ),
+            ),
+          ],
         ),
       ),
     );

+ 19 - 16
lib/uitgaanspaginas/p_uitgaantabel_kaart_component/p_uitgaantabel_kaart_component_model.dart

@@ -8,6 +8,7 @@ import 'p_uitgaantabel_kaart_component_widget.dart'
     show PUitgaantabelKaartComponentWidget;
 import 'package:flutter/material.dart';
 import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
 import 'package:google_fonts/google_fonts.dart';
 import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 import 'package:provider/provider.dart';
@@ -16,10 +17,10 @@ class PUitgaantabelKaartComponentModel
     extends FlutterFlowModel<PUitgaantabelKaartComponentWidget> {
   ///  State fields for stateful widgets in this component.
 
-  // State field(s) for ListView widget.
+  // State field(s) for StaggeredView widget.
 
-  PagingController<ApiPagingParams, dynamic>? listViewPagingController;
-  Function(ApiPagingParams nextPageMarker)? listViewApiCall;
+  PagingController<ApiPagingParams, dynamic>? staggeredViewPagingController;
+  Function(ApiPagingParams nextPageMarker)? staggeredViewApiCall;
 
   // Models for UitgaantabelKaart dynamic component.
   Map<String, FlutterFlowModel> uitgaantabelKaartModels = {};
@@ -32,18 +33,19 @@ class PUitgaantabelKaartComponentModel
 
   @override
   void dispose() {
-    listViewPagingController?.dispose();
+    staggeredViewPagingController?.dispose();
   }
 
   /// Additional helper methods.
-  PagingController<ApiPagingParams, dynamic> setListViewController(
+  PagingController<ApiPagingParams, dynamic> setStaggeredViewController(
     Function(ApiPagingParams) apiCall,
   ) {
-    listViewApiCall = apiCall;
-    return listViewPagingController ??= _createListViewController(apiCall);
+    staggeredViewApiCall = apiCall;
+    return staggeredViewPagingController ??=
+        _createStaggeredViewController(apiCall);
   }
 
-  PagingController<ApiPagingParams, dynamic> _createListViewController(
+  PagingController<ApiPagingParams, dynamic> _createStaggeredViewController(
     Function(ApiPagingParams) query,
   ) {
     final controller = PagingController<ApiPagingParams, dynamic>(
@@ -53,31 +55,32 @@ class PUitgaantabelKaartComponentModel
         lastResponse: null,
       ),
     );
-    return controller..addPageRequestListener(listViewUitgaanstabelPage);
+    return controller..addPageRequestListener(staggeredViewUitgaanstabelPage);
   }
 
-  void listViewUitgaanstabelPage(ApiPagingParams nextPageMarker) =>
-      listViewApiCall!(nextPageMarker).then((listViewUitgaanstabelResponse) {
+  void staggeredViewUitgaanstabelPage(ApiPagingParams nextPageMarker) =>
+      staggeredViewApiCall!(nextPageMarker)
+          .then((staggeredViewUitgaanstabelResponse) {
         final pageItems = (getJsonField(
-                  listViewUitgaanstabelResponse.jsonBody,
+                  staggeredViewUitgaanstabelResponse.jsonBody,
                   r'''$''',
                 ) ??
                 [])
             .toList() as List;
         final newNumItems = nextPageMarker.numItems + pageItems.length;
-        listViewPagingController?.appendPage(
+        staggeredViewPagingController?.appendPage(
           pageItems,
           (pageItems.length > 0)
               ? ApiPagingParams(
                   nextPageNumber: nextPageMarker.nextPageNumber + 1,
                   numItems: newNumItems,
-                  lastResponse: listViewUitgaanstabelResponse,
+                  lastResponse: staggeredViewUitgaanstabelResponse,
                 )
               : null,
         );
       });
 
-  Future waitForOnePageForListView({
+  Future waitForOnePageForStaggeredView({
     double minWait = 0,
     double maxWait = double.infinity,
   }) async {
@@ -86,7 +89,7 @@ class PUitgaantabelKaartComponentModel
       await Future.delayed(Duration(milliseconds: 50));
       final timeElapsed = stopwatch.elapsedMilliseconds;
       final requestComplete =
-          (listViewPagingController?.nextPageKey?.nextPageNumber ?? 0) > 0;
+          (staggeredViewPagingController?.nextPageKey?.nextPageNumber ?? 0) > 0;
       if (timeElapsed > maxWait || (requestComplete && timeElapsed > minWait)) {
         break;
       }

+ 26 - 14
lib/uitgaanspaginas/p_uitgaantabel_kaart_component/p_uitgaantabel_kaart_component_widget.dart

@@ -6,6 +6,7 @@ import '/uitgaanspaginas/uitgaantabel_kaart/uitgaantabel_kaart_widget.dart';
 import 'dart:async';
 import 'package:flutter/material.dart';
 import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
 import 'package:google_fonts/google_fonts.dart';
 import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 import 'package:provider/provider.dart';
@@ -122,21 +123,30 @@ class _PUitgaantabelKaartComponentWidgetState
           0.0),
       child: RefreshIndicator(
         onRefresh: () async {
-          safeSetState(() => _model.listViewPagingController?.refresh());
-          await _model.waitForOnePageForListView();
+          safeSetState(() => _model.staggeredViewPagingController?.refresh());
+          await _model.waitForOnePageForStaggeredView();
         },
-        child: PagedListView<ApiPagingParams, dynamic>(
-          pagingController: _model.setListViewController(
+        child: PagedMasonryGridView<ApiPagingParams, dynamic>.count(
+          pagingController: _model.setStaggeredViewController(
             (nextPageMarker) => UitgaanstabelCall.call(
-              page: nextPageMarker.nextPageNumber,
               townid: widget!.towndid,
               displayId: widget!.displayid,
+              page: nextPageMarker.nextPageNumber,
             ),
           ),
-          padding: EdgeInsets.zero,
-          shrinkWrap: true,
-          reverse: false,
-          scrollDirection: Axis.vertical,
+          crossAxisCount: () {
+            if (MediaQuery.sizeOf(context).width < kBreakpointSmall) {
+              return 1;
+            } else if (MediaQuery.sizeOf(context).width < kBreakpointMedium) {
+              return 1;
+            } else if (MediaQuery.sizeOf(context).width < kBreakpointLarge) {
+              return 2;
+            } else {
+              return 3;
+            }
+          }(),
+          crossAxisSpacing: 10.0,
+          mainAxisSpacing: 10.0,
           builderDelegate: PagedChildBuilderDelegate<dynamic>(
             // Customize what your widget looks like when it's loading the first page.
             firstPageProgressIndicatorBuilder: (_) => Center(
@@ -160,20 +170,22 @@ class _PUitgaantabelKaartComponentWidgetState
                 ),
               ),
             ),
-
+            noItemsFoundIndicatorBuilder: (_) => Image.asset(
+              'assets/images/logo800px.png',
+            ),
             itemBuilder: (context, _, evenementenIndex) {
-              final evenementenItem =
-                  _model.listViewPagingController!.itemList![evenementenIndex];
+              final evenementenItem = _model
+                  .staggeredViewPagingController!.itemList![evenementenIndex];
               return Builder(builder: (_) {
                 return DebugFlutterFlowModelContext(
                   rootModel: _model.rootModel,
                   parentModelCallback: (m) {
                     _model.uitgaantabelKaartModels[
-                        'Keybvr_${evenementenIndex}_of_${_model.listViewPagingController!.itemList!.length}'] = m;
+                        'Keybvr_${evenementenIndex}_of_${_model.staggeredViewPagingController!.itemList!.length}'] = m;
                   },
                   child: UitgaantabelKaartWidget(
                     key: Key(
-                        'Keybvr_${evenementenIndex}_of_${_model.listViewPagingController!.itemList!.length}'),
+                        'Keybvr_${evenementenIndex}_of_${_model.staggeredViewPagingController!.itemList!.length}'),
                     logo: getJsonField(
                       evenementenItem,
                       r'''$.logo''',