You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用BoxConstraints无限宽度错误求助

Flutter约束错误:无限宽度问题解决

错误信息

FlutterError (BoxConstraints forces an infinite width.
These invalid constraints were provided to RenderParagraph's layout() function by the following function, which probably computed the invalid constraints in question:
  _RenderListTile._layoutBox (package:flutter/src/material/list_tile.dart:1274:9)
The offending constraints were:
  BoxConstraints(w=Infinity, 0.0<=h<=Infinity))

问题场景

尝试在Column中嵌套SingleChildScrollView实现血液捐赠请求卡片的横向滚动,期望卡片能在屏幕宽度内平滑滚动展示所有请求,但出现上述无限宽度约束错误。

原代码片段

import 'package:blood_token_app/models/services_model/blood_request_model.dart';
import 'package:blood_token_app/screens/main_screens/details_screen.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/svg.dart';

class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;

    return Scaffold(
      appBar: AppBar(
        title: Text('Blood Token'),
      ),
      body: Container(
        height: size.height,
        width: size.width,
        child: SingleChildScrollView(
          child: Column(
            children: [
              SizedBox(
                child: Padding(
                  padding:
                      const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                  child: Center(
                    child: Card(
                      color: Theme.of(context).scaffoldBackgroundColor,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20),
                      ),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          SvgPicture.asset(
                            "assets/logos/032-blood_bag.svg",
                            height: size.height * 0.18,
                          ),
                          Text(
                            "Donate Blood\n Save Lives",
                            textAlign: TextAlign.center,
                            style: TextStyle(
                              fontSize: size.height * 0.030,
                              color: Colors.black,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ),
              Column(
                children: [
                  ListTile(
                    title: Text(
                      'Current Requests',
                      style: TextStyle(fontSize: 20.0),
                    ),
                    trailing: Text('See all'),
                  ),
                  Expanded(
                    child: StreamBuilder<QuerySnapshot>(
                      stream: FirebaseFirestore.instance
                          .collection('blood_requests')
                          .snapshots(),
                      builder: (context, snapshot) {
                        if (snapshot.connectionState ==
                            ConnectionState.waiting) {
                          return AppUtils.customProgressIndicator();
                        }
                        if (snapshot.hasError) {
                          return Text('Error: ${snapshot.error}');
                        }
                        final List<BloodRequestModel> bloodRequests = snapshot
                            .data!.docs
                            .map((doc) => BloodRequestModel.fromJson(
                                doc.data() as Map<String, dynamic>))
                            .toList();

                        return Container(
                          width: MediaQuery.of(context)
                              .size
                              .width, // Ensure finite width
                          child: SingleChildScrollView(
                            scrollDirection: Axis.horizontal,
                            child: Row(
                              children: bloodRequests.map((value) {
                                return Padding(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 10, vertical: 10),
                                  child: Container(
                                    width:
                                        300, // Set a finite width as per your design
                                    decoration: BoxDecoration(
                                      shape: BoxShape.rectangle,
                                      boxShadow: [
                                        BoxShadow(
                                          color: Colors.grey.withOpacity(0.5),
                                          spreadRadius: 5,
                                          blurRadius: 7,
                                          offset: Offset(0, 3),
                                        ),
                                      ],
                                      color: Theme.of(context)
                                          .scaffoldBackgroundColor,
                                      borderRadius: BorderRadius.circular(20.0),
                                      border: Border.all(
                                        color: Colors.grey.shade100,
                                        width: 0.0,
                                      ),
                                    ),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        ListTile(
                                          title: Text(
                                            "Requester Name",
                                            textAlign: TextAlign.left,
                                            overflow: TextOverflow.ellipsis,
                                          ),
                                          subtitle: Text(
                                            "${value.requesterName}",
                                            textAlign: TextAlign.left,
                                            overflow: TextOverflow.ellipsis,
                                          ),
                                          trailing: Column(
                                            mainAxisAlignment:
                                                MainAxisAlignment.center,
                                            children: [
                                              Text("Urgency Level"),
                                              Text(
                                                "${value.urgencyLevel}",
                                                textAlign: TextAlign.left,
                                                overflow: TextOverflow.ellipsis,
                                              ),
                                            ],
                                          ),
                                        ),
                                        ListTile(
                                          title: Text("Location"),
                                          subtitle:
                                              Text("${value.customLocation}"),
                                          trailing: Column(
                                            mainAxisAlignment:
                                                MainAxisAlignment.center,
                                            children: [
                                              Text("Blood Type"),
                                              Text("${value.bloodType}"),
                                            ],
                                          ),
                                        ),
                                        ListTile(
                                          leading: Icon(Icons.watch_outlined),
                                          title: Text(
                                              "${value.formattedTimestamp()}"),
                                        ),
                                        MaterialButton(
                                          shape: RoundedRectangleBorder(
                                            borderRadius: BorderRadius.only(
                                              bottomLeft: Radius.circular(20),
                                              bottomRight: Radius.circular(20),
                                            ),
                                          ),
                                          height: size.height * 0.060,
                                          minWidth: size.width,
                                          color: AppUtils.redColor,
                                          onPressed: () {
                                            if (mounted) {
                                              Navigator.push(context,
                                                  MaterialPageRoute(
                                                      builder: (_) {
                                                return DetailsScreen(
                                                    requesterName:
                                                        value.requesterName,
                                                    bloodType: value.bloodType,
                                                    quantityNeeded:
                                                        value.quantityNeeded,
                                                    urgencyLevel:
                                                        value.urgencyLevel,
                                                    location: value.location,
                                                    contactNumber:
                                                        value.contactNumber,
                                                    patientName:
                                                        value.patientName,
                                                    date: value
                                                        .formattedTimestamp(),
                                                    customLocation:
                                                        value.customLocation,
                                                    // Convert latitude string to double
                                                    latitude: double.parse(value
                                                        .location!
                                                        .split(', ')[0]),
                                                    // Convert longitude string to double
                                                    longitude: double.parse(
                                                        value.location!
                                                            .split(', ')[1]));
                                              }));
                                            }
                                          },
                                          child: Text(
                                            "Details",
                                            style: TextStyle(
                                              color: AppUtils.whiteColor,
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                );
                              }).toList(),
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

问题根源

  1. Expanded在无限高度容器中失效:最外层SingleChildScrollView允许垂直无限滚动,内部Column高度无限制,导致嵌套的Expanded无法获取有效高度约束,进而引发子组件宽度约束异常。
  2. 按钮宽度设置错误:卡片内的MaterialButton使用minWidth: size.width,强制按钮宽度等于屏幕宽度,但卡片本身仅300宽度,打破布局约束。

修复方案

步骤1:调整布局结构,给请求卡片区域设置固定高度

将包含StreamBuilder的嵌套Column包裹在固定高度的Container中,确保Expanded能获取有效高度约束。

步骤2:修正按钮宽度

将MaterialButton的minWidth改为double.infinity,使其自适应卡片宽度。

步骤3:移除不必要的容器约束

删除最外层Container的height和width设置,Scaffold的body默认填充屏幕。

修复后的代码

import 'package:blood_token_app/models/services_model/blood_request_model.dart';
import 'package:blood_token_app/screens/main_screens/details_screen.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/svg.dart';

class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;

    return Scaffold(
      appBar: AppBar(
        title: Text('Blood Token'),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            SizedBox(
              child: Padding(
                padding:
                    const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                child: Center(
                  child: Card(
                    color: Theme.of(context).scaffoldBackgroundColor,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20),
                    ),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        SvgPicture.asset(
                          "assets/logos/032-blood_bag.svg",
                          height: size.height * 0.18,
                        ),
                        Text(
                          "Donate Blood\n Save Lives",
                          textAlign: TextAlign.center,
                          style: TextStyle(
                            fontSize: size.height * 0.030,
                            color: Colors.black,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
            // 给请求卡片区域设置固定高度
            Container(
              height: size.height * 0.6,
              child: Column(
                children: [
                  ListTile(
                    title: Text(
                      'Current Requests',
                      style: TextStyle(fontSize: 20.0),
                    ),
                    trailing: Text('See all'),
                  ),
                  Expanded(
                    child: StreamBuilder<QuerySnapshot>(
                      stream: FirebaseFirestore.instance
                          .collection('blood_requests')
                          .snapshots(),
                      builder: (context, snapshot) {
                        if (snapshot.connectionState ==
                            ConnectionState.waiting) {
                          return AppUtils.customProgressIndicator();
                        }
                        if (snapshot.hasError) {
                          return Text('Error: ${snapshot.error}');
                        }
                        final List<BloodRequestModel> bloodRequests = snapshot
                            .data!.docs
                            .map((doc) => BloodRequestModel.fromJson(
                                doc.data() as Map<String, dynamic>))
                            .toList();

                        return SingleChildScrollView(
                          scrollDirection: Axis.horizontal,
                          child: Row(
                            children: bloodRequests.map((value) {
                              return Padding(
                                padding: const EdgeInsets.symmetric(
                                    horizontal: 10, vertical: 10),
                                child: Container(
                                  width: 300,
                                  decoration: BoxDecoration(
                                    shape: BoxShape.rectangle,
                                    boxShadow: [
                                      BoxShadow(
                                        color: Colors.grey.withOpacity(0.5),
                                        spreadRadius: 5,
                                        blurRadius: 7,
                                        offset: Offset(0, 3),
                                      ),
                                    ],
                                    color: Theme.of(context)
                                        .scaffoldBackgroundColor,
                                    borderRadius: BorderRadius.circular(20.0),
                                    border: Border.all(
                                      color: Colors.grey.shade100,
                                      width: 0.0,
                                    ),
                                  ),
                                  child: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      ListTile(
                                        title: Text(
                                          "Requester Name",
                                          textAlign: TextAlign.left,
                                          overflow: TextOverflow.ellipsis,
                                        ),
                                        subtitle: Text(
                                          "${value.requesterName}",
                                          textAlign: TextAlign.left,
                                          overflow: TextOverflow.ellipsis,
                                        ),
                                        trailing: Column(
                                          mainAxisAlignment:
                                              MainAxisAlignment.center,
                                          children: [
                                            Text("Urgency Level"),
                                            Text(
                                              "${value.urgencyLevel}",
                                              textAlign: TextAlign.left,
                                              overflow: TextOverflow.ellipsis,
                                            ),
                                          ],
                                        ),
                                      ),
                                      ListTile(
                                        title: Text("Location"),
                                        subtitle:
                                            Text("${value.customLocation}"),
                                        trailing: Column(
                                          mainAxisAlignment:
                                              MainAxisAlignment.center,
                                          children: [
                                            Text("Blood Type"),
                                            Text("${value.bloodType}"),
                                          ],
                                        ),
                                      ),
                                      ListTile(
                                        leading: Icon(Icons.watch_outlined),
                                        title: Text(
                                            "${value.formattedTimestamp()}"),
                                      ),
                                      MaterialButton(
                                        shape: RoundedRectangleBorder(
                                          borderRadius: BorderRadius.only(
                                            bottomLeft: Radius.circular(20),
                                            bottomRight: Radius.circular(20),
                                          ),
                                        ),
                                        height: size.height * 0.060,
                                        minWidth: double.infinity, // 自适应卡片宽度
                                        color: AppUtils.redColor,
                                        onPressed: () {
                                          if (mounted) {
                                            Navigator.push(context,
                                                MaterialPageRoute(
                                                    builder: (_) {
                                              return DetailsScreen(
                                                  requesterName:
                                                      value.requesterName,
                                                  bloodType: value.bloodType,
                                                  quantityNeeded:
                                                      value.quantityNeeded,
                                                  urgencyLevel:
                                                      value.urgencyLevel,
                                                  location: value.location,
                                                  contactNumber:
                                                      value.contactNumber,
                                                  patientName:
                                                      value.patientName,
                                                  date: value
                                                      .formattedTimestamp(),
                                                  customLocation:
                                                      value.customLocation,
                                                  latitude: double.parse(value
                                                      .location!
                                                      .split(', ')[0]),
                                                  longitude: double.parse(
                                                      value.location!
                                                          .split(', ')[1]));
                                            }));
                                          }
                                        },
                                        child: Text(
                                          "Details",
                                          style: TextStyle(
                                            color: AppUtils.whiteColor,
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              );
                            }).toList(),
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Muhammad Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 02:09:55