Flutter 固定按钮位置

时间:2021-05-14 22:33:09

标签: flutter dart

我正在开发 Flutter 应用程序,但 ElevatedButton 的位置有问题。当 Validator 在 TextFormField 下方返回错误信息时,widget 向下展开,添加按钮的位置发生变化。我想将添加按钮固定在与应用程序开头相同的位置

button in normal position

Button out of its original position after returning the validator

我的代码:

 Widget build(BuildContext context) {
return Scaffold(
    appBar: AppBar(
      title: Text("Lista de Compras"),
      backgroundColor: Colors.green,
      centerTitle: true,
    ),
    body: Column(
      children: <Widget>[
        Container(
            padding: EdgeInsets.fromLTRB(15, 10, 5, 10),
            child: Form(
              key: _formKey,
              child: Row(
                children: <Widget>[
                  Theme(
                      data: ThemeData(
                          primaryColor: Colors.green,
                          hintColor: Colors.green),
                      child: Expanded(
                          child: TextFormField(
                              controller: _controlador,
                              validator: (value) {
                                if (value.isEmpty) {
                                  return "Insira um item";
                                }
                                return null;
                              },
                              decoration: InputDecoration(
                                  enabledBorder: OutlineInputBorder(
                                      borderSide:
                                          BorderSide(color: Colors.green),
                                      borderRadius:
                                          BorderRadius.circular(100)),
                                  border: OutlineInputBorder(
                                      borderRadius:
                                          BorderRadius.circular(100)),
                                  labelText: "Novo item",
                                  hintText: "Insira um item",
                                  hintStyle: TextStyle(color: Colors.grey),
                                  labelStyle:
                                      TextStyle(color: Colors.green),
                                  suffixIcon: IconButton(
                                    onPressed: () => _controlador.clear(),
                                    icon: Icon(Icons.clear,
                                        color: Colors.grey),
                                  ))))),
                  Padding(padding: EdgeInsets.only(right: 6)),
                  ElevatedButton(
                      style: ElevatedButton.styleFrom(
                          primary: Colors.green,
                          shape: CircleBorder(),
                          padding: EdgeInsets.all(12)),
                      child: Icon(Icons.add, color: Colors.white),
                      onPressed: () {
                        if (_formKey.currentState.validate()) {
                          _addCompras();
                        }
                      }),
                ],
              ),
            )),

2 个答案:

答案 0 :(得分:1)

这是预期的行为,当 TextFormField 显示 errorText 时,这将在 TextFormField 下方附加一个文本,增加大约 22 的额外高度。检查下面的工作示例:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.light(),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Column(
          children: [
            MeasureSize(
              child: FormWidget(),
              onChange: (size) {
                print(size);
              },
            ),
            MeasureSize(
              child: FormWidget(hideError: false),
              onChange: (size) {
                print(size);
              },
            ),
            FormWidget(
              hideError: false,
              addPaddingToTrailingButton: true,
            ),
          ],
        ),
      ),
    );
  }
}

class FormWidget extends StatelessWidget {
  final bool hideError;
  final bool addPaddingToTrailingButton;

  FormWidget({
    this.hideError = true,
    this.addPaddingToTrailingButton = false,
  });

  @override
  Widget build(BuildContext context) {
    Widget trailingButton = ElevatedButton(
      style: ElevatedButton.styleFrom(
        shape: CircleBorder(),
        padding: EdgeInsets.all(12),
      ),
      child: Icon(Icons.add),
      onPressed: () {},
    );

    if (addPaddingToTrailingButton) {
      trailingButton = Padding(
        padding: const EdgeInsets.only(bottom: 22),
        child: trailingButton,
      );
    }

    return Container(
      color: Colors.grey[300],
      margin: const EdgeInsets.symmetric(vertical: 16),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SizedBox(width: 8),
          Expanded(
            child: TextField(
              decoration: InputDecoration(
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(100),
                ),
                labelText: "Label text field",
                hintText: "Hint text field",
                errorText: hideError ? null : 'Error text shown',
                suffixIcon: IconButton(
                  onPressed: () {},
                  icon: Icon(Icons.clear),
                ),
              ),
            ),
          ),
          SizedBox(width: 8),
          trailingButton,
        ],
      ),
    );
  }
}

typedef void OnWidgetSizeChange(Size size);

class MeasureSizeRenderObject extends RenderProxyBox {
  Size oldSize;
  final OnWidgetSizeChange onChange;

  MeasureSizeRenderObject(this.onChange);

  @override
  void performLayout() {
    super.performLayout();

    Size newSize = child.size;
    if (oldSize == newSize) return;

    oldSize = newSize;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      onChange(newSize);
    });
  }
}

class MeasureSize extends SingleChildRenderObjectWidget {
  final OnWidgetSizeChange onChange;

  const MeasureSize({
    Key key,
    @required this.onChange,
    @required Widget child,
  }) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return MeasureSizeRenderObject(onChange);
  }
}

Running example 我添加了一个背景,所以它会显示高度差:

  1. 没有错误的文本字段显示文本。
  2. 显示了 errorText 的 TextField。
  3. 显示了 errorText 的 TextField,在图标按钮上有额外的填充。

Check dartpad here

答案 1 :(得分:0)

Allan 上面的回答非常好。 但是,如果您在学习时遇到问题,请这样做:

  • 将 Elevated 按钮添加到 Column 并添加高度为 22 的 SizedBox 作为其子项。这里的高度使用颤振检查器计算为(有错误的 TextFormField 的高度 - 无错误的 TextFormField 的高度)。
Column(
    children: [
        ElevatedButton(...),
        SizedBox(
            height: 22,
        ),
    ],
),
  • 现在在 TextFormField InputDecoration 中添加 helperText: ' ',
TextFormField(
    validator: (value) {
        if (value == null || value.isEmpty) {
            return "Insira um item";
        }
            return null;
        },
    decoration: InputDecoration(
        helperText: ' ',
        enabledBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.green),
        borderRadius: BorderRadius.circular(100)),
        border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(100)),
        labelText: "Novo item",
        hintText: "Insira um item",
        hintStyle: TextStyle(color: Colors.grey),
        labelStyle: TextStyle(color: Colors.green),
    ),
),

Here 你可以看到完整代码的飞镖板。

这会给你这样的结果: enter image description here