Flutter:如何在左侧添加一个小部件,在一行的中心添加另一个小部件

Flutter: How to add a widget on the left, and another one in the centre of a row

我想将一个文本小部件对齐到一行的中心,我还想在同一行的左侧放置一个按钮小部件。文本小部件被展开的小部件包围,因此它占据了按钮留下的剩余 space。

以下是我目前拥有的:

红线代表屏幕中间,文本小部件应该在它的正上方。 下面是我的代码:

final double _buttonTextSize = 20.0;
  final double _buttonWidth = 90.0;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              Container(
                  padding: const EdgeInsets.all(8.0),
                  child: _backButton(),),
              Expanded(
                child: Text(
                  'Encryption',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    fontSize: 30.0,
                    color: MyThemeColors.textTitle(),
                    fontWeight: FontWeight.w400,
                  ),
                ),
              ),
            ],
          ),
          Center(
            child: Container(color: Colors.red, height: 100, width: 5),
          )
        ],
      ),
    );
  }

  Button _backButton() {
    return Button(
      style: MyButtonStyles.defaultStyle(),
      child: Container(
        width: _buttonWidth,
        padding: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 4.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Padding(
              padding: EdgeInsets.only(right: 4.0),
              child: Icon(FluentIcons.back, size: 22.0),
            ),
            Text(
              'Back',
              style: TextStyle(
                color: MyThemeColors.textTitle(),
                fontSize: _buttonTextSize,
              ),
            ),
          ],
        ),
      ),
      onPressed: () {
        Navigator.pop(context);
      },
    );
  }

对我来说,我有 2 个选项供您选择:

  1. 使用 Stack 将按钮放在文本上方。无需计算 :D

  2. 使用 LayoutBuilder 正确计算按钮的大小并填充它。

    Contrait.maxWith 给你 space 的大小,你可以使用屏幕大小(或外面的另一个 LayoutBuilder 小部件来获得父大小)。

对我来说最好的选择是选项(1)。 这是一些测试代码(抱歉,您提供的代码有一些自定义小部件(Button、MyButtonStyles...)并且不能 copy/paste for 运行,所以我需要创建一个新的)。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Column(
        children: const [
          OnlyText(),
          Divider(),
          OptionOne(),
          Divider(),
          OptionTwo(),
        ],
      ),
    );
  }
}

class OnlyText extends StatelessWidget {
  const OnlyText({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Material(
      child: SizedBox(
        height: 100,
        child: Center(child: Text("this one is in middle")),
      ),
    );
  }
}

class OptionTwo extends StatelessWidget {
  const OptionTwo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      child: SizedBox(
        width: double.infinity,
        height: 100,
        child: Row(children: [
          Container(
            color: Colors.green,
            height: 100,
            child: const Center(child: Text('back button')),
          ),
          Expanded(
            child: LayoutBuilder(builder: (context, constrait) {
              final padding =
                  (MediaQuery.of(context).size.width - constrait.maxWidth);
              return Padding(
                padding: EdgeInsets.only(right: padding),
                child: const Center(child: Text('center screen')),
              );
            }),
          )
        ]),
      ),
    );
  }
}

class OptionOne extends StatelessWidget {
  const OptionOne({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Align(
        alignment: Alignment.topCenter,
        child: Container(
          width: double.infinity,
          height: 100,
          padding: const EdgeInsets.all(0),
          child: Stack(
            // <---- Here you go, a stack will help you
            children: [
              Row(
                children: [
                  Container(
                    color: Colors.green,
                    child: const Center(child: Text('back button')),
                  ),
                ],
              ),
              const Center(child: Text('center screen')),
            ],
          ),
        ),
      ),
    );
  }
}

这是结果:

堆栈建议很好,除非您在中心显示的文本足够长可以重叠。 以下是我如何使用 LayoutBuilder 完成的:

import 'dart:ui' as ui;
    Row(
      children: [
        const BackButton(),
        Expanded(
          child: LayoutBuilder(
            builder: (context, constraints) {
              const String string = 'Short title';
              final TextSpan span = TextSpan(
                text: string,
                // Note: use the TextStyle that's relevant for your case. I'm replacing the title of a SliverAppBar, so I used the default TextStyle for AppBar, headline6
                style: Theme.of(context).textTheme.headline6,
              );
              final textPainter = TextPainter(
                text: span,
                // Maybe test with rtl in the future
                textDirection: ui.TextDirection.ltr,
              )..layout(maxWidth: constraints.maxWidth);

              final double screenWidth = MediaQuery.of(context).size.width;
              final double textWidth = textPainter.size.width;
              final double leadingWidth = screenWidth - constraints.maxWidth;
              final double remainingSpace = screenWidth / 2 - leadingWidth - textWidth / 2;

              const Text text = Text(string);
              if (remainingSpace <= 0) {
                // If the Text overflows, we can just return the text with no positioning
                return text;
              } else {
                // Otherwise, we add blank space to the left to center the text
                return Row(
                  children: [
                    SizedBox(width: remainingSpace),
                    text,
                  ],
                );
              }
            },
          ),
        ),
      ],
    ),

放置一个与左侧小部件大小相同的 Sizedbox,删除展开部分,以便文本仅采用 space 所需的内容并更改对齐方式。

Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Container(
              padding: const EdgeInsets.all(8.0),
              child: _backButton(),),
              Text(
              'Encryption',
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 30.0,
                color: MyThemeColors.textTitle(),
                fontWeight: FontWeight.w400,
              ),
              SizedBox(
                width: _buttonWidth,
              ),
          ]}