Flutter开发笔记:Flutter 布局相关组件

news2024/10/6 6:01:32
Flutter开发笔记
Flutter 布局与布局组件

- 文章信息 - Author: Jack Lee (jcLee95)
Visit me at: https://jclee95.blog.csdn.net
Email: 291148484@163.com.
Shenzhen Chine
Address of this article:https://blog.csdn.net/qq_28550263/article/details/131419782

【介绍】:本文介绍Flutter 布局相关组件。


1. 概述

Flutter 中提供了丰富的原生布局组件。可以对这些组件分层以下几类:

1. 线性布局(Linear Layout):

  • Row:水平方向的线性布局组件,可以包含多个子组件。
  • Column:垂直方向的线性布局组件,可以包含多个子组件。

2. 层叠布局(Stacking Layout):

  • Stack:层叠布局组件,可以叠加多个子组件。
  • Positioned:用于定位子组件在Stack中的位置的组件。
  • IndexedStack:将子组件堆叠在一起的布局组件,但只显示其中一个子组件,可以通过索引来控制显示哪个子组件。

3. 弹性布局(Flex Layout):

  • Expanded:将子组件填充剩余空间的弹性布局组件。
  • Flexible:弹性布局组件,可以根据比例分配可用空间。

4. 流式布局(Flow Layout):

  • Wrap:自动换行的流式布局组件,可以容纳多个子组件。
  • Flow:根据子组件的大小和约束条件来自动布局的自定义流式布局组件。

5. 表格布局(Table Layout):

  • Table:以表格形式布局子组件的组件,可以指定行和列的数量,并对每个单元格进行定位。

6. 限制布局(Constraint Layout):

  • LimitedBox:根据最大宽度和高度限制子组件的尺寸的布局组件。
  • ConstrainedBox:对子组件施加额外约束条件的布局组件。

7. 宽高比布局(Aspect Ratio Layout):

  • AspectRatio:根据给定的宽高比调整子组件的尺寸的布局组件。

这些分类可以用于根据布局需求选择适合的原生布局组件,以构建灵活且美观的用户界面。另外,还有一些其它的组件,实质上也起到了布局的作用,如 GridView 组件、ListView组件等等,不过我们将在其它文章中介绍。

2. 线性布局组件

2.1 什么是线性布局

在Flutter中,线性布局是一种常用的布局方式,可以使用Row组件和Column组件来创建水平和垂直方向的线性布局。

2.2 Row 组件

Row组件用于创建水平方向的线性布局,可以包含多个子组件。可以通过设置属性来调整子组件在水平方向上的对齐方式、间距和尺寸等。下面是一个使用Row组件创建水平线性布局的示例代码:

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: <Widget>[
    Text('子组件1'),
    Text('子组件2'),
    Text('子组件3'),
  ],
)

在这里插入图片描述

在上面的示例中,Row组件包含了三个Text组件作为子组件,并使用mainAxisAlignment属性设置了子组件在水平方向上的对齐方式为平均分布。子组件1、子组件2和子组件3将会平均分布在Row组件的水平空间上。

2.3 Column 组件

Column组件用于创建垂直方向的线性布局,可以包含多个子组件。可以通过设置属性来调整子组件在垂直方向上的对齐方式、间距和尺寸等。下面是一个使用Column组件创建垂直线性布局的示例代码:

Column(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: <Widget>[
    Text('子组件1'),
    Text('子组件2'),
    Text('子组件3'),
  ],
)

在这里插入图片描述

在上面的示例中,Column组件包含了三个Text组件作为子组件,并使用mainAxisAlignment属性设置了子组件在垂直方向上的对齐方式为平均分布。子组件1、子组件2和子组件3将会平均分布在Column组件的垂直空间上。

通过使用Row组件和Column组件,您可以轻松创建水平和垂直方向的线性布局,并对子组件进行灵活的排列和对齐。这些布局组件是构建Flutter应用程序用户界面的重要工具。

3. 层叠布局(Stacking Layout)

3.1 什么是层叠布局

层叠布局(Stack)是一种特殊的布局方式,可以让子组件按照不同的位置和顺序堆叠在一起。通常,这种布局用于在同一区域显示多个相互重叠的元素,例如悬浮按钮、提示标签或视觉效果。

