Ошибка флаттера GridView.builder, если список пуст

Вот фрагмент кода, в котором есть проблема (запущен на эмуляторе Android):

          GridView.builder(
                  padding: const EdgeInsets.all(10),
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: _columNum,
                    crossAxisSpacing: 10,
                    mainAxisSpacing: 10,
                  ),
                  itemCount: myColorList.length,
                  itemBuilder: (context, i) {
                    return Container(
                      color: myColorList[i],
                      child: GestureDetector(
                        onTap: () {
                          setState(() {
                            myColorList[i] = Color(
                                    (math.Random().nextDouble() * 0xFFFFFF)
                                        .toInt())
                                .withOpacity(1.0);
                            // _columNum >= myColorList.length? _columNum = 1 : _columNum++;
/*                      myColorList.removeLast();
                      if (_columNum > myColorList.length && _columNum > 1) {
                        _columNum--;
                      }*/
                          });
                        },
                      ),
                    );
                  },
                )

Когда я пытаюсь запустить это с пустым myColorList, я получаю много ошибок (вот только первая из-за ограничения на количество символов. Вы можете воспроизвести ее с помощью кода):

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performLayout():
SliverGeometry is not valid: The "scrollExtent" is negative.

The RenderSliver that returned the offending geometry was: RenderSliverGrid#feba7 relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-PAINT
...  parentData: paintOffset=Offset(0.0, 0.0) (can use size)
...  constraints: SliverConstraints(AxisDirection.down, GrowthDirection.forward, ScrollDirection.idle, scrollOffset: 0.0, remainingPaintExtent: 593.4, crossAxisExtent: 391.4, crossAxisDirection: AxisDirection.right, viewportMainAxisExtent: 603.4, remainingCacheExtent: 843.4, cacheOrigin: 0.0)
...  geometry: SliverGeometry(scrollExtent: -10.0, hidden, maxPaintExtent: -10.0)
...    scrollExtent: -10.0
...    hidden
...    maxPaintExtent: -10.0
...  no children current live
The relevant error-causing widget was: 
  GridView GridView:file:///C:/Users/rodri/AndroidStudioProjects/gestion_ganadera/lib/grid_page.dart:36:20
