在 Flutter 的自定义 TextFormField 中将验证器消息定位在边框之外

问题描述 投票:0回答:1

正在开发 Flutter 应用程序并使用

CustomTextFormField
小部件来处理用户输入。但是,我遇到了验证器消息出现在字段边框内的问题,我想将其放置在边框外。

这是我创建的

CustomTextFormField
小部件的片段:

import 'package:flutter/material.dart';

class CustomTextFormField extends StatefulWidget {
  final String label;
  final String? Function(String?)? validator;
  final void Function(String?)? onSaved;
  final TextEditingController? controller;
  final String? type;
  final TextInputType keyboardType;
  final IconData? suffixIcon;
  final IconData? prefixIcon;
  final bool isPassword; // Menambahkan parameter untuk kolom password
  final bool giveBorder;
  final bool isRequired;

  const CustomTextFormField({
    super.key,
    required this.label,
    required this.validator,
    this.controller,
    required this.type,
    required this.keyboardType,
    required this.onSaved,
    this.suffixIcon,
    this.prefixIcon,
    this.isPassword = false, // Default tidak menggunakan password
    this.giveBorder = false,
    this.isRequired = false,
  });
  @override
  State<CustomTextFormField> createState() {
    return _CustomTextFormFieldState();
  }
}

class _CustomTextFormFieldState extends State<CustomTextFormField> {
  bool _obscureText = true; // Mengatur visibilitas password

  @override
  Widget build(BuildContext context) {
    Widget content = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        widget.isRequired
            ? Row(
                children: [
                  Text(
                    widget.label,
                    style: const TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.w600,
                      color: Colors.black54,
                    ),
                    textAlign: TextAlign.start,
                  ),
                  const Text(
                    ' *',
                    style: TextStyle(color: Colors.red),
                  )
                ],
              )
            : Text(
                widget.label,
                style: const TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                  color: Colors.black54,
                ),
                textAlign: TextAlign.start,
              ),
        widget.giveBorder
            ? Container(
                margin: const EdgeInsets.symmetric(vertical: 8),
                padding: const EdgeInsets.symmetric(horizontal: 16),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(10),
                  border:
                      Border.all(color: Colors.black12), // Border warna abu-abu
                ),
                child: TextField(
                  controller: widget.controller,
                  keyboardType: widget.keyboardType,
                  obscureText: widget.isPassword ? _obscureText : false,
                  decoration: InputDecoration(
                    border: InputBorder.none, // Hilangkan border default
                    hintText: widget.label, // Placeholder
                    hintStyle: const TextStyle(color: Colors.grey),
                    prefixIcon: widget.prefixIcon != null
                        ? Icon(widget.prefixIcon)
                        : null,
                    suffixIcon:
                        widget.isPassword // Menambahkan ikon untuk password
                            ? IconButton(
                                icon: Icon(
                                  _obscureText
                                      ? Icons
                                          .visibility_off // Tampilkan ikon 'lihat'
                                      : Icons
                                          .visibility, // Tampilkan ikon 'sembunyikan'
                                ),
                                onPressed: () {
                                  setState(() {
                                    _obscureText =
                                        !_obscureText; // Toggle visibilitas
                                  });
                                },
                              )
                            : widget.suffixIcon != null
                                ? Icon(widget.suffixIcon)
                                : null,
                  ),
                ),
              )
            : TextField(
                controller: widget.controller,
                keyboardType: widget.keyboardType,
                obscureText: widget.isPassword ? _obscureText : false,
                decoration: InputDecoration(
                  hintText: widget.label, // Placeholder
                  hintStyle: const TextStyle(color: Colors.grey),
                  prefixIcon: widget.prefixIcon != null
                      ? Icon(widget.prefixIcon)
                      : null,
                  suffixIcon: widget
                          .isPassword // Menambahkan ikon untuk password
                      ? IconButton(
                          icon: Icon(
                            _obscureText
                                ? Icons.visibility_off // Tampilkan ikon 'lihat'
                                : Icons
                                    .visibility, // Tampilkan ikon 'sembunyikan'
                          ),
                          onPressed: () {
                            setState(() {
                              _obscureText =
                                  !_obscureText; // Toggle visibilitas
                            });
                          },
                        )
                      : widget.suffixIcon != null
                          ? Icon(widget.suffixIcon)
                          : null,
                ),
              ),
      ],
    );

    if (widget.type == 'form') {
      content = Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          widget.isRequired
              ? Row(
                  children: [
                    Text(
                      widget.label,
                      style: const TextStyle(
                        fontSize: 14,
                        fontWeight: FontWeight.w600,
                        color: Colors.black54,
                      ),
                      textAlign: TextAlign.start,
                    ),
                    const Text(
                      ' *',
                      style: TextStyle(color: Colors.red),
                    )
                  ],
                )
              : Text(
                  widget.label,
                  style: const TextStyle(
                    fontSize: 14,
                    fontWeight: FontWeight.w600,
                    color: Colors.black54,
                  ),
                  textAlign: TextAlign.start,
                ),
          Container(
            alignment: Alignment.center,
            margin: const EdgeInsets.symmetric(vertical: 8),
            padding: EdgeInsets.only(
              right: 4,
              left: widget.prefixIcon != null ? 4 : 16,
            ),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(10),
              border: widget.giveBorder
                  ? Border.all(color: Colors.grey)
                  : Border.all(color: Colors.black12), // Border warna abu-abu
            ),
            child: TextFormField(
              controller: widget.controller,
              keyboardType: widget.keyboardType,
              obscureText: widget.isPassword ? _obscureText : false,
              decoration: InputDecoration(
                border: InputBorder.none, // Hilangkan border default
                hintText: widget.label, // Placeholder
                hintStyle: const TextStyle(color: Colors.grey),
                prefixIcon:
                    widget.prefixIcon != null ? Icon(widget.prefixIcon) : null,
                contentPadding: widget.isPassword
                    ? const EdgeInsets.symmetric(vertical: 12)
                    : null,
                suffixIcon: widget.isPassword // Menambahkan ikon untuk password
                    ? IconButton(
                        icon: Icon(
                          _obscureText
                              ? Icons.visibility_off
                              : Icons.visibility,
                        ),
                        padding: EdgeInsets.zero,
                        iconSize: 20,
                        onPressed: () {
                          setState(() {
                            _obscureText = !_obscureText;
                          });
                        },
                      )
                    : widget.suffixIcon != null
                        ? Icon(widget.suffixIcon)
                        : null,
              ),
              onSaved: widget.onSaved,
              validator: widget.validator,
            ),
          ),
        ],
      );
    }

    return content;
  }
}

但是,当验证失败时,错误消息会出现在 TextFormField 的边框内,如下图所示:

我想知道如何将验证器消息移动到边框之外,这样它就不会干扰输入外观。有推荐的方法来实现这一目标吗?先谢谢你了enter image description here

我希望验证器位于边界之外

flutter flutter-textformfield
1个回答
0
投票

不要在 TextFormField 的装饰中使用 border: InputBorder.none ,而是尝试使用更明确的边框:

边框:轮廓输入边框( borderRadius: BorderRadius.circular(6), borderSide: const BorderSide( 宽度:1, 颜色:边框颜色, ), ),

© www.soinside.com 2019 - 2024. All rights reserved.