在Flutter中,层叠布局主要通过 StackPositioned 组件实现,其中Stack 组件负责将子组件堆叠在一起,而 Positioned 组件则用于指定相对于父 Stack 组件的位置。层叠布局可实现更丰富的视觉效果和高度定制的 UI设计。

3.2 Stack 组件

Stack组件用于创建层叠布局,它可以叠加多个子组件,并根据它们的位置进行叠放。下面是一个使用Stack组件创建层叠布局的示例代码:

Stack(
  alignment: Alignment.center,
  children: <Widget>[
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    Container(
      width: 150,
      height: 150,
      color: Colors.red,
    ),
    Container(
      width: 100,
      height: 100,
      color: Colors.green,
    ),
  ],
)

在上面的示例中,Stack组件包含了三个Container组件作为子组件,它们分别具有不同的大小和颜色。Stack的alignment属性被设置为Alignment.center,这意味着子组件将会在层叠布局的中心对齐。

3.3 Positioned 组件

Positioned 组件用于定位子组件在 Stack 布局中的位置。通过设置top、bottom、left、right等属性,可以精确地控制子组件在Stack布局中的偏移和大小。下面是一个使用Positioned组件的示例代码:

Stack(
  children: <Widget>[
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    Positioned(
      top: 50,
      left: 50,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.red,
      ),
    ),
  ],
)

在上面的示例中,Stack组件包含了两个Container组件作为子组件。第二个Container组件使用Positioned组件进行定位,设置top为50,left为50,这样它将会相对于Stack布局的左上角向下和向右偏移,形成重叠的效果。

通过使用Stack组件和Positioned组件,您可以创建复杂的层叠布局,并精确控制子组件的位置和大小。这些布局组件为您构建Flutter应用程序的图层效果提供了强大的工具。

一个完整的例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Stack Example')),
        body: Center(
          child: SizedBox(
            width: 200,
            height: 200,
            child: Stack(
              children: [
                Container(
                  color: Colors.red,
                ),
                Positioned(
                  left: 30,
                  top: 30,
                  child: Container(
                    width: 100,
                    height: 100,
                    color: Colors.green,
                  ),
                ),
                const Positioned(
                  right: 10,
                  bottom: 10,
                  child: Text(
                    'Stack',
                    style: TextStyle(fontSize: 24, color: Colors.white),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

在这里插入图片描述

3.4 特殊的层叠布局:IndexedStack 组件

IndexedStack 是一个特殊类型的层叠布局,该布局允许显示子组件中的单个元素,基于一个索引值。

在Flutter中,IndexedStack是一个继承自 Stack 的特殊组件,它可以显示一个列表中指定索引(index)的子组件。与Stack不同,IndexedStack 只显示一个子组件,其他子组件在显示时不可见。

例如:

IndexedStack(
  index: 2,
  children: <Widget>[
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    Container(
      width: 200,
      height: 200,
      color: Colors.red,
    ),
    Container(
      width: 200,
      height: 200,
      color: Colors.green,
    ),
  ],
)

在上面的示例中,IndexedStack组件包含了三个Container组件作为子组件。通过设置index属性为2,表示显示索引为2的子组件,即绿色的Container组件。蓝色和红色的Container组件则被隐藏。

通过使用IndexedStack组件,您可以轻松创建堆叠布局,并根据需要显示不同的子组件。这种布局方式特别适用于在同一个位置上切换显示不同内容的场景,如切换不同的页面或组件等。

官方一个完整的例子如:

该例子来源于此页面:https://api.flutter.dev/flutter/widgets/IndexedStack-class.html

import 'package:flutter/material.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('IndexedStack Sample')),
        body: const IndexedStackExample(),
      ),
    );
  }
}

class IndexedStackExample extends StatefulWidget {
  const IndexedStackExample({super.key});

  
  State<IndexedStackExample> createState() => _IndexedStackExampleState();
}

class _IndexedStackExampleState extends State<IndexedStackExample> {
  List<String> names = <String>['Dash', 'John', 'Mary'];
  int index = 0;
  final TextEditingController fieldText = TextEditingController();

  
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        SizedBox(
          width: 300,
          child: TextField(
            decoration: const InputDecoration(
              border: OutlineInputBorder(),
              hintText: 'Enter the name for a person to track',
            ),
            onSubmitted: (String value) {
              setState(() {
                names.add(value);
              });
              fieldText.clear();
            },
            controller: fieldText,
          ),
        ),
        const SizedBox(height: 50),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            GestureDetector(
              onTap: () {
                setState(() {
                  if (index == 0) {
                    index = names.length - 1;
                  } else {
                    index -= 1;
                  }
                });
              },
              child: const Icon(Icons.chevron_left, key: Key('gesture1')),
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                IndexedStack(
                  index: index,
                  children: <Widget>[
                    for (String name in names) PersonTracker(name: name)
                  ],
                )
              ],
            ),
            GestureDetector(
              onTap: () {
                setState(() {
                  if (index == names.length - 1) {
                    index = 0;
                  } else {
                    index += 1;
                  }
                });
              },
              child: const Icon(Icons.chevron_right, key: Key('gesture2')),
            ),
          ],
        )
      ],
    );
  }
}

