خطای "سرریز پایین صفحه" ناشی از صفحه کلید در فلاتر Bottom Overflowed
سلام! خوشحالم که دوباره با مقاله جدیدی درباره Flutter، با شما هستم. اگر تا به حال با TextFormFields در Flutter کار کرده باشید، مطمئن هستم که نوارهای زرد / سیاه روی پایین صفحه نمایش خود دیده اید، درست مانند تصویر زیر. در این مقاله ، ما در مورد بهترین راه حل برای جلوگیری از خطای سرریز پایین صفحه (Bottom Overflough) هنگام ظاهر شدن صفحه کلید صحبت خواهیم کرد.
همانطور که مشاهده می کنید ویجت ها باید به صورت عمودی نمایش داده شوند، به همین دلیل به عنوان والد به یک ویجت ستون یا همان column احتیاج داریم. رنگ پس زمینه و فاصله چپ / راست (padding) را فراموش نکنید! برای سفارشی کردن پس زمینه به یک Container با خاصیت decotation مانند کد زیر نیاز داریم. برای اعتبارسنجی قسمت فرم متن ، به یک ویجت به نام Form نیاز داریم که باید یک key برای آن تعریف کنیم.
final _formKey = new GlobalKey<FormState>(); // outside the build() method
...@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Color.fromRGBO(36, 43, 47, 1),
padding: const EdgeInsets.symmetric(horizontal: 43.0),
child: Form(
key: _formKey,
child: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFirstName(),
_buildLastName(),
_buildEmail(),
_buildPassword(),
_buildConfirmPassword(),
_buildSignUpButton(context)
],
),
),
),
));
}
اول یک decoration برای هر یک از tetxfieldها درست کنیم
InputDecoration _buildInputDecoration(String hint, String iconPath) {
return InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(252, 252, 252, 1))),
hintText: hint,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(151, 151, 151, 1))),
hintStyle: TextStyle(color: Color.fromRGBO(252, 252, 252, 1)),
icon: iconPath != '' ? Image.asset(iconPath) : null,
errorStyle: TextStyle(color: Color.fromRGBO(248, 218, 87, 1)),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(248, 218, 87, 1))),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color.fromRGBO(248, 218, 87, 1))));
}
و در ادامه هر کدام از ویجت های موجد در form را جداگانه تعریف می کنیم.
_buildFirstName()
Widget _buildFirstName() {
return TextFormField(
validator: (value) =>
value.isEmpty ? "First name cannot be empty" : null,
style: TextStyle(
color: Color.fromRGBO(252, 252, 252, 1), fontFamily: 'RadikalLight'),
decoration:
_buildInputDecoration("First name", 'assets/ic_worker.png'),
);
}
_buildLastName()
Widget _buildLastName() {
return Container(
margin: const EdgeInsets.only(left: 40),
child: TextFormField(
validator: (value) =>
value.isEmpty ? "Last name cannot be empty" : null,
style: TextStyle(
color: Color.fromRGBO(252, 252, 252, 1), fontFamily: 'RadikalLight'),
decoration: _buildInputDecoration("Last name", ''),
));
}
_buildEmail()
Widget _buildEmail() {
return TextFormField(
validator: (value) => !isEmail(value) ? "Sorry, we do not recognize this email address" : null,
style: TextStyle(
color: Color.fromRGBO(252, 252, 252, 1), fontFamily: 'RadikalLight'),
decoration: _buildInputDecoration("Email", 'assets/ic_email.png'),
);
}
_buildPassword()
final _passwordController = TextEditingController(); //this line is outside the build() method
...Widget _buildPassword() {
return TextFormField(
obscureText: true,
controller: _passwordController,
validator: (value) =>
value.length <= 6 ? "Password must be 6 or more characters in length" : null,
style: TextStyle(
color: Color.fromRGBO(252, 252, 252, 1), fontFamily: 'RadikalLight'),
decoration:
_buildInputDecoration("Password", 'assets/ic_password.png'),
);
}bool isEmail(String value) {
String regex =
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regExp = new RegExp(regex);
return value.isNotEmpty && regExp.hasMatch(value);
}
_buildConfirmPassword()
Widget _buildConfirmPassword() {
return Container(
margin: const EdgeInsets.only(left: 40),
child: TextFormField(
obscureText: true,
validator: (value) => value.isEmpty ||
(value.isNotEmpty && value != _passwordController.text)
? "Must match the previous entry"
: null,
style: TextStyle(
color: Color.fromRGBO(252, 252, 252, 1), fontFamily: 'RadikalLight'),
decoration: _buildInputDecoration("Confirm password", ''),
));
}
_buildSignUpButton().
Widget _buildSignUpButton(BuildContext context) {
return Container(
margin: const EdgeInsets.only(top: 43.0),
width: MediaQuery.of(context).size.width * 0.62,
child: RaisedButton(
child: const Text(
"Sign Up",
style: TextStyle(
color: Color.fromRGBO(40, 48, 52, 1),
fontFamily: 'RadikalMedium',
fontSize: 14),
),
color: Colors.white,
elevation: 4.0,
onPressed: () {
_validateAndSubmit();
},
),
);
}
خب دوستان کد رو روی صفحه کوچک تست کنید.
مشکل زمانی هست که کیبورد فعال شود. مانند شکل بالا!!!
یک راه حل سریع این است که ویجت های داخل Scaffold را مسدود کنید تا در زمان باز شدن صفحه کلید تغییر اندازه دهند اما از این طریق برخی ویجت ها توسط صفحه کلید مبهم می شوند. ما می توانیم این کار را با استفاده از ویژگی resizeToAvoidBottomInset در ویجت Scaffold انجام دهیم. روش ساخت به شرح زیر است:
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false, //new line
body: Container(
color: Color.fromRGBO(36, 43, 47, 1),
padding: const EdgeInsets.symmetric(horizontal: 43.0),
child: Form(
key: _formKey,
child: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFirstName(),
_buildLastName(),
_buildEmail(),
_buildPassword(),
_buildConfirmPassword(),
_buildSignUpButton(context)
],
),
),
),
));
}
راه حل دیگر این است که ویجت Column را در یک ویجت قابل پیمایش قرار دهید. ویجت قابل پیمایش ساخته شده توسط Flutter که به خوبی کار می کند SingleChildScrollView است. این بهترین راه حل برای جلوگیری از خطای "Bottom overflough" هنگام باز شدن صفحه کلید است.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Color.fromRGBO(36, 43, 47, 1),
padding: const EdgeInsets.symmetric(horizontal: 43.0),
child: Form(
key: _formKey,
child: Container(
alignment: Alignment.center,
child: SingleChildScrollView( // new line
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFirstName(),
_buildLastName(),
_buildEmail(),
_buildPassword(),
_buildConfirmPassword(),
_buildSignUpButton(context)
],
),
),
),
),
));
}
امیدوارم که این مقاله به شما کمک کند که درک بهتری داشته باشین که چرا صفحه کلید باعث ایجاد خطای "Bottom overflough" می شود ، و همچنین چگونه آن را برطرف کنید.
با ما همراه باشید ، مقالات بیشتری درباره Flutter در راه است!
ممنون از خواندن!
مطلبی دیگر از این انتشارات
آموزش فلاتر ( Flutter ) - تبدیل Json
مطلبی دیگر از این انتشارات
بررسی pubspec.yaml در فلاتر
مطلبی دیگر از این انتشارات
راه اندازی deep link در فلاتر