flutter Sliver不允许设置容器的最大宽度?

ldioqlga  于 2023-02-25  发布在  Flutter
关注(0)|答案(2)|浏览(171)

我正在尝试制作一个在移动设备和桌面上都能很好工作的响应页面。我在NestedScrollView中使用SliverAppBar。问题是在NestedScrollView中容器的最大宽度约束被完全忽略了。这个行为也与CustomScrollView相同。
如何限制NestedScrollView主体小部件中容器的大小。
下面是代码:

import "dart:math";
import "package:flutter/material.dart";

class ResponsiveSliver extends StatefulWidget {
  static const routeName = 'responsive-sliver';

  @override
  _ResponsiveSliverState createState() => _ResponsiveSliverState();
}

class _ResponsiveSliverState extends State<ResponsiveSliver> with SingleTickerProviderStateMixin {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        floatHeaderSlivers: true,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text(
                "Responsive Sliver",
              ),
              centerTitle: true,
              pinned: true,
              floating: true,
            ),
          ];
        },
        body: ConstrainedBox(
          constraints: BoxConstraints(maxWidth: 200),
          child: Container(
            child: ListView.separated(
              separatorBuilder: (context, child) => Divider(
                height: 1,
              ),
              padding: EdgeInsets.all(0.0),
              itemCount: 10,
              itemBuilder: (context, i) {
                return Container(
                  constraints: BoxConstraints(maxWidth: 200),
                  height: 100,
                  // width: double.infinity,
                  color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
                );
              },
            ),
          ),
        ),
      ),
    );
  }

}

在我上面的代码中,你可以注意到我使用了maxWidth约束,

ConstrainedBox( constraints: BoxConstraints(maxWidth: 200), child: ())

以及

Container( constraints: BoxConstraints(maxWidth: 200), child: (),)

但是这些maxWidth约束被完全忽略,它占用了可用屏幕的全部宽度。
我想让NestedScrollView的全屏宽度,从而使SliverAppbar覆盖整个屏幕宽度。
到目前为止,我知道约束的宽度是基于其父级的大小。在本例中,父级NestedScrollView采用全屏宽度,因此忽略了ConstrainedBox maxWidth属性。
那么,如何使SliverAppBar的大小为全宽,并仍然设置容器的最大宽度?
请建议如何解决此问题。
谢谢

kyvafyod

kyvafyod1#

默认情况下,任何可滚动小部件都会强制子小部件展开,除非您约束了可滚动小部件,否则不关心其水平约束。
然而,在大多数情况下,您只需要约束子对象,这里有几种方法可以做到这一点,但最好的方法是将其 Package 在UnconstrainedBox中。

import "dart:math";
import "package:flutter/material.dart";

class ResponsiveSliver extends StatefulWidget {
  static const routeName = 'responsive-sliver';

  const ResponsiveSliver({super.key});

  @override
  State<ResponsiveSliver> createState() => _ResponsiveSliverState();
}

class _ResponsiveSliverState extends State<ResponsiveSliver> with SingleTickerProviderStateMixin {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        floatHeaderSlivers: true,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            const SliverAppBar(
              title: Text(
                "Responsive Sliver",
              ),
              centerTitle: true,
              pinned: true,
              floating: true,
            ),
          ];
        },
        body: UnconstrainedBox(
          child: Container(
            width: 200,
            child: ListView.separated(
              separatorBuilder: (context, child) => const Divider(
                height: 1,
              ),
              padding: const EdgeInsets.all(0.0),
              itemCount: 10,
              itemBuilder: (context, i) {
                return Container(
                  height: 100,
                  color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
                );
              },
            ),
          ),
        ),
      ),
    );
  }

}

它只是做了与ConstrainedBox相反的事情。它没有强制约束,也没有强加任何传入的约束,例如来自ListView, NestedScrollView, CustomSrollView等,而是允许子对象使用自己的约束来放置自己。
请参阅Flutter Documentation here,其中明确指出
一种不对其子构件施加任何约束的构件,允许子构件以其“自然”大小呈现。
这允许子对象以其在没有约束的无限画布上单独呈现时的大小呈现。然后,此容器将尝试在其自身约束的限制范围内采用相同的大小。如果它最终采用不同的大小,它将基于对齐方式对齐子对象。如果框无法扩展到足以容纳整个子对象,则子对象将被剪切。
在调试模式下,如果子容器溢出,控制台上将打印一个警告,并且在发生溢出的地方将显示黑色和黄色条纹区域。
令人惊讶的是(或者说正如预期的那样),只要你的孩子不溢出,它就没有任何问题。
然而,如果没有Mustafa Tahir的文章,我是无法找到这个解决方案的。你可以找到here的更多方法。虽然我最喜欢这个,因为它是干净的。

e37o9pze

e37o9pze2#

我用填充代替BoxConstraint解决了这个问题。

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

class ConstrainedSliverWidth extends StatelessWidget {
  final Widget child;
  final double maxWidth;
  const ConstrainedSliverWidth({
    Key? key,
    required this.child,
    required this.maxWidth,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    var padding = (size.width - maxWidth) / 2;
    return Padding(
      padding:
          EdgeInsets.symmetric(horizontal: max(padding, 0)),
      child: child,
    );
  }
}

如果您将ConstrainedBox替换为ConstrainedSliverWidth,它应该可以工作。

相关问题