class PersonTracker extends StatefulWidget {
  const PersonTracker({super.key, required this.name});
  final String name;
  
  State<PersonTracker> createState() => _PersonTrackerState();
}

class _PersonTrackerState extends State<PersonTracker> {
  int counter = 0;
  
  Widget build(BuildContext context) {
    return Container(
      key: Key(widget.name),
      decoration: BoxDecoration(
        color: const Color.fromARGB(255, 239, 248, 255),
        border: Border.all(color: const Color.fromARGB(255, 54, 60, 244)),
        borderRadius: const BorderRadius.all(Radius.circular(10)),
      ),
      padding: const EdgeInsets.all(16.0),
      child: Column(
        children: <Widget>[
          Text('Name: ${widget.name}'),
          Text('Score: $counter'),
          TextButton.icon(
            key: Key('increment${widget.name}'),
            icon: const Icon(Icons.add),
            onPressed: () {
              setState(() {
                counter += 1;
              });
            },
            label: const Text('Increment'),
          )
        ],
      ),
    );
  }
}

在这里插入图片描述

这个示例显示了一个 IndexedStack 组件,用于从一系列卡片中一次展示一张卡片,每张卡片都保持各自的状态。通过输入框输入可以增加卡片。

4. 弹性布局(Flex Layout)

在Flutter中,弹性布局是一种常用的布局方式,可以使用Expanded组件和Flexible组件来实现弹性布局。

4.1 Expanded 组件

Expanded 组件是弹性布局的关键组件之一,它用于将子组件 填充剩余的可用空间

Expanded 组件通常作为父组件的子组件,并且会将剩余的空间按比例分配给其中的子组件。

例如:

Row(
  children: <Widget>[
    Expanded(
      child: Container(
        height: 100,
        color: Colors.blue,
      ),
    ),
    Expanded(
      child: Container(
        height: 100,
        color: Colors.red,
      ),
    ),
    Expanded(
      child: Container(
        height: 100,
        color: Colors.green,
      ),
    ),
  ],
)

在上面的示例中,Expanded 组件被用作 Row 布局的子组件,它包含了三个 Container 组件作为子组件。

每个 Expanded 组件都会自动填充剩余的水平空间,并按比例分配给子组件,从而使它们平均分布在 Row 布局中。

