正在开发 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 的边框内,如下图所示:
我想知道如何将验证器消息移动到边框之外,这样它就不会干扰输入外观。有推荐的方法来实现这一目标吗?先谢谢你了
我希望验证器位于边界之外
不要在 TextFormField 的装饰中使用 border: InputBorder.none ,而是尝试使用更明确的边框:
边框:轮廓输入边框( borderRadius: BorderRadius.circular(6), borderSide: const BorderSide( 宽度:1, 颜色:边框颜色, ), ),