Flutter 布局备忘录 -- 多图警告,干货建议收藏

2022-08-30 15:22:20 浏览数 (1)

你是否需要了解 Flutter 布局的案例?

这里我将展示我在使用 Flutter 布局的代码片段。我将通过精美的代码片段结合可视化的图形来举例。

本文注重 Flutter 部件中比较有用的一些来展示,而不是走马观花展示一大推的部件内容。

本文是翻译的文章,采用意译的方式

Row and Column

行(Row)和列(Column)的布局

MainAxisAlignment

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisAlignment: MainAxisAlignment.start,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisAlignment: MainAxisAlignment.end,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisAlignment: MainAxisAlignment.spaceAround,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

如果你需要文本是针对基线对齐,那么你应该使用 CrossAxisAlignment.baseline

代码语言:javascript复制
Row(
  crossAxisAlignment: CrossAxisAlignment.baseline,
  textBaseline: TextBaseline.alphabetic,
  children: <Widget>[
    Text(
      'Baseline',
      style: Theme.of(context).textTheme.headline2,
    ),
    Text(
      'Baseline',
      style: Theme.of(context).textTheme.bodyText2,
    ),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 200),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 200),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  crossAxisAlignment: CrossAxisAlignment.end,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 200),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 200),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

|

代码语言:javascript复制
Row /*or Column*/(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
    Icon(Icons.star, size: 50),
  ],
),

IntrinsicWidth and IntrinsicHeight

在行列布局中,如何使得所有的部件跟宽度/高度最大的部件同宽/同高呢?如下:

我们假有下面的布局:

代码语言:javascript复制
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('IntrinsicWidth')),
    body: Center(
      child: Column(
        children: <Widget>[
          RaisedButton(
            onPressed: () {},
            child: Text('Short'),
          ),
          RaisedButton(
            onPressed: () {},
            child: Text('A bit Longer'),
          ),
          RaisedButton(
            onPressed: () {},
            child: Text('The Longest text button'),
          ),
        ],
      ),
    ),
  );
}

那么,你想所有的按钮的宽度都跟最宽的按钮那么宽,那就使用IntrinsicWidth

代码语言:javascript复制
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('IntrinsicWidth')),
    body: Center(
      child: IntrinsicWidth(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            RaisedButton(
              onPressed: () {},
              child: Text('Short'),
            ),
            RaisedButton(
              onPressed: () {},
              child: Text('A bit Longer'),
            ),
            RaisedButton(
              onPressed: () {},
              child: Text('The Longest text button'),
            ),
          ],
        ),
      ),
    ),
  );
}

同理,如果你想所有的部件的高度跟最高的部件一样高,你需要结合 IntrinsicHeightRow 来实现。

Stack

Stack 很适合小部件相互叠加。

代码语言:javascript复制
Widget build(BuildContext context) {
  Widget main = Scaffold(
    appBar: AppBar(title: Text('Stack')),
  );

  return Stack(
    fit: StackFit.expand,
    children: <Widget>[
      main,
      Banner(
        message: "Top Start",
        location: BannerLocation.topStart,
      ),
      Banner(
        message: "Top End",
        location: BannerLocation.topEnd,
      ),
      Banner(
        message: "Bottom Start",
        location: BannerLocation.bottomStart,
      ),
      Banner(
        message: "Bottom End",
        location: BannerLocation.bottomEnd,
      ),
    ],
  );
}

使用自己的部件,你需要将它们放在Positioned部件中。

代码语言:javascript复制
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('Stack')),
    body: Stack(
      fit: StackFit.expand,
      children: <Widget>[
        Material(color: Colors.yellowAccent),
        Positioned(
          top: 0,
          left: 0,
          child: Icon(Icons.star, size: 50),
        ),
        Positioned(
          top: 340,
          left: 250,
          child: Icon(Icons.call, size: 50),
        ),
      ],
    ),
  );
}

如果你不想猜测顶部/底部的值,你可以使用 LayoutBuilder 部件来检索它们的值。

代码语言:javascript复制
Widget build(BuildContext context) {
  const iconSize = 50;
  return Scaffold(
    appBar: AppBar(title: Text('Stack with LayoutBuilder')),
    body: LayoutBuilder(
      builder: (context, constraints) =>
        Stack(
          fit: StackFit.expand,
          children: <Widget>[
            Material(color: Colors.yellowAccent),
            Positioned(
              top: 0,
              child: Icon(Icons.star, size: iconSize),
            ),
            Positioned(
              top: constraints.maxHeight - iconSize,
              left: constraints.maxWidth - iconSize,
              child: Icon(Icons.call, size: iconSize),
            ),
          ],
        ),
    ),
  );
}

Expanded

Expanded 配合 FlexFlexbox 布局实现,它对于多项目分配空间很棒。

代码语言:javascript复制
Row(
  children: <Widget>[
    Expanded(
      child: Container(
        decoration: const BoxDecoration(color: Colors.red),
      ),
      flex: 3,
    ),
    Expanded(
      child: Container(
        decoration: const BoxDecoration(color: Colors.green),
      ),
      flex: 2,
    ),
    Expanded(
      child: Container(
        decoration: const BoxDecoration(color: Colors.blue),
      ),
      flex: 1,
    ),
  ],
),

ConstrainedBox

默认的,很多部件多尽量使用小空间,比如:

代码语言:javascript复制
Card(
  child: const Text('Hello World!'),
  color: Colors.yellow,
),

ConstrainedBox允许小部件根据需要使用剩下的空间。

代码语言:javascript复制
ConstrainedBox(
  constraints: BoxConstraints.expand(),
  child: const Card(
    child: const Text('Hello World!'),
    color: Colors.yellow,
  ),
),

使用 BoxConstraints,你可以指定一个小部件可以有多少空间,你可以指定高度/宽度的最小/最大值。

除非指定值,否则 BoxConstraints.expand 使用无限的空间量(也就是使用剩下的所有空间):

代码语言:javascript复制
ConstrainedBox(
  constraints: BoxConstraints.expand(height: 300),
  child: const Card(
    child: const Text('Hello World!'),
    color: Colors.yellow,
  ),
),

上面

0 人点赞