Flutter:可滚动列内的列表视图在 AlertDialog 中不起作用

问题描述 投票:0回答:1

我试图在 AlertDialog 内的已可滚动列中包含列表视图。我发现如果我使用

NeverScrollablePhysics()
shrinkWrap: true
SingleChildScrollView()
应该可以工作。

我尝试了在 StackOverflow 和 Medium 上看到的多个其他问题的解决方案,但它们都不起作用,我怀疑它是在对话框中导致问题的。

这是我的 showDialog 方法的代码:

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          scrollable: true,
          insetPadding: EdgeInsets.symmetric(
            // vertical: context.height * 0.05,
            horizontal: context.width * 0.05,
          ),
          contentPadding: EdgeInsets.symmetric(
            vertical: context.height * 0.02,
            horizontal: context.width * 0.05,
          ),
          title: Text(
            "Booster '${post.title}'",
            style: TextStyle(
              color: context.thirdColor,
              fontSize: context.width * 0.05,
              fontWeight: FontWeight.bold,
            ),
          ),
          content: StatefulBuilder(builder: (context, refresh) {
            return SingleChildScrollView(
              physics: ScrollPhysics(),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Container(
                    height: context.height * 0.06,
                    width: context.width,
                    padding: EdgeInsets.symmetric(
                      horizontal: context.width * 0.02,
                    ),
                    child: Text(
                      "Choisissez parmi nos offres pour booster votre annonce",
                      style: TextStyle(
                        color: const Color.fromARGB(
                          255,
                          87,
                          87,
                          87,
                        ),
                        fontSize: context.height * 0.017,
                        fontWeight: FontWeight.w500,
                      ),
                    ),
                  ),
                  Container(
                    height: context.width * 0.06,
                    child: Text(
                      "Les boosts",
                      style: TextStyle(
                        color: context.secondaryColor,
                        fontSize: context.height * 0.02,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  Expanded(
                    // constraints: BoxConstraints(
                    //   minHeight: context.height * 0.15,
                    // ),
                    // width: context.width * 0.9,
                    child: ListView.builder(
                      itemCount: getBoosts().length,
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemBuilder: (context, index) {
                        Map<String, dynamic> boost = getBoosts()[index];
                        return ListTile(
                          contentPadding: EdgeInsets.zero,
                          dense: true,
                          tileColor: boost["name"] == selectedBoost["name"]
                              ? context.thirdColor.withOpacity(0.1)
                              : Colors.transparent,
                          onTap: () {
                            if (boost["name"] != selectedBoost["name"]) {
                              selectedBoost = boost;
                              refresh(() {});
                            } else {
                              selectedBoost = {};
                              refresh(() {});
                            }
                          },
                          leading: //radio selected if boost["name"] == selectedBoost["name"]
                              SizedBox(
                                  width: context.width * 0.05,
                                  child: Icon(
                                    Icons.arrow_right_rounded,
                                    color: Colors.grey,
                                  )),
                          title: Text(
                            boost["name"],
                            style: TextStyle(
                              color: Colors.black,
                              fontSize: context.height * 0.017,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          subtitle: Text(
                            boost["price"] + " FCFA",
                            style: TextStyle(
                              color: Colors.grey,
                              // color: context.thirdColor,
                              fontWeight: FontWeight.bold,
                              fontSize: context.height * 0.015,
                            ),
                          ),
                          trailing: //if boost["name"] == selectedBoost["name"] then show check icon
                              selectedBoost["name"] == boost["name"]
                                  ? Icon(
                                      Icons.check,
                                      color: context.thirdColor,
                                    )
                                  : null,
                        );
                      },
                    ),
                  ),
                  Container(
                    height: context.width * 0.06,
                    width: context.width * 0.9,
                    child: Text(
                      "Les publicités",
                      style: TextStyle(
                        color: context.secondaryColor,
                        fontSize: context.height * 0.02,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  Expanded(
                    child: ListView.builder(
                      itemCount: getAds().length,
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemBuilder: (context, index) {
                        Map<String, dynamic> ad = getAds()[index];
                        return ListTile(
                          dense: true,
                          minVerticalPadding: 0,
                          contentPadding: EdgeInsets.zero,
                          onTap: () {
                            if (ad["name"] != selectedAd["name"]) {
                              selectedAd = ad;
                              refresh(() {});
                            } else {
                              selectedAd = {};
                              refresh(() {});
                            }
                          },
                          tileColor: ad["name"] == selectedAd["name"]
                              ? context.thirdColor.withOpacity(0.1)
                              : Colors.transparent,
                          leading: //radio selected if ad["name"] == selectedAd["name"]
                              SizedBox(
                            width: context.width * 0.05,
                            child: Icon(
                              Icons.arrow_right_rounded,
                              color: Colors.grey,
                            ),
                          ),
                          title: Text(
                            ad["name"],
                            style: TextStyle(
                              color: Colors.black,
                              fontSize: context.height * 0.017,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          subtitle: Text(
                            ad["price"] + " FCFA",
                            style: TextStyle(
                              color: Colors.grey,
                              // color: context.thirdColor,
                              fontWeight: FontWeight.bold,
                              fontSize: context.height * 0.015,
                            ),
                          ),
                          trailing: //if ad["name"] == selectedAd["name"] then show check icon
                              selectedAd["name"] == ad["name"]
                                  ? Icon(
                                      Icons.check,
                                      color: context.thirdColor,
                                    )
                                  : null,
                        );
                      },
                    ),
                  ),
                ],
              ),
            );
          }),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text(
                "Annuler",
                style: TextStyle(
                  color: context.primaryColor,
                  fontSize: context.height * 0.02,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            ElevatedButton(
              onPressed: () {
                showDialog(
                  context: context,
                  //invisible background
                  barrierColor: Colors.transparent,
                  builder: (context) {
                    return Center(
                      child: CircularProgressIndicator(),
                    );
                  },
                );
                int total = 0;
                String details = "";
                if (selectedAd.isEmpty & selectedBoost.isEmpty) {
                  return;
                }
                if (selectedAd.isNotEmpty) {
                  total += int.parse(selectedAd["price"]);
                  details += selectedAd["name"];
                }
                if (selectedBoost.isNotEmpty) {
                  total += int.parse(selectedBoost["price"]);
                  if (details.isNotEmpty) {
                    details += " \n|| ";
                  }
                  details += selectedBoost["name"];
                }

                CreateBoostPaymentUseCase()
                    .execute(
                  post,
                  total,
                  details,
                  categoryAd: selectedBoost["value"] ?? null,
                  homepageAd: selectedAd["value"] ?? null,
                )
                    .then((value) {
                  Navigator.pop(context);
                });
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: context.primaryColor,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
              child: Text(
                "Valider",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: context.height * 0.02,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ],
        );
      },
    );

也许问题是由于我使用 AlertDialog 的方式造成的,但我实际上对导致错误的原因感到困惑。这是我的完整错误:

he following assertion was thrown during performLayout():
RenderShrinkWrappingViewport does not support returning intrinsic dimensions.
Calculating the intrinsic dimensions would require instantiating every child of the viewport, which defeats the point of viewports being lazy.
If you are merely trying to shrink-wrap the viewport in the main axis direction, you should be able to achieve that effect by just giving the viewport loose constraints, without needing to measure its intrinsic dimensions.

The relevant error-causing widget was:
    AlertDialog AlertDialog:file:///Users/pulsar/development/flutter_workspace/smxew-mobile/lib/core/services.dart:1018:16

When the exception was thrown, this was the stack:

我跳过了堆栈跟踪...

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderIntrinsicWidth#3f98f relayoutBoundary=up5 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2165 pos 12: 'hasSize'
The relevant error-causing widget was:
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: _RenderInkFeatures#597aa relayoutBoundary=up4 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2165 pos 12: 'hasSize'
The relevant error-causing widget was:
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderCustomPaint#4fa77 relayoutBoundary=up3 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2165 pos 12: 'hasSize'
The relevant error-causing widget was:
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderPhysicalShape#e022d relayoutBoundary=up2 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2165 pos 12: 'hasSize'
The relevant error-causing widget was:
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════
'package:flutter/src/rendering/shifted_box.dart': Failed assertion: line 345 pos 12: 'child!.hasSize': is not true.
The relevant error-causing widget was:
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderPhysicalShape#e022d relayoutBoundary=up2
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2165 pos 12: 'hasSize'
The relevant error-causing widget was:
flutter mobile flutter-listview
1个回答
0
投票

我修复了您所面临的错误,方法是用 SizedBox 替换包裹 ListView 的扩展小部件,并为其提供任意尺寸。

请尝试以下代码,看看这是否是您正在寻找的功能。根据您的回复,我可以进一步帮助您。注意:我用示例文本替换了广告和增强内容,因为我不知道这些字段中会包含什么。

return AlertDialog(
  insetPadding: EdgeInsets.symmetric(
    horizontal: screenWidth(context) * 0.05,
  ),
  contentPadding: EdgeInsets.symmetric(
    vertical: screenHeight(context) * 0.02,
    horizontal: screenWidth(context) * 0.05,
  ),
  title: Text(
    "Booster",
    style: TextStyle(
      color: Colors.blue,
      fontSize: screenWidth(context) * 0.05,
      fontWeight: FontWeight.bold,
    ),
  ),
  content: StatefulBuilder(builder: (context, refresh) {
    return SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            height: screenHeight(context) * 0.06,
            width: screenWidth(context),
            padding: EdgeInsets.symmetric(
              horizontal: screenWidth(context) * 0.02,
            ),
            child: Text(
              "Choisissez parmi nos offres pour booster votre annonce",
              style: TextStyle(
                color: const Color.fromARGB(
                  255,
                  87,
                  87,
                  87,
                ),
                fontSize: screenHeight(context) * 0.017,
                fontWeight: FontWeight.w500,
              ),
            ),
          ),
          SizedBox(
            height: screenWidth(context) * 0.06,
            child: Text(
              "Les boosts",
              style: TextStyle(
                color: Colors.black,
                fontSize: screenHeight(context) * 0.02,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          SizedBox(
            height: screenHeight(context) * 0.25,
            width: screenWidth(context),
            child: ListView.builder(
              itemCount: 15,
              itemBuilder: (context, index) {
                return ListTile(
                  contentPadding: EdgeInsets.zero,
                  dense: true,
                  tileColor: Colors.transparent,
                  onTap: () {
                    return;
                  },
                  leading: //radio selected if boost["name"] == selectedBoost["name"]
                      SizedBox(
                    width: screenWidth(context) * 0.05,
                    child: const Icon(
                      Icons.arrow_right_rounded,
                      color: Colors.grey,
                    ),
                  ),
                  title: Text(
                    "Test",
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: screenHeight(context) * 0.017,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  subtitle: Text(
                    "100 FCFA",
                    style: TextStyle(
                      color: Colors.grey,
                      // color: Colors.blue,
                      fontWeight: FontWeight.bold,
                      fontSize: screenHeight(context) * 0.015,
                    ),
                  ),
                  trailing: //if boost["name"] == selectedBoost["name"] then show check icon
                      const Icon(
                    Icons.check,
                    color: Colors.blue,
                  ),
                );
              },
            ),
          ),
          Container(
            height: screenWidth(context) * 0.06,
            width: screenWidth(context) * 0.9,
            child: Text(
              "Les publicités",
              style: TextStyle(
                color: Colors.black,
                fontSize: screenHeight(context) * 0.02,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          SizedBox(
            height: screenHeight(context) * 0.25,
            width: screenWidth(context),
            child: ListView.builder(
              itemCount: 10,
              itemBuilder: (context, index) {
                return ListTile(
                  dense: true,
                  minVerticalPadding: 0,
                  contentPadding: EdgeInsets.zero,
                  onTap: () {
                    return;
                  },
                  tileColor: Colors.transparent,
                  leading: //radio selected if ad["name"] == selectedAd["name"]
                      SizedBox(
                    width: screenWidth(context) * 0.05,
                    child: const Icon(
                      Icons.arrow_right_rounded,
                      color: Colors.grey,
                    ),
                  ),
                  title: Text(
                    "AD",
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: screenHeight(context) * 0.017,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  subtitle: Text(
                    "150 FCFA",
                    style: TextStyle(
                      color: Colors.grey,
                      // color: Colors.blue,
                      fontWeight: FontWeight.bold,
                      fontSize: screenHeight(context) * 0.015,
                    ),
                  ),
                  trailing: //if ad["name"] == selectedAd["name"] then show check icon
                      const Icon(
                    Icons.check,
                    color: Colors.blue,
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }),
  actions: [
    Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        TextButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text(
            "Annuler",
            style: TextStyle(
              color: Colors.red,
              fontSize: screenHeight(context) * 0.02,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
        ElevatedButton(
          onPressed: () => null,
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.white,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(10),
            ),
          ),
          child: Text(
            "Valider",
            style: TextStyle(
              color: Colors.blue,
              fontSize: screenHeight(context) * 0.02,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ],
    )
  ],
);
© www.soinside.com 2019 - 2024. All rights reserved.