When the exception was thrown, this was the stack: 
#0      SliverGeometry.debugAssertIsValid.<anonymous closure>.verify (package:flutter/src/rendering/sliver.dart:711:9)
#1      SliverGeometry.debugAssertIsValid.<anonymous closure> (package:flutter/src/rendering/sliver.dart:720:7)
#2      SliverGeometry.debugAssertIsValid (package:flutter/src/rendering/sliver.dart:750:6)
#3      RenderSliver.debugAssertDoesMeetConstraints (package:flutter/src/rendering/sliver.dart:1205:22)
#4      RenderObject.layout.<anonymous closure> (package:flutter/src/rendering/object.dart:1890:9)
#5      RenderObject.layout (package:flutter/src/rendering/object.dart:1892:8)
#6      RenderSliverEdgeInsetsPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:137:12)
#7      RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:371:11)
#8      RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#9      RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:510:13)
#10     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1580:12)
#11     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1489:20)
#12     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#13     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#14     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#15     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#16     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#17     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#18     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#19     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#20     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#21     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#22     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#23     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#24     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#25     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#26     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#27     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#28     RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:545:11)
#29     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#30     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#31     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#32     ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:56:11)
#33     RenderStack._computeSize (package:flutter/src/rendering/stack.dart:570:43)
#34     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:597:12)
#35     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#36     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:171:12)
#37     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1005:7)
#38     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:240:7)
#39     RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:403:14)
#40     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#41     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#42     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#43     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#44     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1376:11)
#45     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#46     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#47     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#48     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#49     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#50     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#51     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#52     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#53     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#54     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#55     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#56     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#57     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#58     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#59     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#60     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#61     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#62     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#63     RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3430:13)
#64     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#65     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#66     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#67     _RenderTheatre.performLayout (package:flutter/src/widgets/overlay.dart:751:15)
#68     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#69     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#70     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#71     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#72     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#73     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#74     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#75     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#76     RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:545:11)
#77     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#78     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#79     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#80     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#81     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#82     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#83     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#84     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
#85     RenderObject.layout (package:flutter/src/rendering/object.dart:1887:7)
#86     RenderView.performLayout (package:flutter/src/rendering/view.dart:165:14)
#87     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1731:7)
#88     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:887:18)
#89     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:497:19)
#90     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:883:13)
#91     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)
#92     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
#93     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1081:9)
#94     SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:862:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
The following RenderObject was being processed when the exception was fired: RenderSliverGrid#feba7 relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-PAINT
...  parentData: paintOffset=Offset(0.0, 0.0) (can use size)
...  constraints: SliverConstraints(AxisDirection.down, GrowthDirection.forward, ScrollDirection.idle, scrollOffset: 0.0, remainingPaintExtent: 593.4, crossAxisExtent: 391.4, crossAxisDirection: AxisDirection.right, viewportMainAxisExtent: 603.4, remainingCacheExtent: 843.4, cacheOrigin: 0.0)
...  geometry: SliverGeometry(scrollExtent: -10.0, hidden, maxPaintExtent: -10.0)
...    scrollExtent: -10.0
...    hidden
...    maxPaintExtent: -10.0
...  no children current live
RenderObject: RenderSliverGrid#feba7 relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-PAINT
  parentData: paintOffset=Offset(0.0, 0.0) (can use size)
  constraints: SliverConstraints(AxisDirection.down, GrowthDirection.forward, ScrollDirection.idle, scrollOffset: 0.0, remainingPaintExtent: 593.4, crossAxisExtent: 391.4, crossAxisDirection: AxisDirection.right, viewportMainAxisExtent: 603.4, remainingCacheExtent: 843.4, cacheOrigin: 0.0)
  geometry: SliverGeometry(scrollExtent: -10.0, hidden, maxPaintExtent: -10.0)
    scrollExtent: -10.0
    hidden
    maxPaintExtent: -10.0
  no children current live
====================================================================================================

Решение, которое я нашел, просто игнорирует виджет GridView и оценивает его раньше, если список пуст:

myColorList.isNotEmpty ?
          GridView.builder(
                  padding: const EdgeInsets.all(10),
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: _columNum,
                    crossAxisSpacing: 10,
                    mainAxisSpacing: 10,
                  ),
                  itemCount: myColorList.length,
                  itemBuilder: (context, i) {
                    return Container(
                      color: myColorList[i],
                      child: GestureDetector(
                        onTap: () {
                          setState(() {
                            myColorList[i] = Color(
                                    (math.Random().nextDouble() * 0xFFFFFF)
                                        .toInt())
                                .withOpacity(1.0);
                            // _columNum >= myColorList.length? _columNum = 1 : _columNum++;
/*                      myColorList.removeLast();
                      if (_columNum > myColorList.length && _columNum > 1) {
                        _columNum--;
                      }*/
                          });
                        },
                      ),
                    );
                  },
                )
              : Container(),

Итак, мой вопрос: нет ли лучшего способа решить это внутри GridView.builder и почему это происходит.

Вот полный код:

import 'package:flutter/material.dart';
import 'dart:math' as math;

class GridPage extends StatefulWidget {
  final List<Color> myColorList;

  const GridPage({Key? key, required this.myColorList}) : super(key: key);

  @override
  State<GridPage> createState() => _GridPageState();
}

class _GridPageState extends State<GridPage> {
  int _columNum = 1;
  bool _scaleDone = false;
  List<Color> myColorList = [];

