flutter软键盘覆盖Textfield和SinglechildScrollview不起作用
好的,所以我过去三天一直在观看Singlechildscroll视频和阅读论坛,每个人都说使用SinglechildScroll。对于我的一生,我无法让这个小部件使用我的注册页面。我几乎将这个小部件放在每个级别上,并将其包裹在扩展和外部扩展的其他小部件,例如带有特殊ViewinSet的容器或桨式。所以我要伸出援手,因为我现在没有想法。
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:vext/controllers/auth_controller.dart';
import 'package:vext/helpers/constants.dart';
import 'package:vext/screens/login_screen.dart';
import 'package:vext/widgets/decorativeWidgets/rounded_text_form_field.dart';
import 'package:vext/widgets/decorativeWidgets/vext_elevated_button.dart';
import 'login_title.dart';
class SignUp extends StatefulWidget {
const SignUp({Key? key}) : super(key: key);
@override
State<SignUp> createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
final _signUpFormKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final _authController = Get.find<AuthController>();
final FocusNode _nameFocus = FocusNode();
final FocusNode _emailFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
final FocusNode _passwordConfirmFocus = FocusNode();
bool _isLoading = false;
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_passwordController.dispose();
_authController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
bool keyboardIsOpen = MediaQuery.of(context).viewInsets.bottom != 0;
debugPrint('New user Sign Up Initiated');
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: kPrimaryColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 40.h,
),
LoginTitle(
title: 'Sign Up',
subtitle: 'Create an account...',
titleFontSize: 75.sp,
subFontSize: 25.sp,
),
SizedBox(height: 15.h),
buildSignUpForm(),
SizedBox(height: 30.h),
Text(
'Already have an account?',
style: TextStyle(
fontSize: 20.sp,
),
),
TextButton(
onPressed: () {
FocusScope.of(context).unfocus();
Get.to(() => LoginScreen());
},
child: Text(
'Sign In',
style: TextStyle(
color: kSecondaryColor,
fontSize: 20.sp,
),
),
style: ButtonStyle(
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
),
),
// Padding(
// padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
// ),
],
),
),
);
}
// Sign-up form Section
Form buildSignUpForm() {
return Form(
key: _signUpFormKey,
child: Column(
children: <Widget>[
RoundedTextFormField(
autoFocus: true,
focusNode: _nameFocus,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _nameFocus, _emailFocus);
},
keyboardType: TextInputType.name,
keyboardAction: TextInputAction.next,
controller: _nameController,
hintText: 'Name',
validator: (value) {
if (value.toString().length <= 2 || value!.isEmpty) {
return 'Enter a valid Name';
}
return '';
},
),
SizedBox(height: 10.h),
RoundedTextFormField(
focusNode: _emailFocus,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _emailFocus, _passwordFocus);
},
keyboardType: TextInputType.emailAddress,
keyboardAction: TextInputAction.next,
controller: _emailController,
hintText: 'Email',
validator: (value) {
bool _isEmailValid =
RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value!);
if (!_isEmailValid || value.isEmpty) {
return 'Invalid Email';
}
return '';
},
),
SizedBox(height: 10.h),
RoundedTextFormField(
focusNode: _passwordFocus,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _passwordFocus, _passwordConfirmFocus);
},
keyboardType: TextInputType.visiblePassword,
keyboardAction: TextInputAction.next,
obsecureText: true,
controller: _passwordController,
hintText: 'Password',
validator: (value) {
if (value.toString().length < 7 || value!.isEmpty) {
return 'Password should be longer or equal to 7 characters.';
}
return '';
},
),
SizedBox(height: 10.h),
RoundedTextFormField(
focusNode: _passwordConfirmFocus,
keyboardAction: TextInputAction.done,
onFieldSubmitted: (term) {
_passwordConfirmFocus.unfocus();
//Get.to(() => LoginScreen());
},
keyboardType: TextInputType.visiblePassword,
obsecureText: true,
hintText: 'Confirm Password',
validator: (value) {
if (value!.trim() != _passwordController.text.trim() || value.isEmpty) {
return 'Passwords do not match!';
}
return '';
},
),
SizedBox(height: 30.h),
_isLoading
? const CircularProgressIndicator() // TODO custom progress indicator
: VextElevatedButton(
buttonText: 'Sign Up',
onPressed: () {
debugPrint('Signup Submit button Pressed');
if (_signUpFormKey.currentState!.validate()) {
_signUpFormKey.currentState!.save();
setState(() {
_isLoading = true;
});
FocusScope.of(context).unfocus();
String name = _nameController.text.trim();
String email = _emailController.text.trim();
String password = _passwordController.text.trim();
debugPrint('Attempting Signup with Firebase');
_authController.signUp(name, email, password);
setState(() {
_isLoading = false;
});
}
},
),
],
),
);
}
}
_fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
currentFocus.unfocus();
FocusScope.of(context).requestFocus(nextFocus);
}
几次,我在所有键盘上滚动的屏幕会推动所有内容,但是当键盘关闭页面时,内容将保持在升高级别,但可滚动。
任何帮助都将不胜感激的
编辑*
这是我能想到的2个自定义小部件,这些小部件在注册屏幕
RoundedTextformfield
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:vext/helpers/constants.dart';
class RoundedTextFormField extends StatelessWidget {
const RoundedTextFormField({
Key? key,
this.controller,
required this.hintText,
this.obsecureText = false,
required this.validator,
this.keyboardType = TextInputType.text,
this.keyboardAction = TextInputAction.next,
this.focusNode,
this.onFieldSubmitted,
this.autoFocus = false,
this.errorText,
this.onChanged,
this.initialValue,
}) : super(key: key);
final TextEditingController? controller;
final bool? obsecureText;
final String? hintText;
final String? Function(String?) validator;
final TextInputType? keyboardType;
final TextInputAction keyboardAction;
final FocusNode? focusNode;
final Function(String)? onFieldSubmitted;
final bool? autoFocus;
final String? errorText;
final Function(String)? onChanged;
final String? initialValue;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 18.0.w),
child: TextFormField(
initialValue: initialValue,
onChanged: onChanged,
cursorColor: kSecondaryColor,
autofocus: autoFocus!,
keyboardType: keyboardType,
textInputAction: keyboardAction,
focusNode: focusNode,
onFieldSubmitted: onFieldSubmitted,
style: TextStyle(color: Theme.of(context).colorScheme.secondary),
controller: controller,
obscureText: obsecureText!,
decoration: InputDecoration(
errorStyle: TextStyle(
color: Colors.orange,
fontSize: 10.sp,
fontWeight: FontWeight.bold,
),
hintText: hintText,
hintStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.secondary,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.secondary,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).errorColor,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).errorColor,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
),
validator: validator,
),
);
}
}
和另一个高架按钮
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
class VextElevatedButton extends StatelessWidget {
const VextElevatedButton({
Key? key,
required this.buttonText,
required this.onPressed,
this.fontSize = 20,
}) : super(key: key);
final String? buttonText;
final double? fontSize;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(
buttonText!,
style: TextStyle(
fontSize: 20.sp,
),
),
style: ElevatedButton.styleFrom(
elevation: 20,
shadowColor: Theme.of(context).colorScheme.secondary,
minimumSize: Size(context.width * 0.4.w, context.height * 0.065.h),
onPrimary: Theme.of(context).colorScheme.secondary,
textStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.r),
side: BorderSide(
width: 2.w,
color: Theme.of(context).colorScheme.secondary,
),
),
),
);
}
}
中都使用,但这些只是flutter窗口小部件
Ok so I've spent the last 3 days watching singlechildscroll videos and reading forums and everyone says use singlechildscroll. For the life of me I can not get this widget to work with my signup page. I've placed this widget at almost every level and wrapping it in expanded and outside expanded amongst other widgets like containers or paddings with special viewinset.bottom settings and its just been a nightmare the amount of variances I've tried and still cant figure this out so I'm reaching out cause I'm out of ideas now.
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:vext/controllers/auth_controller.dart';
import 'package:vext/helpers/constants.dart';
import 'package:vext/screens/login_screen.dart';
import 'package:vext/widgets/decorativeWidgets/rounded_text_form_field.dart';
import 'package:vext/widgets/decorativeWidgets/vext_elevated_button.dart';
import 'login_title.dart';
class SignUp extends StatefulWidget {
const SignUp({Key? key}) : super(key: key);
@override
State<SignUp> createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
final _signUpFormKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final _authController = Get.find<AuthController>();
final FocusNode _nameFocus = FocusNode();
final FocusNode _emailFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
final FocusNode _passwordConfirmFocus = FocusNode();
bool _isLoading = false;
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_passwordController.dispose();
_authController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
bool keyboardIsOpen = MediaQuery.of(context).viewInsets.bottom != 0;
debugPrint('New user Sign Up Initiated');
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: kPrimaryColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 40.h,
),
LoginTitle(
title: 'Sign Up',
subtitle: 'Create an account...',
titleFontSize: 75.sp,
subFontSize: 25.sp,
),
SizedBox(height: 15.h),
buildSignUpForm(),
SizedBox(height: 30.h),
Text(
'Already have an account?',
style: TextStyle(
fontSize: 20.sp,
),
),
TextButton(
onPressed: () {
FocusScope.of(context).unfocus();
Get.to(() => LoginScreen());
},
child: Text(
'Sign In',
style: TextStyle(
color: kSecondaryColor,
fontSize: 20.sp,
),
),
style: ButtonStyle(
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
),
),
// Padding(
// padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
// ),
],
),
),
);
}
// Sign-up form Section
Form buildSignUpForm() {
return Form(
key: _signUpFormKey,
child: Column(
children: <Widget>[
RoundedTextFormField(
autoFocus: true,
focusNode: _nameFocus,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _nameFocus, _emailFocus);
},
keyboardType: TextInputType.name,
keyboardAction: TextInputAction.next,
controller: _nameController,
hintText: 'Name',
validator: (value) {
if (value.toString().length <= 2 || value!.isEmpty) {
return 'Enter a valid Name';
}
return '';
},
),
SizedBox(height: 10.h),
RoundedTextFormField(
focusNode: _emailFocus,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _emailFocus, _passwordFocus);
},
keyboardType: TextInputType.emailAddress,
keyboardAction: TextInputAction.next,
controller: _emailController,
hintText: 'Email',
validator: (value) {
bool _isEmailValid =
RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value!);
if (!_isEmailValid || value.isEmpty) {
return 'Invalid Email';
}
return '';
},
),
SizedBox(height: 10.h),
RoundedTextFormField(
focusNode: _passwordFocus,
onFieldSubmitted: (term) {
_fieldFocusChange(context, _passwordFocus, _passwordConfirmFocus);
},
keyboardType: TextInputType.visiblePassword,
keyboardAction: TextInputAction.next,
obsecureText: true,
controller: _passwordController,
hintText: 'Password',
validator: (value) {
if (value.toString().length < 7 || value!.isEmpty) {
return 'Password should be longer or equal to 7 characters.';
}
return '';
},
),
SizedBox(height: 10.h),
RoundedTextFormField(
focusNode: _passwordConfirmFocus,
keyboardAction: TextInputAction.done,
onFieldSubmitted: (term) {
_passwordConfirmFocus.unfocus();
//Get.to(() => LoginScreen());
},
keyboardType: TextInputType.visiblePassword,
obsecureText: true,
hintText: 'Confirm Password',
validator: (value) {
if (value!.trim() != _passwordController.text.trim() || value.isEmpty) {
return 'Passwords do not match!';
}
return '';
},
),
SizedBox(height: 30.h),
_isLoading
? const CircularProgressIndicator() // TODO custom progress indicator
: VextElevatedButton(
buttonText: 'Sign Up',
onPressed: () {
debugPrint('Signup Submit button Pressed');
if (_signUpFormKey.currentState!.validate()) {
_signUpFormKey.currentState!.save();
setState(() {
_isLoading = true;
});
FocusScope.of(context).unfocus();
String name = _nameController.text.trim();
String email = _emailController.text.trim();
String password = _passwordController.text.trim();
debugPrint('Attempting Signup with Firebase');
_authController.signUp(name, email, password);
setState(() {
_isLoading = false;
});
}
},
),
],
),
);
}
}
_fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
currentFocus.unfocus();
FocusScope.of(context).requestFocus(nextFocus);
}
The few times I got the screen to scroll at all the keyboard would push everything up but when the keyboard would close the page contents would stay at the raised level but scrollable.
Any help would be most appreciated
EDIT*
Here are the 2 custom Widgets that I can think of that are used in the signup screen
roundedTextFormfield
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:vext/helpers/constants.dart';
class RoundedTextFormField extends StatelessWidget {
const RoundedTextFormField({
Key? key,
this.controller,
required this.hintText,
this.obsecureText = false,
required this.validator,
this.keyboardType = TextInputType.text,
this.keyboardAction = TextInputAction.next,
this.focusNode,
this.onFieldSubmitted,
this.autoFocus = false,
this.errorText,
this.onChanged,
this.initialValue,
}) : super(key: key);
final TextEditingController? controller;
final bool? obsecureText;
final String? hintText;
final String? Function(String?) validator;
final TextInputType? keyboardType;
final TextInputAction keyboardAction;
final FocusNode? focusNode;
final Function(String)? onFieldSubmitted;
final bool? autoFocus;
final String? errorText;
final Function(String)? onChanged;
final String? initialValue;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 18.0.w),
child: TextFormField(
initialValue: initialValue,
onChanged: onChanged,
cursorColor: kSecondaryColor,
autofocus: autoFocus!,
keyboardType: keyboardType,
textInputAction: keyboardAction,
focusNode: focusNode,
onFieldSubmitted: onFieldSubmitted,
style: TextStyle(color: Theme.of(context).colorScheme.secondary),
controller: controller,
obscureText: obsecureText!,
decoration: InputDecoration(
errorStyle: TextStyle(
color: Colors.orange,
fontSize: 10.sp,
fontWeight: FontWeight.bold,
),
hintText: hintText,
hintStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.secondary,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.secondary,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).errorColor,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).errorColor,
width: 2.w,
),
borderRadius: BorderRadius.all(
Radius.circular(30.0.r),
),
),
),
validator: validator,
),
);
}
}
and the other of an elevated button
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
class VextElevatedButton extends StatelessWidget {
const VextElevatedButton({
Key? key,
required this.buttonText,
required this.onPressed,
this.fontSize = 20,
}) : super(key: key);
final String? buttonText;
final double? fontSize;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(
buttonText!,
style: TextStyle(
fontSize: 20.sp,
),
),
style: ElevatedButton.styleFrom(
elevation: 20,
shadowColor: Theme.of(context).colorScheme.secondary,
minimumSize: Size(context.width * 0.4.w, context.height * 0.065.h),
onPrimary: Theme.of(context).colorScheme.secondary,
textStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.r),
side: BorderSide(
width: 2.w,
color: Theme.of(context).colorScheme.secondary,
),
),
),
);
}
}
but these are just the flutter widgets with set options for reusability
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
将您的注册类列用 singlechildscrollview 用 容器包裹起来,它们具有以下属性
Wrap your SignUp class column with SingleChildScrollview after that wrap it up with Container which have property Like Below