键盘显示时树重建
tree rebuilds when keyboard shows
我正在为我的应用程序使用 responsive_sizer 包..
当键盘以文本字段打开时,我的整个树被重建。
这里是文本字段的代码:
class ProfileNameTextField extends StatefulWidget {
const ProfileNameTextField({Key? key}) : super(key: key);
@override
_ProfileNameTextFieldState createState() => _ProfileNameTextFieldState();
}
class _ProfileNameTextFieldState extends State<ProfileNameTextField> {
TextEditingController? _controller;
String _previousName = "";
FocusNode? _focusNode;
final String _forbiddenCharacters = "1234567890&)°(+=/,;.£$*€<>\_#@";
Widget _subText = Container();
@override
void initState() {
// TODO: implement initState
_controller = TextEditingController();
_previousName = CloudUser.instance.username;
_controller!.text = CloudUser.instance.username;
_focusNode = FocusNode();
_focusNode!.addListener(() {
if(!_focusNode!.hasFocus) {
print("Focus on name textfield is lost");
_onSubmitted(_controller!.text);
}
});
super.initState();
}
@override
void dispose() {
// Clean up the focus node when the Form is disposed.
_focusNode!.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Widget? _suffix;
switch(Provider.of<LoadingProvider>(context).state) {
case LoadingState.busy:
_suffix = SpinKitRing(
color: Theme
.of(context)
.primaryColor,
lineWidth: 2,
size: Theme.of(context).textTheme.subtitle1!.fontSize!
);
break;
case LoadingState.idle:
_suffix = Container();
break;
}
return CustomTextContainer(
child: InkWell(
onTap: _giveFocus,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children:
[
Text(
"Prénom",
style: Theme.of(context).textTheme.bodyText2!.copyWith(
fontSize: Theme.of(context).textTheme.bodyText2!.fontSize!.sp
)
),
Container(height: Sizer().heightSmallSpace),
Container(height: Theme.of(context).textTheme.bodyText1!.fontSize,
child: Row(children: [
Expanded(
child: TextField(
keyboardType: TextInputType.name,
controller: _controller,
onSubmitted: _onSubmitted,
focusNode: _focusNode,
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
),
style: Theme.of(context).textTheme.bodyText1!.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.w600,
fontSize: Theme.of(context).textTheme.bodyText1!.fontSize!.sp
),
textAlign: TextAlign.start,
),),
_suffix,
]),
),
Container(height: Sizer().heightSmallSpace),
Row(children: [
Spacer(),
Container(
height: Theme.of(context).textTheme.subtitle1!.fontSize!*1.2,
child: Center(child: _subText)),
]),
Container(height: Sizer().heightSmallSpace),
]
)
)
);
}
_onSubmitted(String username) {
RegExp regExp = RegExp('[' + _forbiddenCharacters + ']');
if(!regExp.hasMatch(username)) {
if(_previousName != username) {
print("name is " + username);
_previousName = username;
setState(() {
_subText = Container();
});
Provider.of<LoadingProvider>(context, listen: false).update('username', username).then((result) {
if(result) {
CloudUser.instance.username = username;
setState(() {
_subText = Text(
"Enregistré",
style: Theme
.of(context)
.textTheme
.subtitle1!
.copyWith(
color: color.success,
fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
),
);
});
}
else
setState(() {
_subText = Text(
"Erreur serveur",
style: Theme.of(context).textTheme.subtitle1!.copyWith(
color: Theme.of(context).errorColor,
fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
),
);
});
});
}
} else {
setState(() {
_subText = Text(
"Caractères interdits",
style: Theme.of(context).textTheme.subtitle1!.copyWith(
color: Theme.of(context).errorColor,
fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
),
textAlign: TextAlign.right,
);
});
}
}
_giveFocus() {
_focusNode!.requestFocus();
}
}
在 Sizer() 中,我有:
double padding = 2.h;
double widgetHeight = 8.h;
double iconButton = 4.h;
double radius = 15;
double lineWidth = 3.h;
double heightSpace = 3.h;
double heightSmallSpace = 0.9.h;
double gridSpacing = 0.3.h;
double widthSpace = 1.25.w;
ProfileNameTextField 包含在
class _ProfileControllerState extends State<ProfileController> {
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).backgroundColor,
child: Column(
children: [
ProfileAppBar(
onSetting: _onSetting,
),
Flexible(
child: Container(
padding: EdgeInsets.symmetric(horizontal: Sizer().padding/3),
color: Theme.of(context).scaffoldBackgroundColor,
child: Scrollbar(
child: SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Container(
padding: EdgeInsets.symmetric(horizontal: Sizer().padding*2/3),
child: Column(children:
[
Container(height: Sizer().heightSpace),
SvgPicture.asset(
"assets/icons/phone_kisses.svg",
height: Sizer().widgetHeight*3,
width: Sizer().getCustomWidth(66),
fit: BoxFit.contain,
),
_space(),
ChangeNotifierProvider<LoadingProvider>(
create: (BuildContext context) => LoadingProvider(),
child: ProfileNameTextField(),
),
我在导入 responsive_sizer 后遇到了这个问题...我不明白问题出在哪里。
我尝试了 resizetoavoidbottominset 但没有任何改变。
我发现了问题。它不是来自 MediaQuery,而是来自 Responsive_sizer 包。
当我打开键盘时,我实际上更新了高度和宽度。但是这个包必须以下列方式包含您的 MaterialApp:
MaterialApp(
home: ResponsiveSizer(
builder: (context, orientation, screenType) {
return const HomePage();
},
),
);
这就是问题所在。在我的主页下,我有一个流来查看用户是否已登录,然后会转到个人资料页面等。我不希望它重新加载,我只希望配置文件重新加载。
我的解决方案:我使用 MediaQuery 的方式与 Responsive_sizer 类似。我没有使用 .h 和 .w 包,而是使用 MediaQuery.of(context).size.height 及其对应物。字体大小也是一样。
希望能帮到和我有相同问题的朋友,
晚上好
我正在为我的应用程序使用 responsive_sizer 包..
当键盘以文本字段打开时,我的整个树被重建。
这里是文本字段的代码:
class ProfileNameTextField extends StatefulWidget {
const ProfileNameTextField({Key? key}) : super(key: key);
@override
_ProfileNameTextFieldState createState() => _ProfileNameTextFieldState();
}
class _ProfileNameTextFieldState extends State<ProfileNameTextField> {
TextEditingController? _controller;
String _previousName = "";
FocusNode? _focusNode;
final String _forbiddenCharacters = "1234567890&)°(+=/,;.£$*€<>\_#@";
Widget _subText = Container();
@override
void initState() {
// TODO: implement initState
_controller = TextEditingController();
_previousName = CloudUser.instance.username;
_controller!.text = CloudUser.instance.username;
_focusNode = FocusNode();
_focusNode!.addListener(() {
if(!_focusNode!.hasFocus) {
print("Focus on name textfield is lost");
_onSubmitted(_controller!.text);
}
});
super.initState();
}
@override
void dispose() {
// Clean up the focus node when the Form is disposed.
_focusNode!.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Widget? _suffix;
switch(Provider.of<LoadingProvider>(context).state) {
case LoadingState.busy:
_suffix = SpinKitRing(
color: Theme
.of(context)
.primaryColor,
lineWidth: 2,
size: Theme.of(context).textTheme.subtitle1!.fontSize!
);
break;
case LoadingState.idle:
_suffix = Container();
break;
}
return CustomTextContainer(
child: InkWell(
onTap: _giveFocus,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children:
[
Text(
"Prénom",
style: Theme.of(context).textTheme.bodyText2!.copyWith(
fontSize: Theme.of(context).textTheme.bodyText2!.fontSize!.sp
)
),
Container(height: Sizer().heightSmallSpace),
Container(height: Theme.of(context).textTheme.bodyText1!.fontSize,
child: Row(children: [
Expanded(
child: TextField(
keyboardType: TextInputType.name,
controller: _controller,
onSubmitted: _onSubmitted,
focusNode: _focusNode,
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
),
style: Theme.of(context).textTheme.bodyText1!.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.w600,
fontSize: Theme.of(context).textTheme.bodyText1!.fontSize!.sp
),
textAlign: TextAlign.start,
),),
_suffix,
]),
),
Container(height: Sizer().heightSmallSpace),
Row(children: [
Spacer(),
Container(
height: Theme.of(context).textTheme.subtitle1!.fontSize!*1.2,
child: Center(child: _subText)),
]),
Container(height: Sizer().heightSmallSpace),
]
)
)
);
}
_onSubmitted(String username) {
RegExp regExp = RegExp('[' + _forbiddenCharacters + ']');
if(!regExp.hasMatch(username)) {
if(_previousName != username) {
print("name is " + username);
_previousName = username;
setState(() {
_subText = Container();
});
Provider.of<LoadingProvider>(context, listen: false).update('username', username).then((result) {
if(result) {
CloudUser.instance.username = username;
setState(() {
_subText = Text(
"Enregistré",
style: Theme
.of(context)
.textTheme
.subtitle1!
.copyWith(
color: color.success,
fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
),
);
});
}
else
setState(() {
_subText = Text(
"Erreur serveur",
style: Theme.of(context).textTheme.subtitle1!.copyWith(
color: Theme.of(context).errorColor,
fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
),
);
});
});
}
} else {
setState(() {
_subText = Text(
"Caractères interdits",
style: Theme.of(context).textTheme.subtitle1!.copyWith(
color: Theme.of(context).errorColor,
fontSize: Theme.of(context).textTheme.subtitle1!.fontSize!.sp
),
textAlign: TextAlign.right,
);
});
}
}
_giveFocus() {
_focusNode!.requestFocus();
}
}
在 Sizer() 中,我有:
double padding = 2.h;
double widgetHeight = 8.h;
double iconButton = 4.h;
double radius = 15;
double lineWidth = 3.h;
double heightSpace = 3.h;
double heightSmallSpace = 0.9.h;
double gridSpacing = 0.3.h;
double widthSpace = 1.25.w;
ProfileNameTextField 包含在
class _ProfileControllerState extends State<ProfileController> {
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).backgroundColor,
child: Column(
children: [
ProfileAppBar(
onSetting: _onSetting,
),
Flexible(
child: Container(
padding: EdgeInsets.symmetric(horizontal: Sizer().padding/3),
color: Theme.of(context).scaffoldBackgroundColor,
child: Scrollbar(
child: SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Container(
padding: EdgeInsets.symmetric(horizontal: Sizer().padding*2/3),
child: Column(children:
[
Container(height: Sizer().heightSpace),
SvgPicture.asset(
"assets/icons/phone_kisses.svg",
height: Sizer().widgetHeight*3,
width: Sizer().getCustomWidth(66),
fit: BoxFit.contain,
),
_space(),
ChangeNotifierProvider<LoadingProvider>(
create: (BuildContext context) => LoadingProvider(),
child: ProfileNameTextField(),
),
我在导入 responsive_sizer 后遇到了这个问题...我不明白问题出在哪里。 我尝试了 resizetoavoidbottominset 但没有任何改变。
我发现了问题。它不是来自 MediaQuery,而是来自 Responsive_sizer 包。
当我打开键盘时,我实际上更新了高度和宽度。但是这个包必须以下列方式包含您的 MaterialApp:
MaterialApp(
home: ResponsiveSizer(
builder: (context, orientation, screenType) {
return const HomePage();
},
),
);
这就是问题所在。在我的主页下,我有一个流来查看用户是否已登录,然后会转到个人资料页面等。我不希望它重新加载,我只希望配置文件重新加载。
我的解决方案:我使用 MediaQuery 的方式与 Responsive_sizer 类似。我没有使用 .h 和 .w 包,而是使用 MediaQuery.of(context).size.height 及其对应物。字体大小也是一样。
希望能帮到和我有相同问题的朋友, 晚上好