视口大于 maxwidth 时 SingleChildScrollView 渲染溢出

Posted

技术标签:

【中文标题】视口大于 maxwidth 时 SingleChildScrollView 渲染溢出【英文标题】:SingleChildScrollView rendering overflow when viewport greater than maxwidth 【发布时间】:2022-01-01 12:15:04 【问题描述】:

我正在尝试将网络内容设置为具有最大宽度(图像中的橙色),并始终填充可用高度,我已经达到了。

但是当窗口宽于最大内容宽度,并且窗口高度小于内容、页眉和页脚组合的高度时。我得到一个渲染溢出。 当我追求的是内容保持其高度和启用滚动时。

注意:如果每个文本只有 1 行值,问题似乎就解决了。

我尝试将 CustomeScrollViewSliverFillRemaining 一起使用,但遇到了同样的问题。

任何帮助将不胜感激。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget 
  const MyApp(Key? key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return const MaterialApp(
      title: 'Scrollable Layout',
      home: ScrollableLayout(),
    );
  


class ContentWidthContainer extends StatelessWidget 
  final Widget child;

  const ContentWidthContainer(Key? key, required this.child)
      : super(key: key);

  @override
  Widget build(BuildContext context) 
    return Container(
      color: Colors.grey,
      child: Align(
        alignment: Alignment.topCenter,
        child: Container(
            color: Colors.orange,
            width: double.infinity,
            constraints: const BoxConstraints(
              maxWidth: 960,
            ),
            padding: const EdgeInsets.symmetric(horizontal: 75),
            child: child),
      ),
    );
  


class ScrollableLayout extends StatelessWidget 
  const ScrollableLayout(Key? key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return DefaultTextStyle(
      style: Theme.of(context).textTheme.bodyText2!,
      child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints viewportConstraints) 
          return SingleChildScrollView(
            child: ConstrainedBox(
              constraints: BoxConstraints(
                minHeight: viewportConstraints.maxHeight,
              ),
              child: IntrinsicHeight(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    ContentWidthContainer(
                      child: Container(
                          color: Colors.indigo,
                          height: 200,
                          child: const Text('Header: Fixed Height')),
                    ),
                    Expanded(
                      child: ContentWidthContainer(
                        child: Container(
                            color: Colors.white,
                            child: Column(
                              children: const [
                                Text(
                                    'ContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContent'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                              ],
                            )),
                      ),
                    ),
                    ContentWidthContainer(
                      child: Container(
                          color: Colors.indigo,
                          height: 200,
                          child: const Text('Footer: Fixed Height')),
                    ),
                  ],
                ),
              ),
            ),
          );
        ,
      ),
    );
  

【问题讨论】:

【参考方案1】:

在将其更改为使用只有 2 个子项的 Column 并将对齐设置为 SpaceBetween 时,当您将窗口宽度设置为比内容短时溢出问题就会消失。

class ScrollableSpaceBetweenLayout extends StatelessWidget 
  const ScrollableSpaceBetweenLayout(Key? key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return DefaultTextStyle(
      style: Theme.of(context).textTheme.bodyText2!,
      child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints viewportConstraints) 
          return SingleChildScrollView(
            child: Container(
              color: Colors.black12, // the background / sides
              constraints: BoxConstraints(
                minHeight: viewportConstraints.maxHeight,
              ),
              child: Column(
                mainAxisSize: MainAxisSize.max,
                children: <Widget>[
                  Container(
                      color: Colors.indigo,
                      height: 200,
                      child: const Align(
                          alignment: Alignment.center,
                          child: Text('Header: Fixed Height'))),
                  Container(
                    color: Colors.orange,
                    constraints: BoxConstraints(
                      maxWidth: 960,
                      minHeight: max(viewportConstraints.maxHeight - 400, 0),
                    ),
                    padding: const EdgeInsets.symmetric(horizontal: 75),
                    child: Container(
                        color: Colors.white,
                        child: Column(
                          mainAxisSize: MainAxisSize.max,
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Column(
                              children: const [
                                Text(
                                    'ContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContent'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                              ],
                            ),
                            Container(
                                child: const Text('spacer'),
                                height: 1,
                                color: Colors.red)
                          ],
                        )),
                  ),
                  Container(
                      color: Colors.indigo,
                      height: 200,
                      child: const Align(
                          alignment: Alignment.center,
                          child: Text('Footer: Fixed Height'))),
                ],
              ),
            ),
          );
        ,
      ),
    );
  


【讨论】:

【参考方案2】:

如果页眉和页脚高度各为200,则中间内容高度应小于400。

height: MediaQuery.of(context).size.height - 400

因此将您的代码更改为

 @override
   Widget build(BuildContext context) 
    return DefaultTextStyle(
      style: Theme.of(context).textTheme.bodyText2!,
      child: LayoutBuilder(
        builder: (BuildContext context, BoxConstraints viewportConstraints) 
        
          return SingleChildScrollView(
            child: ConstrainedBox(
              constraints: BoxConstraints(
                minHeight: viewportConstraints.maxHeight,
              ),
              child: IntrinsicHeight(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    ContentWidthContainer(
                      child: Container(
                          color: Colors.indigo,
                          height: 200,
                          child: const Text('Header: Fixed Height')),
                    ),
                    Expanded(
                      child: ContentWidthContainer(
                        child: Container(
                            height: MediaQuery.of(context).size.height - 400,
                            color: Colors.white,
                            child: Column(
                              children: const [
                                Text(
                                    'ContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContentContent'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                                Text('Content'),
                              ],
                            )),
                      ),
                    ),
                    ContentWidthContainer(
                      child: Container(
                          color: Colors.indigo,
                          height: 200,
                          child: const Text('Footer: Fixed Height')),
                    ),
                  ],
                ),
              ),
            ),
          );
        ,
      ),
    );
  

【讨论】:

您好 Meysam,感谢您的反馈。我正在尝试实现的设计没有粘性页眉或页脚,并且需要成为将滚动的整个页面的一部分。 @OneGoodRun 嗨,由于您希望页眉和页脚滚动,所以您必须从页眉和页脚的高度减少中间高度。我编辑了答案。 嗨 Meysam,嗯,我仍然需要保持内容的可见性。这似乎会使 Expanded 中的内容随着屏幕变短而不是激活滚动而消失。 我测试了你的代码。它工作正常。可能是由于 Chrome 浏览器溢出

以上是关于视口大于 maxwidth 时 SingleChildScrollView 渲染溢出的主要内容,如果未能解决你的问题,请参考以下文章

当设备视口大于指定大小时禁用onClick事件[重复]

iOS Safari 扩展框架集大于视口

大于 GL_MAX_VIEWPORT_DIMS 的视口平铺渲染

如果视口超过一定宽度,则停止图像元素下载图像

移动web基础

Android TextView 不会用多行紧紧地拥抱文本,而是坚持使用 maxWidth