一个完整的例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Expanded组件示例')),
        body: Column(
          children: <Widget>[
            Row(children: [
              Expanded(
                flex: 1,
                child: Container(
                  color: Colors.red,
                  child: const Text('第一个组件'),
                ),
              ),
              Expanded(
                flex: 2,
                child: Container(
                  color: Colors.green,
                  child: const Text('第二个组件'),
                ),
              ),
            ]),
            Row(children: [
              Expanded(
                flex: 3,
                child: Container(
                  color: Colors.blue,
                  child: const Text('第三个组件'),
                ),
              ),
              Expanded(
                flex: 4,
                child: Container(
                  color: Colors.orange,
                  child: const Text('第四个组件'),
                ),
              ),
            ]),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

在这个例子中,有两个 Row,每个 Row 中有两个 Expanded 组件,分别设置了不同的flex权重。每个 Expanded 组件包含一个颜色填充的容器以及文本

4.2 Flexible 组件

Flexible组件也是实现弹性布局的重要组件,它可以根据给定的比例来分配可用的空间。与Expanded组件不同的是,Flexible组件可以灵活地调整空间分配的比例,以满足布局的需求。下面是一个使用Flexible组件的示例代码:

Row(
  children: <Widget>[
    Flexible(
      flex: 2,
      child: Container(
        height: 100,
        color: Colors.blue,
      ),
    ),
    Flexible(
      flex: 1,
      child: Container(
        height: 100,
        color: Colors.red,
      ),
    ),
    Flexible(
      flex: 1,
      child: Container(
        height: 100,
        color: Colors.green,
      ),
    ),
  ],
)

在上面的示例中,Flexible组件被用作Row布局的子组件,它包含了三个Container组件作为子组件。每个Flexible组件通过设置flex属性来定义空间分配的比例,这样第一个子组件会占据2/4的空间,而后两个子组件会各自占据1/4的空间,从而实现了不同的比例分配。

一个完整的例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Flexible组件示例')),
        body: Column(
          children: <Widget>[
            Row(children: [
              Flexible(
                flex: 1,
                fit: FlexFit.tight,
                child: Container(
                  color: Colors.red,
                  child: const Text('第一个组件'),
                ),
              ),
              Flexible(
                flex: 2,
                fit: FlexFit.loose,
                child: Container(
                  color: Colors.green,
                  child: const Text('第二个组件'),
                ),
              ),
            ]),
            Row(children: [
              Flexible(
                flex: 3,
                fit: FlexFit.tight,
                child: Container(
                  color: Colors.blue,
                  child: const Text('第三个组件'),
                ),
              ),
              Flexible(
                flex: 4,
                fit: FlexFit.loose,
                child: Container(
                  color: Colors.orange,
                  child: const Text('第四个组件'),
                ),
              ),
            ]),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

在此示例中,我们使用了两个Row 组件,其中每个 Row 包含两个 Flexible 组件。每个 Flexible 组件内部有一个带颜色的容器。

Expanded 类似,通过设置 flex 属性,可以控制子组件在行或列中占据的空间。此外,Flexible 组件还有一个 fit 属性,允许您设置子组件如何适应所分配的空间。在上面的示例中,我们所设置的 FlexFit.tight 指示子组件要占据所有可用空间,而 FlexFit.loose 则允许子组件在占用所需空间后仍然保持可用空间。

5. 流式布局(Flow Layout)

5.1 什么是流式布局

Flutter 中,流式布局指的是一种将子组件排列在多行或多列的布局方式,它可以自动根据屏幕尺寸调整子组件的排列。Flutter 框架提供了两种原生流式布局组件:

  • Wrap 组件用于将一系列子组件按行排列,并在子组件长度超出容器宽度时自动换行。
  • Flow 组件是一个高度可定制的流式布局组件。
    下面我们一一介绍之。

5.2 Wrap 组件

Wrap 组件用于创建 自动换行的流式布局,它可以容纳多个子组件,并在达到容器边界时自动换行。下面是一个使用 Wrap 组件创建流式布局的示例代码:

Wrap(
  spacing: 8.0,
  runSpacing: 8.0,
  children: <Widget>[
    Chip(
      label: Text('标签1'),
      backgroundColor: Colors.blue,
    ),
    Chip(
      label: Text('标签2'),
      backgroundColor: Colors.red,
    ),
    Chip(
      label: Text('标签3'),
      backgroundColor: Colors.green,
    ),
    Chip(
      label: Text('标签4'),
      backgroundColor: Colors.orange,
    ),
  ],
)

在上面的示例中,Wrap组件包含了四个Chip组件作为子组件。Wrap组件的spacing属性设置了子组件之间的水平间距为8.0,而runSpacing属性设置了子组件在新行上的垂直间距为8.0。当子组件的总宽度超过Wrap组件的宽度时,Wrap组件会自动将子组件放置在新行上。

5.3 Flow 组件

Flow组件是Flutter中一个强大且灵活的布局组件,它允许开发者自定义子组件在父组件中的位置

使用Flow组件时,我们需要提供一个FlowDelegate对象,该对象负责控制子组件如何布局及排列。

5.3.1 使用 Flow 组件

要使用 Flow 组件,首先需要创建一个继承自FlowDelegate的子类,并实现其中的三个方法:

  1. paintChildren:负责绘制子组件。
  2. shouldRepaint:确定是否重绘子组件。通常在子组件位置或外观发生修改时返回true
  3. getSize:返回Flow组件的尺寸。

以下是一个简单的示例,展示了如何创建一个简单的自定义FlowDelegate子类:

class CustomFlowDelegate extends FlowDelegate {
  
  void paintChildren(FlowPaintingContext context) {
    // 实现子组件在父组件中的布局逻辑
  }

  
  bool shouldRepaint(FlowDelegate oldDelegate) {
    // 确定是否需要重绘子组件
  }

  
  Size getSize(BoxConstraints constraints) {
    // 返回Flow组件的尺寸
  }
}

5.3.2 使用自定义FlowDelegate

创建好自定义的FlowDelegate子类后,我们可以在使用Flow组件时指定该子类的一个实例,如下所示:

Flow(
  delegate: CustomFlowDelegate(),
  children: <Widget>[
    // 添加子组件
  ],
)

5.3.3 一个 Flow 组件的完整例子

一个完整例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Flow组件示例')),
        body: Flow(
          delegate: MyFlowDelegate(),
          children: List.generate(
            6,
            (index) => Container(
              height: 50,
              width: 50,
              color: Colors.primaries[index],
              child: Center(child: Text('${index + 1}')),
            ),
          ),
        ),
      ),
    );
  }
}