  @override
  void initState() {
    for (var color in widget.myColorList) {
      myColorList.add(color);
    }

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('GRIDVIEW TEST'),
      ),
      body: Stack(
        children: <Widget>[
          myColorList.isNotEmpty ?
          GridView.builder(
                  padding: const EdgeInsets.all(10),
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: _columNum,
                    crossAxisSpacing: 10,
                    mainAxisSpacing: 10,
                  ),
                  itemCount: myColorList.length,
                  itemBuilder: (context, i) {
                    return Container(
                      color: myColorList[i],
                      child: GestureDetector(
                        onTap: () {
                          setState(() {
                            myColorList[i] = Color(
                                    (math.Random().nextDouble() * 0xFFFFFF)
                                        .toInt())
                                .withOpacity(1.0);
                            // _columNum >= myColorList.length? _columNum = 1 : _columNum++;
/*                      myColorList.removeLast();
                      if (_columNum > myColorList.length && _columNum > 1) {
                        _columNum--;
                      }*/
                          });
                        },
                      ),
                    );
                  },
                )
              : Container(),
          GestureDetector(
            onScaleUpdate: (details) {
              setState(() {
                if (details.scale > 1 &&
                    _columNum < myColorList.length &&
                    !_scaleDone) {
                  _columNum++;
                  _scaleDone = true;
                } else if (details.scale < 1 && _columNum > 1 && !_scaleDone) {
                  _columNum--;
                  _scaleDone = true;
                }
              });
            },
            onScaleEnd: (details) {
              setState(() {
                _scaleDone = false;
              });
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            myColorList.add(
                Color((math.Random().nextDouble() * 0xFFFFFF).toInt())
                    .withOpacity(1.0));
          });
        },
        tooltip: 'Add color',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Я новичок в флаттере и программировании в целом, поэтому буду очень признателен, если вы увидите что-то странное в моем коде и сообщите мне об этом.

1
0
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:project_control_space/src/constant/color/color.dart';
import 'dart:math' as math;

class Testing1 extends StatefulWidget {
  const Testing1({super.key});

  @override
  State<Testing1> createState() => _Testing1State();
}

class _Testing1State extends State<Testing1> {
  List myColorList = [
    Colors.red,
    Colors.red[100],
    Colors.red[200],
    Colors.red[400],
    Colors.red[600],
    Colors.red[700],
    Colors.red[900],
    Colors.blue,
    Colors.blue[100],
    Colors.blue[200],
    Colors.blue[400],
    Colors.blue[600],
    Colors.blue[700],
    Colors.blue[900],
    Colors.green,
    Colors.green[100],
    Colors.green[200],
    Colors.green[400],
    Colors.green[600],
    Colors.green[700],
    Colors.green[900],
    Colors.grey,
    Colors.grey[100],
    Colors.grey[200],
    Colors.grey[400],
    Colors.grey[600],
    Colors.grey[700],
    Colors.grey[900],
    Colors.yellow,
    Colors.yellow[100],
    Colors.yellow[200],
    Colors.yellow[400],
    Colors.yellow[600],
    Colors.yellow[700],
    Colors.yellow[900]
  ];
  int _columNum = 2;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: GridView.builder(
        padding: const EdgeInsets.all(10),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: _columNum,
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
        ),
        itemCount: myColorList.length,
        itemBuilder: (context, i) {
          return Container(
            color: myColorList[i],
            child: GestureDetector(
              onTap: () {
                setState(() {
                  myColorList[i] =
                      Color((math.Random().nextDouble() * 0xFFFFFF).toInt())
                          .withOpacity(1.0);
                  // _columNum >= myColorList.length? _columNum = 1 : _columNum++;
/*                      myColorList.removeLast();
                      if (_columNum > myColorList.length && _columNum > 1) {
                        _columNum--;
                      }*/
                });
              },
            ),
          );
        },
      )),
    );
  }
}

Я использую ваш код и добавляю colors его работу со мной, и вы можете использовать его.

Большое спасибо за ваш ответ. Я попробовал ваш код, и он работает хорошо. Было моей ошибкой думать, что выданные ошибки были в GridView.builder, но теперь я думаю, что проблема внутри виджета Stack и его дочерней иерархии, потому что GridView находится поверх GestureDetector. Я до сих пор вообще не знаю, почему это происходит. Знаете ли вы какой-либо другой метод реализации обнаружения жестов на этом маршруте и только в теле «скафолда»? Также спасибо за виджет «SafeArea», о котором я еще не знал.

Drick 25.10.2022 22:20

Другие вопросы по теме