طراحی و کدنویسی فرم در فلاتر – راهنمای کاربردی


در این مقاله با شیوه به کارگیری مؤثر فرم در فلاتر آشنا خواهیم شد. در این راهنما موضوعات زیادی مانند اعتبارسنجی، ذخیرهسازی، جابجایی کرسر به فیلدهای دیگر و ارسال فرم با زدن return روی کیبورد موبایل مطرح میشوند. در انتها شما میتوانید یک صفحه لاگین کامل را بسازید. با ما همراه باشید تا با روش کار کردن با فرمها در فلاتر آشنا شوید.
گام اول: ساخت لیآوت
یک پروژه جدید فلاتر بسازید.
سپس کد زیر را برای شروع کار در آن قرار دهید:
1import 'package:flutter/material.dart';
2
3main() {
4 runApp(MyApp());
5}
6
7class MyApp extends StatelessWidget {
8 @override
9 Widget build(BuildContext context) {
10 return MaterialApp(
11 title: 'Form Demo',
12 home: FormDemo(),
13 );
14 }
15}
16class FormDemo extends StatefulWidget {
17 @override
18 State<StatefulWidget> createState() {
19 return _FormDemoState();
20 }
21}
22
23class _FormDemoState extends State<FormDemo> {
24 @override
25 Widget build(BuildContext context) {
26 return Scaffold(
27 appBar: AppBar(
28 title: Text('Form Demo'),
29 ),
30 body: _buildForm(),
31 );
32 }
33}
این یک اپلیکیشن ساده با یک AppBar و یک Form است. فعلاً بخش مهم برای ما متد ()buildForm_ است.
این فرم قرار است حاوی یک Column همراستا با مرکز صفحه و دو TextFormField و یک RaisedButton باشد. توجه داشته باشید که فیلدهای متنی ما باید از نوع From باشند: TextFormField و نه TextField. این قرار است مهم باشد، زیرا میخواهیم از Form widget استفاده کنیم:
1Widget _buildForm() {
2 return Column(
3 mainAxisAlignment: MainAxisAlignment.center,
4 children: <Widget>[
5 _buildEmailField(),
6 _buildPasswordField(),
7 _buildSubmitButton(),
8 ],
9 );
10}
11
12Widget _buildEmailField() {
13 return TextFormField(
14 decoration: InputDecoration(labelText: 'Email'),
15 );
16}
17
18Widget _buildPasswordField() {
19 return TextFormField(
20 decoration: InputDecoration(labelText: 'Password'),
21 );
22}
23
24Widget _buildSubmitButton() {
25 return RaisedButton(
26 onPressed: () {},
27 child: Text('SEND'),
28 );
29}
گام دوم: ساخت فرم و افزودن کلید
سؤالی که اینجا مطرح میشود باید به فلاتر اعلام کنیم که این دو فیلد و دکمه یک فرم هستند که باید دادهها را ذخیره کرده و اعتبارسنجی کنند. قبل از هر چیز باید ویجت Column را درون یک Form قرار دهیم:
1Widget _buildForm() {
2 return Form(
3 child: Column(
4 mainAxisAlignment: MainAxisAlignment.center,
5 children: <Widget>[
6 _buildEmailField(),
7 _buildPasswordField(),
8 _buildSubmitButton(),
9 ],
10 ));
11}
تصور کنید بیش از یک فرم روی صفحه داشته باشید، در این صورت برای ردگیری آنها باید از مشخصه key در Form استفاده کنیم. کلید خود را ایجاد کرده و آن را به فرم اضافه کنید تا یکتا شود:
1class _FormDemoState extends State<FormDemo> {
2 final _formKey = GlobalKey<FormState>();
3
4 Widget _buildForm() {
5 return Form(
6 key: _formKey,
7 ...);
8 }
9}
گام سوم: اعتبارسنجی
زمانی که TextFormField دارید، میتوانید پیش از ارسال آن را اعتبارسنجی کنید. فرض کنید میخواهیم بررسی کنیم آیا فیلد خالی است یا یک ایمیل معتبر در آن وجود دارد.
مشخصه validator این وظیفه را بر عهده دارد. کافی است قاعده خود را بگویید و در مواردی که خطایی وجود دارد یک string بازگشت دهید.
1Widget _buildEmailField() {
2 return TextFormField(
3 decoration: InputDecoration(labelText: 'Email'),
4 validator: (String value) {
5 if (!RegExp(
6 r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
7 .hasMatch(value)) {
8 return 'This is not a valid email';
9 }
10 },
11 );
12}
13
14Widget _buildPasswordField() {
15 return TextFormField(
16 decoration: InputDecoration(labelText: 'Password'),
17 validator: (String value) {
18 if (value.isEmpty) {
19 return 'Preencha a senha';
20 }
21 },
22 );
23}
در فیلد رمز عبور مقدار درون فیلد را بررسی میکنیم تا خالی نباشد. در صورتی که این فیلد خالی باشد، یک پیام خطا زیر TextFormField نمایش میدهیم. فیلد ایمیل هم همین کار را انجام میدهد، اما از RegExp برای معتبر بودن ایمیل استفاده میکنیم.
اکنون زمانی که فرم را ذخیره میکنید باید معتبر بودن آن را بررسی کنید. در حالتی که فرم معتبر باشد میتوانید دادهها را ذخیره کنید در این صورت پیام خطایی نمایش مییابد.
1Widget _buildSubmitButton() {
2 return RaisedButton(
3 onPressed: () {
4 _submitForm();
5 },
6 ...
7 );
8}
9
10void _submitForm() {
11 print('Submitting form');
12 if (_formKey.currentState.validate()) {
13 print('Form was validated');
14 }
15}
پروژه را اجرا کرده و لاگ را بررسی کنید تا اجرای عملی آن را ملاحظه کنید.
گام چهارم: ذخیرهسازی
احتمالاً میخواهید دادههای فرم را ذخیره کنید تا کاری با آن انجام دهید. در این گام همان قواعد ذخیرهسازی را برای فیلدها ایجاد میکنیم و سپس زمانی که متد save() را فراخوانی کنیم، آن قواعد اجرا میشوند. ما قصد داریم ایمیل و رمز عبور را در یک Map ذخیره کنیم.
1class _FormDemoState extends State<FormDemo> {
2 final Map<String, dynamic> formData = {'email': null, 'password': null};
3
4 Widget _buildEmailField() {
5 return TextFormField(
6 ...
7 onSaved: (String value) {
8 formData['email'] = value;
9 },
10 );
11 }
12
13 Widget _buildPasswordField() {
14 return TextFormField(
15 ...
16 onSaved: (String value) {
17 formData['password'] = value;
18 },
19 );
20 }
21 void _submitForm() {
22 print('Submitting form');
23 if (_formKey.currentState.validate()) {
24 _formKey.currentState.save(); //onSaved is called!
25 print(formData);
26 }
27 }
28}
زمانی که ()formKey.currentState.save_ را فراخوانی میکنید در ادامه onSaved از فرمها اجرا خواهد شد. پس از آن دادههای نوشته شده روی لاگها پرینت خواهند شد. آن را خودتان اجرا و بررسی کنید.
گام پنجم: جابجا کردن نشانگر ماوس
یک قابلیت جالب فرمها توانایی نوشتن چیزی در کیبورد است و سپس میتوان با زدن کلید Next به فیلد بعدی رفت. در نهایت زمانی که کلید return زده شود فرم ارسال میشود. این وضعیت مناسبی است، زیرا کاربر میتواند بدون نیاز به پنهان کردن یا نمایان کردن کیبورد به بخشهای مختلف اپلیکیشن برد و در هر حالی روی صفحه اسکرول کند. شاید متوجه شده باشید که فرم هنوز این قابلیت را ندارد. اما جای نگرانی نیست، ما آن را طراحی میکنیم. وقایعی که برای کاربر اتفاق میافتد به صورت زیر هستند:
- ایمیل را وارد کرده و کلید Next روی کیبورد را بزنید.
- فوکوس به طور خودکار به فیلد password میرود.
- فیلد password را پر کنید و کلید Return کیبورد را بزنید.
- فرم به صورت خودکار ارسال میشود.
ما از onFieldSubmitted استفاده خواهیم کرد. این متد هر زمان که کاربر فیلد را ارسال میکند فراخوانی خواهد شد.
1Widget _buildEmailField() {
2 return TextFormField(
3 ...
4 textInputAction: TextInputAction.next,
5 onFieldSubmitted: (v) {
6 FocusScope.of(context).requestFocus(focusPassword);
7 },
8 );
9}
textInputAction مسئول نمایش دکمه Next به جای دکمه Return است. خط بعدی کد فوکوس را به password میبرد. ما باید اعلام کنیم که focusPassword ارجاعی به فیلد رمز عبور ایجاد میکند.
1Widget _buildPasswordField() {
2 return TextFormField(
3 ...
4 focusNode: focusPassword,
5 onFieldSubmitted: (v) {
6 _submitForm();
7 },
8 );
9}
خط اول نشان میدهد که focusPassword مسئول شناسایی فیلد رمز عبور است، در حالی که وقتی کاربر روی کلید Return میزند، خط دوم فرم را با فراخوانی ()submitForm_ ارسال میکند. focusPassword تنها یک وهله سراسری از FocusNode است.
1class _FormDemoState extends State<FormDemo> {
2 final focusPassword = FocusNode();
3 ...
4}
پروژه را اجرا کرده و بررسی کنید که آیا میتوانید فرم را تنها با زدن کلید بازگشت ارسال کنید. برای مشاهده سورس کد کامل این پروژه به این ریپوی گیتهاب (+) بروید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای پروژهمحور برنامهنویسی اندروید
- مجموعه آموزشهای برنامهنویسی
- مفاهیم مقدماتی فلاتر (Flutter) — به زبان ساده
- گوگل فلاتر (Flutter) از صفر تا صد — ساخت اپلیکیشن به کمک ویجت
- ناوبری برگهای در فلاتر (Flutter) — به زبان ساده
==