跳到主內容

帶有間隔項的列表

如何建立帶有間隔或擴充套件項的列表

您可能希望建立一個列表,其中所有列表項均勻間隔,以便這些項佔據可見空間。例如,下圖中的四個項均勻間隔,其中“項 0”位於頂部,“項 3”位於底部。

Spaced items

同時,您可能希望允許使用者在列表項不適合螢幕時滾動列表,可能是因為裝置太小、使用者調整了視窗大小,或者專案數量超過了螢幕大小。

Scrollable items

通常,您使用 Spacer 來調整小部件之間的間距,或使用 Expanded 來擴充套件小部件以填充可用空間。但是,這些解決方案在可滾動小部件內部不可行,因為它們需要有限的高度約束。

本教程演示瞭如何使用 LayoutBuilderConstrainedBox 在有足夠空間時均勻地間隔列表項,並在沒有足夠空間時允許使用者滾動,按照以下步驟操作

  1. 新增一個 LayoutBuilder 和一個 SingleChildScrollView
  2. SingleChildScrollView 內部新增一個 ConstrainedBox
  3. 建立帶有間隔項的 Column

1. 新增帶有 SingleChildScrollViewLayoutBuilder

#

首先建立一個 LayoutBuilder。您需要提供一個帶有兩個引數的 builder 回撥函式

  1. BuildContextLayoutBuilder 提供。
  2. 父小部件的 BoxConstraints

在本教程中,您將不會使用 BuildContext,但您將在下一步中需要 BoxConstraints

builder 函式內部,返回一個 SingleChildScrollView。即使父容器太小,此小部件也能確保子小部件可以滾動。

dart
LayoutBuilder(
  builder: (context, constraints) {
    return SingleChildScrollView(child: Placeholder());
  },
);

2. 在 SingleChildScrollView 內部新增 ConstrainedBox

#

在此步驟中,將 ConstrainedBox 作為 SingleChildScrollView 的子項新增。

ConstrainedBox 小部件對其子項施加額外的約束。

透過將 minHeight 引數設定為 LayoutBuilder 約束的 maxHeight 來配置約束。

這可確保子小部件受到最小高度的約束,該最小高度等於 LayoutBuilder 約束提供的可用空間,即 BoxConstraints 的最大高度。

dart
LayoutBuilder(
  builder: (context, constraints) {
    return SingleChildScrollView(
      child: ConstrainedBox(
        constraints: BoxConstraints(minHeight: constraints.maxHeight),
        child: Placeholder(),
      ),
    );
  },
);

但是,您不設定 maxHeight 引數,因為您需要允許子項大於 LayoutBuilder 大小,以防專案不適合螢幕。

3. 建立帶有間隔項的 Column

#

最後,將 Column 作為 ConstrainedBox 的子項新增。

要均勻間隔這些項,請將 mainAxisAlignment 設定為 MainAxisAlignment.spaceBetween

dart
LayoutBuilder(
  builder: (context, constraints) {
    return SingleChildScrollView(
      child: ConstrainedBox(
        constraints: BoxConstraints(minHeight: constraints.maxHeight),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            ItemWidget(text: 'Item 1'),
            ItemWidget(text: 'Item 2'),
            ItemWidget(text: 'Item 3'),
          ],
        ),
      ),
    );
  },
);

或者,您可以使用 Spacer 小部件來調整項之間的間距,或者使用 Expanded 小部件,如果您希望某個小部件佔用比其他小部件更多的空間。

為此,您必須使用 IntrinsicHeight 小部件包裝 Column,這將強制 Column 小部件調整自身大小到最小高度,而不是無限擴充套件。

dart
LayoutBuilder(
  builder: (context, constraints) {
    return SingleChildScrollView(
      child: ConstrainedBox(
        constraints: BoxConstraints(minHeight: constraints.maxHeight),
        child: IntrinsicHeight(
          child: Column(
            children: [
              ItemWidget(text: 'Item 1'),
              Spacer(),
              ItemWidget(text: 'Item 2'),
              Expanded(child: ItemWidget(text: 'Item 3')),
            ],
          ),
        ),
      ),
    );
  },
);

互動示例

#

此示例顯示了一個在列中均勻間隔的項列表。當專案不適合螢幕時,列表可以向上和向下滾動。專案數量由變數 items 定義,更改此值以檢視專案不適合螢幕時會發生什麼。

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    const items = 4;

    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        cardTheme: CardThemeData(color: Colors.blue.shade50),
      ),
      home: Scaffold(
        body: LayoutBuilder(
          builder: (context, constraints) {
            return SingleChildScrollView(
              child: ConstrainedBox(
                constraints: BoxConstraints(minHeight: constraints.maxHeight),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: List.generate(
                    items,
                    (index) => ItemWidget(text: 'Item $index'),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

class ItemWidget extends StatelessWidget {
  const ItemWidget({super.key, required this.text});

  final String text;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: SizedBox(height: 100, child: Center(child: Text(text))),
    );
  }
}