iOS如果在设置中打开了【自动填充密码】就会显示出这个密码栏,输入时会一闪一闪的
【原因】:在TextField里,只要obscureText为true时,也就是密码框显示全是【•】时,iOS的密码填充栏就会显示出来。
所以我的解决思路是把obscureText写死为False:
这时我们只要解决当他的小眼睛闭上,也就是隐藏密码时,输入框里的显示怎么变为【•】就行了。
上代码!!!
1、把obscureText写死成false
2、在onChange里判断是否隐藏或显示密码,如果是隐藏状态,就把输入框里的value全部替换成【•】;如果显示密码状态,我们只要把realPassword给显示就行--【需要留一个变量去存真实的密码】
TextField(
//只要这个变成了true,也就是密码隐藏密码开关,这个填充密码栏就会显示出来
obscureText: false,
textAlign: TextAlign.start,
inputFormatters: widget.inputFormatters,
controller: widget.controller,
focusNode: widget.focusNode,
autocorrect: false,
onChanged: (value) {
if (widget.onChanged != null) {
widget.onChanged!(value);
}
if (widget.obscureText) {
realPassword = value;
String obscureText = value.replaceAll(RegExp('.'), '•');
if (widget.realPasswordListener != null) {
widget.realPasswordListener!(realPassword);
}
// 设置TextField显示遮蔽字符
widget.controller.value = TextEditingValue(
text: !isShowPsw ? obscureText : realPassword,
selection: TextSelection.collapsed(
offset: widget.controller.selection.baseOffset,
),
);
}
},
toolbarOptions: ToolbarOptions(
copy: !widget.obscureText,
cut: !widget.obscureText,
paste: true,
selectAll: true,
),
cursorColor: Theme.of(context).textTheme.titleLarge!.color!,
style: TextStyle(
color: Theme.of(context).textTheme.titleLarge!.color!,
fontSize: Dimens.font_sp15,
),
decoration: InputDecoration(
hintText: widget.hintText,
hintStyle: TextStyle(
fontSize: Dimens.font_sp15,
color: Theme.of(context).textTheme.bodyLarge!.color!,
),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
keyboardType: widget.keyboardType,
maxLines: 1,
minLines: 1,
),
3、在小眼睛按钮处,如果切换状态,也要全部替换成【•】或者真实密码
//小眼睛图标
if (widget.obscureText)
showPswButton(
context,
isShowPsw: isShowPsw,
onTap: () {
isShowPsw = !isShowPsw;
if (widget.controller.text.isEmpty) {
realPassword = "";
}
if (widget.realPasswordListener != null) {
widget.realPasswordListener!(realPassword);
}
String obscureText = realPassword;
widget.controller.value = TextEditingValue(
text: isShowPsw
? realPassword
: obscureText.replaceAll(RegExp('.'), '•'),
selection: TextSelection.collapsed(
offset: widget.controller.selection.baseOffset,
),
);
setState(() {});
},
),
4、接下来我们在页面上调用封装的输入框:核心是inputFormatters里面TestPswFormatter,在这里面给真实密码去赋值
TestTextField(
icon: 'ic_password',
controller: pswOneController,
focusNode: pswOneFocusNode,
hintText: "请设置密码",
keyboardType: Platform.isIOS
? TextInputType.datetime
: TextInputType.visiblePassword,
realPasswordListener: (value) {
realPassword = value;
setState(() {});
},
inputFormatters: [
//只允许输入数字,字母
FilteringTextInputFormatter(
RegExp("^[a-z0-9A-Z•]+"),
allow: true,
),
LengthLimitingTextInputFormatter(20),
//给真实密码realPassword赋值
TestPswFormatter(realPassword: realPassword),
],
obscureText: true,
)
5、TestPswFormatter:处理真实密码,每次输入都给realPassword赋值,光标位置也需要处理
class TestPswFormatter extends TextInputFormatter {
String realPassword;
TestPswFormatter({this.realPassword = ""});
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
print("realPassword:${realPassword}");
print("oldzqhValue:${oldValue}");
print("newzqhValue:$newValue");
if (newValue.text == "") {
realPassword = "";
} else if (newValue.text.length - oldValue.text.length > 1) {
String newText = newValue.text;
newText = newText.replaceAll('•', '');
realPassword = newText;
return TextEditingValue(
text: realPassword,
selection: TextSelection.fromPosition(
TextPosition(
affinity: TextAffinity.downstream,
offset: realPassword.length,
),
),
);
} else if (realPassword.length < newValue.text.length) {
// 截取光标前的字符串和光标后的字符串
String beforeCursor =
realPassword.substring(0, newValue.selection.baseOffset - 1);
String afterCursor = realPassword.substring(
newValue.selection.baseOffset - 1, realPassword.length);
realPassword = beforeCursor +
newValue.text[newValue.selection.baseOffset - 1] +
afterCursor;
} else if (realPassword.length > newValue.text.length) {
String beforeCursor =
realPassword.substring(0, newValue.selection.baseOffset);
String afterCursor = realPassword.substring(
newValue.selection.baseOffset + 1, realPassword.length);
realPassword = beforeCursor + afterCursor;
}
return TextEditingValue(
text: realPassword,
selection: TextSelection.collapsed(offset: newValue.selection.baseOffset),
);
}
}
这样就解决这个问题了,下面是完整代码:
页面代码:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../common/res/colors.dart';
import '../utils/cache_util.dart';
import 'common/image/load_image.dart';
import 'common/res/dimens.dart';
class TestPage extends StatefulWidget {
const TestPage({super.key});
@override
State<TestPage> createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
TextEditingController pswOneController = TextEditingController();
FocusNode pswOneFocusNode = FocusNode();
//用于记录真实密码,输入框内密码在隐藏的情况下全是•
String realPassword = "";
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Center(
child: TestTextField(
icon: 'ic_password',
controller: pswOneController,
focusNode: pswOneFocusNode,
hintText: "请设置密码",
keyboardType: Platform.isIOS
? TextInputType.datetime
: TextInputType.visiblePassword,
realPasswordListener: (value) {
realPassword = value;
setState(() {});
},
inputFormatters: [
//只允许输入数字,字母
FilteringTextInputFormatter(
RegExp("^[a-z0-9A-Z•]+"),
allow: true,
),
LengthLimitingTextInputFormatter(20),
//给真实密码realPassword赋值
TestPswFormatter(realPassword: realPassword),
],
obscureText: true,
),
),
);
}
}
输入框封装代码:
class TestTextField extends StatefulWidget {
final String? icon;
final List<TextInputFormatter>? inputFormatters;
final TextEditingController controller;
final FocusNode focusNode;
final String hintText;
final bool obscureText;
final TextInputType keyboardType;
final ValueChanged<String>? realPasswordListener;
final ValueChanged<String>? onChanged;
const TestTextField({
super.key,
this.icon,
required this.controller,
required this.focusNode,
required this.hintText,
required this.keyboardType,
this.inputFormatters,
this.obscureText = false,
this.realPasswordListener,
this.onChanged,
});
@override
State<TestTextField> createState() => _TestTextFieldState();
}
class _TestTextFieldState extends State<TestTextField> {
bool showClearButton = false;
String realPassword = '';
bool isShowPsw = false;
@override
void initState() {
super.initState();
widget.focusNode.addListener(() {
showClearButton =
widget.controller.text.isNotEmpty && widget.focusNode.hasFocus;
setState(() {});
});
widget.controller.addListener(() {
showClearButton =
widget.controller.text.isNotEmpty && widget.focusNode.hasFocus;
if (widget.controller.text.isEmpty) {
realPassword = "";
if (widget.realPasswordListener != null) {
widget.realPasswordListener!(realPassword);
}
}
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(4.r),
),
margin: EdgeInsets.symmetric(
horizontal: 36.w,
),
padding: EdgeInsets.only(
left: 16.w,
right: 8.w,
),
child: Row(
children: [
if (widget.icon != null)
Padding(
padding: EdgeInsets.only(right: 10.w),
child: LoadAssetImage(
widget.icon!,
width: 20.w,
height: 20.h,
color: Theme.of(context).textTheme.titleMedium?.color,
),
),
Expanded(
child: TextField(
//只要这个变成了true,也就是密码隐藏密码开关,这个填充密码栏就会显示出来
obscureText: false,
textAlign: TextAlign.start,
inputFormatters: widget.inputFormatters,
controller: widget.controller,
focusNode: widget.focusNode,
autocorrect: false,
onChanged: (value) {
if (widget.onChanged != null) {
widget.onChanged!(value);
}
if (widget.obscureText) {
realPassword = value;
String obscureText = value.replaceAll(RegExp('.'), '•');
if (widget.realPasswordListener != null) {
widget.realPasswordListener!(realPassword);
}
// 设置TextField显示遮蔽字符
widget.controller.value = TextEditingValue(
text: !isShowPsw ? obscureText : realPassword,
selection: TextSelection.collapsed(
offset: widget.controller.selection.baseOffset,
),
);
}
},
toolbarOptions: ToolbarOptions(
copy: !widget.obscureText,
cut: !widget.obscureText,
paste: true,
selectAll: true,
),
cursorColor: Theme.of(context).textTheme.titleLarge!.color!,
style: TextStyle(
color: Theme.of(context).textTheme.titleLarge!.color!,
fontSize: Dimens.font_sp15,
),
decoration: InputDecoration(
hintText: widget.hintText,
hintStyle: TextStyle(
fontSize: Dimens.font_sp15,
color: Theme.of(context).textTheme.bodyLarge!.color!,
),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
keyboardType: widget.keyboardType,
maxLines: 1,
minLines: 1,
),
),
//清除图标
if (showClearButton)
clearButton(
context,
onTap: () {
widget.controller.clear();
if (widget.realPasswordListener != null) {
widget.realPasswordListener!(widget.controller.text);
}
},
),
//小眼睛图标
if (widget.obscureText)
showPswButton(
context,
isShowPsw: isShowPsw,
onTap: () {
isShowPsw = !isShowPsw;
if (widget.controller.text.isEmpty) {
realPassword = "";
}
if (widget.realPasswordListener != null) {
widget.realPasswordListener!(realPassword);
}
String obscureText = realPassword;
widget.controller.value = TextEditingValue(
text: isShowPsw
? realPassword
: obscureText.replaceAll(RegExp('.'), '•'),
selection: TextSelection.collapsed(
offset: widget.controller.selection.baseOffset,
),
);
setState(() {});
},
),
],
),
);
}
}
//输入框清除按钮
Widget clearButton(BuildContext context,
{required Function onTap, EdgeInsetsGeometry? margin}) {
return InkWell(
onTap: () => onTap(),
child: Container(
decoration: BoxDecoration(
color: appIsDark ? COLOR_FF606062 : COLOR_FFD8D9DD,
shape: BoxShape.circle,
),
margin: margin ?? EdgeInsets.all(8.h),
child: LoadAssetSvg(
'ic_clear',
width: 16.w,
height: 16.h,
color: Theme.of(context).secondaryHeaderColor,
),
),
);
}
//显示或隐藏密码的按钮
Widget showPswButton(BuildContext context,
{required bool isShowPsw, required Function onTap}) {
return InkWell(
onTap: () => onTap(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadAssetImage(
isShowPsw ? 'ic_show' : 'ic_hide',
width: 16.w,
height: 16.h,
color: Theme.of(context).textTheme.titleSmall?.color,
),
),
);
}
TestPswFormatter:真实密码赋值
class TestPswFormatter extends TextInputFormatter {
String realPassword;
TestPswFormatter({this.realPassword = ""});
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
print("realPassword:${realPassword}");
print("oldzqhValue:${oldValue}");
print("newzqhValue:$newValue");
if (newValue.text == "") {
realPassword = "";
} else if (newValue.text.length - oldValue.text.length > 1) {
String newText = newValue.text;
newText = newText.replaceAll('•', '');
realPassword = newText;
return TextEditingValue(
text: realPassword,
selection: TextSelection.fromPosition(
TextPosition(
affinity: TextAffinity.downstream,
offset: realPassword.length,
),
),
);
} else if (realPassword.length < newValue.text.length) {
// 截取光标前的字符串和光标后的字符串
String beforeCursor =
realPassword.substring(0, newValue.selection.baseOffset - 1);
String afterCursor = realPassword.substring(
newValue.selection.baseOffset - 1, realPassword.length);
realPassword = beforeCursor +
newValue.text[newValue.selection.baseOffset - 1] +
afterCursor;
} else if (realPassword.length > newValue.text.length) {
String beforeCursor =
realPassword.substring(0, newValue.selection.baseOffset);
String afterCursor = realPassword.substring(
newValue.selection.baseOffset + 1, realPassword.length);
realPassword = beforeCursor + afterCursor;
}
return TextEditingValue(
text: realPassword,
selection: TextSelection.collapsed(offset: newValue.selection.baseOffset),
);
}
}