class MyFlowDelegate extends FlowDelegate {
  
  void paintChildren(FlowPaintingContext context) {
    double x = 10.0;
    double y = 10.0;
    for (int i = 0; i < context.childCount; i++) {
      x += 60.0;
      if (x > context.size.width - 50) {
        x = 10.0;
        y += 60.0;
      }
      context.paintChild(i, transform: Matrix4.translationValues(x, y, 0.0));
    }
  }

  
  bool shouldRepaint(MyFlowDelegate oldDelegate) => true;

  
  Size getSize(BoxConstraints constraints) {
    return constraints.constrain(const Size(double.infinity, 300.0));
  }
}

在这里插入图片描述

Flow 组件具有很高的自适应能力,能够对子组件的位置和布局进行精细控制。虽然Flow组件的使用场景相对少见,但在需要高度自定义布局的情况下,Flow组件将非常有用。

6. 表格布局(Table Layout)

在Flutter中,表格布局是一种常用的布局方式,可以使用Table组件来创建具有行和列的表格布局。

6.1 Table组件

Table组件用于创建表格布局,它以行和列的形式排列子组件。每个子组件被称为一个单元格,并根据给定的行和列进行定位。下面是一个使用Table组件创建表格布局的示例代码:

Table(
  border: TableBorder.all(),
  children: [
    TableRow(
      children: [
        TableCell(
          child: Text('单元格1'),
        ),
        TableCell(
          child: Text('单元格2'),
        ),
      ],
    ),
    TableRow(
      children: [
        TableCell(
          child: Text('单元格3'),
        ),
        TableCell(
          child: Text('单元格4'),
        ),
      ],
    ),
  ],
)

在上面的示例中,Table组件包含了两个TableRow组件作为子组件,每个TableRow组件代表一行。每行又包含了两个TableCell组件作为子组件,每个TableCell组件代表一个单元格。通过嵌套的方式,您可以创建具有多行多列的表格布局。

Table组件的border属性可以设置表格的边框样式,以增加可读性和美观性。

