flutter 如何根据屏幕/父窗口小部件宽度限制窗口小部件的数量以适合一行

vc6uscn9  于 2023-03-24  发布在  Flutter
关注(0)|答案(1)|浏览(139)

我有一个列表块,其中包含的数据变化很大。在每个列表块中,我都想放上类别标签(也许使用芯片小部件)但问题是,我需要限制它们的数量以适应特定的宽度约束。我的数据列表中的类别数量也会变化-有时其中一个瓷砖将有2个类别,有时5个,有时0个。我如何将它们放在屏幕上,更具体地说,我希望只显示适合列表磁贴宽度的类别标签--其余的不会显示。
有没有一些简单的解决方案,不需要测量每个标签的宽度,并将其与设备的屏幕尺寸进行比较?
Wrap小部件不能解决我的问题,因为它不能仅限于一行,并且没有选项可以根据大小约束限制其子小部件的数量😕

inkz8wg9

inkz8wg91#

下面是我使用的解决方案的完整工作示例。

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

void main() {
  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Padding(
            padding: EdgeInsets.all(30.0),
            child: OverflowRow(children: [
              Text('Test'),
              Text('Test'),
              Text('Test'),
              Text('Test'),
              Text('Test'),
              Text('Test'),
              Text('Test'),
              Text('Test'),
              Text('Test'),
            ])));
  }
}

class OverflowRow extends StatefulWidget {
  const OverflowRow({Key? key, required this.children}) : super(key: key);

  final List<Widget> children;

  @override
  State<OverflowRow> createState() => _OverflowRowState();
}

class _OverflowRowState extends State<OverflowRow> {
  late List<double> sizes;
  late List<bool> show;
  late List<int> hideList;
  bool calcFinished = false;
  double width = 0;

  @override
  void initState() {
    sizes = List.generate(widget.children.length, (index) => -1);
    show = List.generate(widget.children.length, (index) => true);
    hideList = List.generate(widget.children.length, (index) => index);
    super.initState();
  }

  void sizeChanged(Size size, int index) {
    sizes[index] = size.width;
    if (!sizes.contains(-1)) {
      setState(() {
        calcFinished = true;
        calculate();
      });
    }
  }

  void calculate() {
    var width = this.width;
    for (final i in hideList) {
      show[i] = width - sizes[i] > 0;
      width -= sizes[i];
    }
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      width = constraints.maxWidth;
      calculate();
      return Row(
          children: widget.children
              .mapIndexed((index, element) => element is Spacer
                  ? element
                  : SizeWidget(
                      sizeChanged: (size) => sizeChanged(size, index),
                      child: element))
              .whereIndexed((index, _) => show[index])
              .toList());
    });
  }
}

class SizeWidget extends StatefulWidget {
  final Widget child;
  final Function(Size size)? sizeChanged;

  const SizeWidget({Key? key, this.sizeChanged, required this.child})
      : super(key: key);

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

class SizeWidgetState extends State<SizeWidget> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _getSize();
    });
  }

  _getSize() {
    RenderBox renderBox = context.findRenderObject() as RenderBox;
    if (widget.sizeChanged != null) widget.sizeChanged!(renderBox.size);
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

它由两个额外的小部件组成。一个SizeWidget能够通过回调报告其大小,另一个OverflowRow使用SizeWidget来测量孩子的大小。它可能比它应该的更复杂,所以我也有兴趣看到更好的解决方案。但这应该对你有用。

相关问题