一个完整的例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Table Example')),
        body: Center(
          child: Container(
            padding: const EdgeInsets.all(16),
            child: Table(
              border: TableBorder.all(color: Colors.black, width: 1),
              defaultColumnWidth: const IntrinsicColumnWidth(),
              columnWidths: const {
                0: FlexColumnWidth(1),
                1: FlexColumnWidth(3),
              },
              children: const [
                TableRow(
                  children: [
                    TableCell(
                        child: Text('Header 1', textAlign: TextAlign.center)),
                    TableCell(
                        child: Text('Header 2', textAlign: TextAlign.center)),
                  ],
                ),
                TableRow(
                  children: [
                    TableCell(
                        child:
                            Text('Row 1 Col 1', textAlign: TextAlign.center)),
                    TableCell(
                        child:
                            Text('Row 1 Col 2', textAlign: TextAlign.center)),
                  ],
                ),
                TableRow(
                  children: [
                    TableCell(
                        child:
                            Text('Row 2 Col 1', textAlign: TextAlign.center)),
                    TableCell(
                        child:
                            Text('Row 2 Col 2', textAlign: TextAlign.center)),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

在这里插入图片描述

7. 限制布局(Constraint Layout)

在Flutter中,限制布局是一种常用的布局方式,可以使用LimitedBox组件和ConstrainedBox组件来实现对子组件尺寸的限制和约束。

7.1 LimitedBox 组件

LimitedBox组件用于 限制子组件的最大尺寸,可以通过设置maxWidth和maxHeight属性来限制子组件的宽度和高度。LimitedBox组件会尽量将子组件的尺寸限制在指定的最大尺寸范围内。

注意:只有在父组件没有限制子组件大小时,LimitedBox才会发挥作用。

例如,当子组件嵌套在一个无限宽高的组件(如ListView)中时,可以使用 LimitedBox 来限制子组件的大小:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('LimitedBox Example')),
        body: ListView(
          children: const [
            LimitedBoxWidget(),
            LimitedBoxWidget(),
            LimitedBoxWidget(),
          ],
        ),
      ),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    return LimitedBox(
      maxWidth: 100,
      maxHeight: 100,
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.blue,
        child: const Center(
          child: Text(
            'LimitedBox',
            style: TextStyle(fontSize: 24, color: Colors.white),
          ),
        ),
      ),
    );
  }
}

在这里插入图片描述

在这个示例中,我们在一个ListView中创建了3个LimitedBoxWidgetLimitedBoxWidget 是一个自定义的 StatelessWidget,其内部包含一个 LimitedBox 组件和一个宽高均为 double.infinity 的蓝色 Container

由于ListView 本身没有限制子组件的大小,LimitedBox 会将子组件的宽高限制在最大 100 像素,从而创建一个等大小的蓝色矩形。在这种情况下,LimitedBox 的限制生效,以展示如何在特定场景下限制子组件的大小。

7.2 ConstrainedBox 组件

ConstrainedBox组件用于对子组件的尺寸进行约束和限制,可以通过设置constraints属性来指定约束条件。constraints属性接受BoxConstraints对象,该对象定义了子组件的最小和最大宽度和高度等约束。下面是一个使用ConstrainedBox组件对子组件尺寸进行约束的示例代码:

ConstrainedBox(
  constraints: BoxConstraints(
    minWidth: 100,
    maxWidth: 200,
    minHeight: 50,
    maxHeight: 100,
  ),
  child: Container(
    width: 150,
    height: 80,
    color: Colors.red,
  ),
)

在上面的示例中,ConstrainedBox组件的constraints属性设置了子组件的最小宽度为100,最大宽度为200,最小高度为50,最大高度为100。子组件Container的宽度为150,高度为80,但由于ConstrainedBox的约束条件,实际上显示的宽度为150(在最小和最大宽度范围内),高度为80(在最小和最大高度范围内)。

再一个完整例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ConstrainedBox Example')),
        body: Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(
              maxWidth: 100,
            ),
            child: Container(
              color: Colors.blue,
              child: const Text(
                'ConstrainedBox',
                textAlign: TextAlign.center,
                style: TextStyle(
                    fontSize: 24, color: Color.fromARGB(255, 168, 44, 44)),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

在这里插入图片描述

8. 宽高比布局:AspectRatio组件

在Flutter中,宽高比布局是一种常用的布局方式,可以使用AspectRatio组件来实现根据指定宽高比例调整子组件的尺寸。AspectRatio,它通过设置aspectRatio属性来指定宽高比例。AspectRatio组件会根据指定的宽高比例调整子组件的尺寸,以保持宽高比例不变。下面是一个使用AspectRatio组件创建宽高比布局的示例代码:

AspectRatio(
  aspectRatio: 16 / 9,
  child: Container(
    color: Colors.blue,
  ),
)

在上面的示例中,AspectRatio组件的aspectRatio属性设置为16 / 9,表示宽高比为16:9。子组件Container的尺寸会根据这个宽高比例进行调整,以保持16:9的宽高比。

可以根据实际需求调整AspectRatio组件的aspectRatio属性,从而实现不同的宽高比例布局。这种布局方式特别适用于需要固定宽高比例的场景,如展示图片或视频的封面、轮播图等。

注意:AspectRatio组件不会对子组件的宽高进行强制调整,而是通过调整父组件的尺寸来保持宽高比例不变。如果子组件的宽高比例与AspectRatio组件的aspectRatio不一致,子组件可能会被裁剪或留有空白区域。

一个完整的例子如:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('AspectRatio Example')),
        body: Center(
          child: Container(
            width: 200,
            height: 200,
            color: Colors.yellow,
            child: AspectRatio(
              aspectRatio: 16 / 9,
              child: Container(
                color: Colors.blue,
                child: const Center(
                  child: Text(
                    '16:9',
                    style: TextStyle(
                      fontSize: 24,
                      color: Colors.white,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/692726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

随笔-当曾经的小弟当了你的领导,阁下该如何应对

前几天&#xff0c;从小龙那得到一个招聘信息&#xff0c;想着被优化的C朋友&#xff0c;就转发给了他。过了会C朋友给我回了信息&#xff1a; C朋友&#xff1a;入职A&#xff08;我现在的公司&#xff09;需要穿正装吗&#xff1f; 我&#xff1a;需要啊&#xff0c;办手续…

并发编程-分布式存储系统之edits_log

复杂一点的多线程编程场景&#xff0c;总结起来也就是 通过加锁来控制好标志位的状态流转&#xff0c;通过标志位的不同的流转状态&#xff0c;来控制每个线程有不同的行为如果是需要各个线程协作处理的逻辑&#xff0c;就采用最简洁的wait/notify机制 分布式存储系统 分布式存…

【软件安装】Linux系统中安装JDK1.8运行环境(Ubuntu系统)

这篇文章&#xff0c;主要介绍Linux系统中安装JDK1.8运行环境&#xff08;Ubuntu系统&#xff09;。 目录 一、Linux安装JDK运行环境 1.1、下载JDK安装包 1.2、上传JDK到Linux服务器 1.3、解压JDK安装包 1.4、配置JDK环境变量 1.5、重新加载profile环境变量 1.6、检查是…

卷积(CNN)| 反卷积(TCNN、Transposed CNN)| 卷积过程中feature map的通道变化 | 1 × 1卷积核如何降维/升维

关于深度学习中的一些小概念&#xff0c;因为网上的资源有些散乱&#xff0c;这里总结一些自己的&#xff0c;方便后面复习&#xff0c;摘一些图&#xff0c;但是会标明引用&#xff01; 一、卷积 对于卷积&#xff0c;下面一张图就够了&#xff0c;根据 stride 步长在 featur…

优维低代码实践:数据加工/转化详解

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

5大最热门云原生API Gateway

文章目录 前言&#xff1a;为什么需要API Gateway&#xff1f;一、APISIX二、Kong三、TyK四、Easegress五、Gloo六、API Gateway应该如何选择&#xff1f; 公众号&#xff1a; MCNU云原生&#xff0c;文章首发地&#xff0c;欢迎微信搜索关注&#xff0c;更多干货&#xff0c;…

Windows安装使用Nacos并进行服务治理

Nacos简介 Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集&#xff0c;帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。 Nacos其实就是一个注册中心,用来管理和注册微服务 搭建Nacos环境 安装nacos(版本1.1.4) 下载网址 htt…

【AIGC】ChatGLM2-6B大模型 据称推理性能超越Chat4.0

ChatGLM2-6B ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本&#xff0c;在保留了初代模型对话流畅、部署门槛较低等众多优秀特性的基础之上&#xff0c;ChatGLM2-6B 引入了如下新特性&#xff1a; 更强大的性能&#xff1a;基于 ChatGLM 初代模型的开发经验&…

Flink CDC 2.4 正式发布,新增 Vitess 数据源,更多连接器支持增量快照,升级 Debezium 版本

Flink CDC 2.4 正式发布&#xff0c;新增 Vitess 数据源&#xff0c;更多连接器支持增量快照&#xff0c;升级 Debezium 版本 1. Flink CDC 简介2. Flink CDC 2.4 概览3. 详解核心特性和重要改进3.1 深入解读3.2 其他改进 4. 未来规划 1. Flink CDC 简介 Flink CDC [1] 是基于…

皓峰防火墙存SQL注入复现

简介 深圳市皓峰通讯技术有限公司成立于2004年&#xff0c;位于深圳市高新技术产业园&#xff0c;是经过国家认定的“双软”企业和“国家高新技术企业” 登陆界面如下 复现 fofa 搜索 app"皓峰防火墙系统登录" 抓取登录的post包 POST /login.php HTTP/1.1 Host:…

专项练习13

目录 一、选择题 1、1true的返回值是true&#xff0c;这句话是否正确&#xff1f; 2、下列关于JavaScript中变量的说法&#xff0c;错误的是&#xff1f; 3、以下哪些表达式的结果为true&#xff08;&#xff09; 二、编程题 1、将数组参数中的数字从大到小进行排序并返回 一…

CVE-2023-34541 LangChain 任意命令执行

漏洞简介 LangChain是一个用于开发由语言模型驱动的应用程序的框架。 在LangChain受影响版本中&#xff0c;由于load_prompt函数加载提示文件时未对加载内容进行安全过滤&#xff0c;攻击者可通过构造包含恶意命令的提示文件&#xff0c;诱导用户加载该文件&#xff0c;即可造…

ROS:服务通信机制详解

目录 ROS&#xff1a;通信机制一、服务通信机制简介1.1概念1.2作用 二、服务通信理论模型三、服务通信自定义srv3.1目的3.2流程3.2.1创建srv文件3.2.2编辑配置文件3.2.3.编译 四、服务通信自定义srv调用(C)4.1要求4.2流程4.3vscode配置4.4服务端代码4.5客户端代码4.6配置 CMake…

知识图谱相关概念整理

文章目录 1、概论2、什么是知识图谱&#xff1f;3、知识图谱构建3.1、构建知识图谱的生命周期3.2、Schema定义3.3、知识抽取3.4、知识融合3.5、知识存储3.6、知识推理 4、图谱建设的一些经验 1、概论 知识图谱&#xff08;KnowledgeGraph&#xff09;以结构化的形式描述客观世界…

C# Winform DataGridView 控件和 DataTable

目录 一、概述 二、DataTable 的用法 1.创建表和列 2.添加行 3.取值和赋值 4.删除行 5.遍历 DataTable 6.判断 DataTable 列中是否存在某个值 7.设置主键 8.获取 DataRow 所在的行号 9.DataTable 转换为 List 10.将 List 转 DataTable 三、DataGridView 的用法 1…

记录好项目D16

记录好项目 你好呀&#xff0c;这里是我专门记录一下从某些地方收集起来的项目&#xff0c;对项目修改&#xff0c;进行添砖加瓦&#xff0c;变成自己的闪亮项目。修修补补也可以成为毕设哦 本次的项目是个电影购票系统 一、系统介绍 前台 普通用户注册、登录、注销 用户…

Redis哨兵——单机安装部署

Redis哨兵——单机安装部署 目录 主从配置&#xff1a; 部署redis哨兵&#xff1a; 结 果 验 证&#xff1a; 主从配置&#xff1a; 1.安装epel源&#xff1a;yum install epel-release -y 2.安装软件&#xff1a;yum install redis -y 3.新建文件夹便于验证&#xff1a;m…

DAY31:回溯算法(六):子集+子集Ⅱ+递增子序列(经典子集问题)

78.子集 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],…

Label,RC,HPA

上面简单说了一下 pod 的基本知识点&#xff0c;待到后面会使用到 pod 的一些高阶知识点的时候&#xff0c;还可以再细细琢磨底层原理 我们接着继续学习 Lable &#xff0c; RC&#xff0c;HPA 的相关知识点 Label 是什么&#xff1f; label 就是标签&#xff0c;例如之前我们…

Redis进阶 - Redis哨兵

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis进阶 - Redis哨兵 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-advance-sentinel.html 思考 slave 节点宕机恢复以后可以找 master 节点同步数据&#xff0c;那么 master 节点宕机怎么办&am…