17 β Formalar va foydalanuvchi kiritmasi¶
β¬ οΈ Oldingi: 16 β StatefulWidget va setState Β· π README Β· Keyingi: 18 β Ro'yxatlar va scroll β‘οΈ
Bu bobda: deyarli har bir jiddiy ilovada foydalanuvchidan ma'lumot olish kerak bo'ladi β ro'yxatdan o'tish, kirish, profil tahrirlash, qidiruv. Mana shu bobda biz formalarni o'rganamiz: bir nechta kiritma maydonini birga boshqarish, ularni bir vaqtda tekshirish (validatsiya) va bir vaqtda saqlash. Siz
Formva uni boshqaradiganGlobalKey<FormState>nima ekanini;TextEditingControllerorqali maydon matnini o'qish/o'rnatishni;TextFormFieldningvalidator:vaonSaved:callbacklarini;formKey.currentState!.validate()va.save()qanday ishlashini; eng yaxshi UX uchunautovalidateMode: AutovalidateMode.onUserInteractionni; fokusni boshqarishni (FocusNode, "Keyingi" tugmasi); klaviatura turini, parol yashirishni, faqat raqam kiritishni; hamda forma ichida ochiluvchi ro'yxat, sana tanlash va checkboxni o'rganasiz. Oxirida birgalikda to'liq, tekshiriladigan ro'yxatdan o'tish formasini noldan quramiz.
Nega "forma" kerak? Bitta maydondan ko'p maydonga¶
Tasavvur qiling, sizda ro'yxatdan o'tish ekrani bor: ism, email, parol va parolni tasdiqlash. To'rtta maydon. Foydalanuvchi "Ro'yxatdan o'tish" tugmasini bosganda siz hammasini birdan tekshirishingiz kerak: ism bo'sh emasmi, email to'g'rimi, parol yetarli uzunmi, ikki parol bir xilmi?
Har bir maydonni alohida, qo'lda tekshirsangiz β kod tez orada chalkash bo'lib ketadi. Aynan shu yerda Form yordamga keladi. Form β bu bir nechta kiritma maydonini bitta guruh qilib birlashtiradigan widget. U sizga ikki kuchli imkon beradi:
- Hammasini bir vaqtda tekshirish β bitta buyruq bilan barcha maydonlarning validatorlarini ishga tushirasiz.
- Hammasini bir vaqtda saqlash β bitta buyruq bilan barcha maydonlardan qiymatni yig'ib olasiz.
Form ko'rinmaydi β u faqat ichidagi maydonlarni boshqaruvchi rol o'ynaydi (xuddi 10-bobdagi Center kabi layout emas, balki "dirijyor"). Uni boshqarish uchun esa sizga unga "dasta" kerak β bu GlobalKey<FormState>.
final _formKey = GlobalKey<FormState>();
// ...build ichida:
Form(
key: _formKey,
child: Column(
children: [
TextFormField(/* ... */),
TextFormField(/* ... */),
FilledButton(
onPressed: () {
// _formKey orqali butun formaga buyruq beramiz
if (_formKey.currentState!.validate()) {
// hamma maydon to'g'ri β davom etamiz
}
},
child: const Text('Saqlash'),
),
],
),
)
GlobalKey<FormState> nima qiladi? U Form widgetining holatiga (FormState) tashqaridan murojaat qilish kalitidir. _formKey.currentState orqali siz "men shu formaga gaplashayapman" deysiz va unga validate(), save(), reset() kabi buyruqlarni yuborasiz. Kalitsiz formani boshqarib bo'lmaydi.
π‘
GlobalKeyβ kamyob mehmon. 10-bobdagi oddiykey:(super.key) widgetlarni daraxtda ajratish uchun edi.GlobalKeyesa kuchliroq: u orqali widgetning holatiga murojaat qilasiz. Uni faqat shunday zarur joylarda β masalan forma boshqarishda β ishlating, har bir widgetga emas.
TextEditingController β maydon matnini boshqarish¶
Forma maydonlariga o'tishdan oldin, kiritmani o'qishning eng to'g'ridan-to'g'ri usuli bilan tanishaylik β TextEditingController.
Controller (boshqaruvchi) β bu matn maydoniga ulanadigan kichik obyekt. U orqali siz:
- maydondagi matnni istalgan paytda o'qiysiz (
controller.text); - matnni dasturiy yo'l bilan o'rnatasiz (
controller.text = 'salom'); - foydalanuvchi yozganini kuzatasiz (listener qo'shib).
Controllerni qayerda yaratamiz? 16-bobdan eslang: o'zgaradigan, "uzoq yashaydigan" obyektlar StatefulWidgetning State klassida saqlanadi. Controller ham xuddi shunday β uni State ichida maydon sifatida yaratamiz va dispose() metodida tozalaymiz:
class _NomFormState extends State<NomForm> {
final _ismController = TextEditingController();
@override
void dispose() {
_ismController.dispose(); // MAJBURIY: xotirani bo'shatadi
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _ismController,
decoration: const InputDecoration(labelText: 'Ism'),
);
}
}
Endi istalgan paytda β masalan tugma bosilganda β matnni o'qiysiz:
β οΈ Eng ko'p uchraydigan xato: controllerni
dispose()qilishni unutish. 16-bobda ko'rganimizdek,dispose()βStateo'lganda chaqiriladigan tozalash metodi. Controllerdisposeqilinmasa, u xotirada qolib ketadi (xotira oqishi β memory leak). Qoida: har bir yaratgan controllernidispose()qiling.
Kiritmani olishning ikki yo'li¶
Maydondan qiymat olishning ikki asosiy usuli bor, va ularni adashtirmaslik muhim:
TextEditingControllerorqali β matnni jonli, istalgan paytda o'qiysiz (controller.text). Matnni o'rnatish yoki yozilayotganini kuzatish kerak bo'lsa, shu yo'l.onChanged/onSavedcallback orqali β Flutter qiymatni sizga uzatadi.onChangedhar bir harf yozilganda chaqiriladi;onSavedesa formasave()qilinganda.
Qaysi birini tanlash kerak? Agar sizga faqat yuborish vaqtida qiymat kerak bo'lsa β onSaved yetarli, controller yaratish/dispose qilish shart emas. Agar matnni jonli o'qish/o'rnatish kerak bo'lsa (masalan "parolni tasdiqlash" maydonini asosiy parol bilan solishtirish) β controller ishlating. Ikkalasini birga ham qo'llash mumkin.
TextFormField β formaga moslashgan matn maydoni¶
10-16 boblarda TextField bilan tanishdingiz. TextFormField β bu uning "forma-aware" (formani biluvchi) ukasi. Tashqi ko'rinishi bir xil, lekin u Form bilan ishlashga moslashgan: validator: va onSaved: callbacklarini qabul qiladi va Form uni avtomatik "ko'radi".
Eng muhim qismi β validator:. Bu funksiya maydondagi qiymatni oladi va:
- agar qiymat to'g'ri bo'lsa β
nullqaytaradi (xato yo'q); - agar qiymat xato bo'lsa β xato matnini (
String) qaytaradi; bu matn maydon ostida qizil rangda avtomatik ko'rsatiladi.
TextFormField(
decoration: const InputDecoration(
labelText: 'Ism',
prefixIcon: Icon(Icons.person),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Ism majburiy'; // xato matni
}
return null; // hammasi joyida
},
)
E'tibor bering: value β String? (null bo'lishi mumkin), shuning uchun value == null || value.isEmpty deb tekshiramiz. null qaytarish = maydon to'g'ri. Buni esda tuting β ko'pchilik adashadigan joy aynan shu.
decoration: β maydon ko'rinishi va xatosi¶
decoration: InputDecoration(...) β maydonning ko'rinishini sozlaydi: yorliq (labelText), ko'rsatma matn (hintText), ikonlar (prefixIcon, suffixIcon), chegara (border). Eng yaxshi yangilik: validatordan qaytgan xato matni decoration orqali avtomatik maydon ostida ko'rsatiladi β siz buni qo'lda qilmaysiz.
TextFormField(
decoration: const InputDecoration(
labelText: 'Email',
hintText: 'siz@misol.com',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
// ...
)
Validatsiya oqimi β validate() va save()¶
Endi eng muhim qismga keldik: tugma bosilganda nima sodir bo'ladi?
Oqim shunday:
- Foydalanuvchi "Saqlash" tugmasini bosadi.
- Siz
_formKey.currentState!.validate()ni chaqirasiz. Bu buyruq formadagi har birTextFormFieldningvalidatorini ishga soladi. - Agar barcha validatorlar
nullqaytarsa βvalidate()trueqaytaradi (forma to'g'ri). - Agar birortasi xato matn qaytarsa β
validate()falseqaytaradi va o'sha maydon(lar) ostida xato matni ko'rsatiladi.
if (_formKey.currentState!.validate()) {
// hamma maydon to'g'ri
_formKey.currentState!.save(); // har bir onSaved'ni chaqiradi
// ...endi yig'ilgan qiymatlar bilan ishlash mumkin
}
save() alohida buyruq: u har bir maydonning onSaved: callbackini chaqiradi, ya'ni qiymatlarni "yig'ib oladi". Odatda avval validate() bilan tekshirib, faqat to'g'ri bo'lsagina save() chaqiramiz.
autovalidateMode β qachon tekshirish kerak?¶
Yuqoridagi usulda xato faqat tugma bosilganda ko'rinadi. Lekin yaxshiroq UX bor: foydalanuvchi yozayotganda darhol fikr-mulohaza berish. Buni autovalidateMode boshqaradi:
AutovalidateMode.onUserInteraction β eng yaxshi tanlov. U shunday ishlaydi: forma dastlab xato ko'rsatmaydi (foydalanuvchi hali hech narsa kiritmagan bo'lsa, uni qizil bilan "qo'rqitish" yomon). Lekin foydalanuvchi birinchi marta maydon bilan ishlagandan keyin, validatsiya har bir o'zgarishda avtomatik ishlaydi β xato bo'lsa darhol ko'rsatadi, tuzatilsa darhol yo'qoladi.
β οΈ Boshidanoq tekshirmang.
AutovalidateMode.alwaysformani ochilishidanoq barcha bo'sh maydonlarni qizil qiladi β foydalanuvchi hali yozishni boshlamasdan turib. Bu noqulay. Deyarli har doimonUserInteractionishlating.
Fokusni boshqarish β maydondan maydonga o'tish¶
Yaxshi formada foydalanuvchi klaviaturadagi "Keyingi" tugmasi bilan bir maydondan ikkinchisiga sakrab o'tadi. Buni FocusNode boshqaradi β bu har bir maydonning "fokusi"ni (ya'ni hozir qaysi maydon tahrirlanayotganini) ifodalovchi obyekt.
Asosiy g'oya:
textInputAction: TextInputAction.nextβ klaviaturadagi tugmani "Keyingi" qiladi (oxirgi maydondaTextInputAction.done).onFieldSubmitted:β foydalanuvchi shu tugmani bosganda chaqiriladi; bu yerda fokusni keyingi maydonga o'tkazamiz.FocusScope.of(context).requestFocus(node)β fokusni berilganFocusNodega uzatadi.FocusScope.of(context).unfocus()β fokusni olib tashlaydi (klaviaturani yopadi); odatda yuborish (submit) paytida ishlatamiz.
final _emailFocus = FocusNode(); // State ichida; dispose() shart!
// Ism maydonida:
TextFormField(
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_emailFocus); // emailga o'tadi
},
decoration: const InputDecoration(labelText: 'Ism'),
),
// Email maydonida:
TextFormField(
focusNode: _emailFocus,
textInputAction: TextInputAction.done,
decoration: const InputDecoration(labelText: 'Email'),
),
β οΈ
FocusNodehamdispose()qilinishi kerak β xuddi controller kabi.Stateichida yaratgan har birFocusNodenidispose()metodida tozalang.
Klaviatura va kiritmani sozlash¶
Yaxshi forma to'g'ri klaviaturani ko'rsatadi va noto'g'ri kiritishni oldini oladi:
keyboardType:β qaysi klaviatura chiqishini belgilaydi:TextInputType.emailAddress(email uchun,@tugmasi bilan),TextInputType.number(raqamlar),TextInputType.phone(telefon).obscureText: trueβ parol maydonlari uchun: yozilgan belgilar nuqtacha bilan yashiriladi.inputFormatters:β kiritishni filtrlaydi. MasalanFilteringTextInputFormatter.digitsOnlyfaqat raqam kiritishga ruxsat beradi (harflarni qabul qilmaydi).maxLength:β maksimal belgilar soni (va pastda hisoblagich ko'rsatadi).
// Faqat raqam qabul qiluvchi telefon maydoni:
TextFormField(
keyboardType: TextInputType.phone,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
maxLength: 9,
decoration: const InputDecoration(labelText: 'Telefon'),
)
π‘
inputFormattersishlatish uchunimport 'package:flutter/services.dart';kerak bo'ladi βFilteringTextInputFormattershu kutubxonada.
Parolni yashirish/ko'rsatish tugmasi¶
Parol maydonlarida ko'p uchraydigan naqsh: ko'z ikonkasini bosib parolni vaqtincha ko'rsatish. Buni obscureTextni boshqaradigan holat (16-bobdagi setState) bilan qilamiz:
bool _parolYashirin = true; // State ichida
TextFormField(
obscureText: _parolYashirin,
decoration: InputDecoration(
labelText: 'Parol',
suffixIcon: IconButton(
icon: Icon(_parolYashirin ? Icons.visibility : Icons.visibility_off),
onPressed: () {
setState(() => _parolYashirin = !_parolYashirin);
},
),
),
)
Formadagi boshqa kiritmalar¶
Forma faqat matn maydonidan iborat emas. Quyidagilar ham Form ichida ishlaydi:
DropdownButtonFormFieldβ ochiluvchi ro'yxat (masalan shahar tanlash). U hamvalidator:qabul qiladi.- Sana tanlash β
showDatePicker(...)β kalendar oynasini ochadi vaFuture<DateTime?>qaytaradi (9-bobdagiFutureesingizdami). - Checkbox β
CheckboxListTilebilan, masalan "Shartlarga roziman".
// Ochiluvchi ro'yxat:
DropdownButtonFormField<String>(
decoration: const InputDecoration(labelText: 'Shahar'),
items: const [
DropdownMenuItem(value: 'toshkent', child: Text('Toshkent')),
DropdownMenuItem(value: 'samarqand', child: Text('Samarqand')),
],
onChanged: (value) { /* tanlandi */ },
validator: (value) => value == null ? 'Shahar tanlang' : null,
),
// Sana tanlash:
final sana = await showDatePicker(
context: context,
firstDate: DateTime(1950),
lastDate: DateTime.now(),
);
if (sana != null) {
// foydalanuvchi sana tanladi
}
Birgalikda: to'liq ro'yxatdan o'tish formasi¶
Endi hamma narsani birlashtiramiz. Quyidagi forma: ism, email, parol (yashirish tugmasi bilan) va parolni tasdiqlash. Tugma bosilganda tekshiradi va muvaffaqiyatli bo'lsa SnackBar ko'rsatadi. Bu β to'liq, kompilyatsiya bo'ladigan kod:
import 'package:flutter/material.dart';
class RoyxatdanOtish extends StatefulWidget {
const RoyxatdanOtish({super.key});
@override
State<RoyxatdanOtish> createState() => _RoyxatdanOtishState();
}
class _RoyxatdanOtishState extends State<RoyxatdanOtish> {
final _formKey = GlobalKey<FormState>();
final _parolController = TextEditingController();
bool _parolYashirin = true;
@override
void dispose() {
_parolController.dispose(); // MAJBURIY
super.dispose();
}
void _yubor() {
// fokusni olib, klaviaturani yopamiz
FocusScope.of(context).unfocus();
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Ro\'yxatdan muvaffaqiyatli o\'tdingiz!')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Ro\'yxatdan o\'tish')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
TextFormField(
textInputAction: TextInputAction.next,
decoration: const InputDecoration(
labelText: 'Ism',
prefixIcon: Icon(Icons.person),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'Ism majburiy';
}
return null;
},
),
const SizedBox(height: 12),
TextFormField(
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
decoration: const InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email majburiy';
}
if (!value.contains('@')) {
return 'Email noto\'g\'ri';
}
return null;
},
),
const SizedBox(height: 12),
TextFormField(
controller: _parolController,
obscureText: _parolYashirin,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
labelText: 'Parol',
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
_parolYashirin ? Icons.visibility : Icons.visibility_off,
),
onPressed: () {
setState(() => _parolYashirin = !_parolYashirin);
},
),
),
validator: (value) {
if (value == null || value.length < 6) {
return 'Parol kamida 6 belgi bo\'lsin';
}
return null;
},
),
const SizedBox(height: 12),
TextFormField(
obscureText: true,
textInputAction: TextInputAction.done,
decoration: const InputDecoration(
labelText: 'Parolni tasdiqlang',
prefixIcon: Icon(Icons.lock_outline),
),
onFieldSubmitted: (_) => _yubor(),
validator: (value) {
if (value != _parolController.text) {
return 'Parollar mos kelmadi';
}
return null;
},
),
const SizedBox(height: 24),
FilledButton(
onPressed: _yubor,
child: const Text('Ro\'yxatdan o\'tish'),
),
],
),
),
),
);
}
}
Bu kodda o'rgangan hamma narsa bir joyda:
_formKeyβGlobalKey<FormState>orqali formani boshqaramiz._parolControllerβ parolni jonli o'qiymiz, chunki "tasdiqlash" maydonining validatori uni asosiy parol bilan solishtiradi (value != _parolController.text). Bu β controller kerak bo'ladigan klassik holat. Va udispose()qilinadi.autovalidateMode: onUserInteractionβ foydalanuvchi yozgani sari xatolar jonli ko'rsatiladi._parolYashirinholati vaIconButtonβ parolni ko'rsatish/yashirish tugmasi.textInputAction.next/.done+ oxirgi maydondaonFieldSubmitted: (_) => _yubor()β klaviatura tugmasidan to'g'ridan-to'g'ri yuborish._yubor()β avvalunfocus()(klaviaturani yopadi), keyinvalidate(), so'ngsave(), oxiridaSnackBar.
Bu formani ishga tushiring, noto'g'ri email kiriting (@ belgisiz) β maydon ostida xato darhol ko'rinadi. Parollarni har xil yozing β "Parollar mos kelmadi" chiqadi. Hammasini to'g'ri to'ldirib tugmani bosing β pastda yashil SnackBar ko'rinadi.
Tez-tez uchraydigan xatolar¶
- Controller/FocusNode'ni
dispose()qilmaslik. Har bir yaratgan controller vaFocusNodenidispose()da tozalang β aks holda xotira oqishi bo'ladi (16-bobdagidisposeqoidasi). nullcurrentStatedavalidate()chaqirish._formKey.currentState!β agarFormhali daraxtda qurilmagan bo'lsa (yoki kalitni boshqa formaga ulagan bo'lsangiz)currentStatenullbo'ladi va!xatoga olib keladi. Kalit aynan o'shaFormga ulanganiga ishonch hosil qiling.- Boshidanoq tekshirish.
AutovalidateMode.alwaysformani ochilishidanoq qizilga bo'yaydi.onUserInteractionishlating. validatorda qaytarish chalkashligi. Esda tuting:null= to'g'ri,String= xato. Teskarisini yozib qo'ymang.TextFieldvaTextFormFieldni adashtirish.Formichida validatsiya kerak bo'lsa βTextFormFieldishlating (TextFielddavalidator:yo'q).
Keyingi qadam¶
Endi siz foydalanuvchidan ma'lumot olishni β formalar qurish, tekshirish va saqlashni β bilasiz. Bu deyarli har bir ilovaning markaziy qismi. Keyingi 18-bobda ro'yxatlar va scrollni o'rganamiz: ListView bilan uzun ro'yxatlarni samarali ko'rsatish, ListView.builder bilan minglab elementni "kerak bo'lganda" qurish va scroll qilinadigan kontentni boshqarish. Forma bilan yig'ilgan ma'lumotni ko'pincha aynan ro'yxat sifatida ko'rsatamiz.
Mashqlar¶
Oson¶
- O'z so'zlaringiz bilan tushuntiring:
Formwidget nima uchun kerak vaGlobalKey<FormState>unda qanday rol o'ynaydi? TextFormFieldningvalidator:callbacki to'g'ri qiymat uchun nimani, xato qiymat uchun nimani qaytaradi?validate()vasave()farqi nimada? Odatda qaysi biri avval chaqiriladi?AutovalidateMode.onUserInteractionvaAutovalidateMode.alwaysorasidagi farq nima? Nega ko'pincha birinchisi yaxshiroq?- Nega har bir
TextEditingControllernidispose()qilish kerak? Buni qaysi metodda qilamiz?
O'rta¶
- Bitta
TextFormFieldyozing: u "Yosh" maydoni bo'lsin, faqat raqam qabul qilsin (inputFormatters), tegishli klaviatura chiqsin (keyboardType) va bo'sh bo'lsa "Yoshni kiriting" xatosini bersin. - Parolni ko'rsatish/yashirish tugmasini (
suffixIcon+IconButton) qanday qilasiz?obscureTextni nima boshqaradi vasetStatebu yerda nega kerak? - Email validatorini yozing: maydon bo'sh bo'lsa "Email majburiy",
@belgisi bo'lmasa "Email noto'g'ri", aks holdanullqaytarsin.
Qiyin¶
- "Parolni tasdiqlash" maydonining validatorini yozish uchun nega
onSavedemas, balkiTextEditingControllerishlatish qulayroq? Tushuntiring va kod parchasini ko'rsating. - Quyidagi kodda nima xato? Tuzating va sababini ayting:
Yechimlar
1. Form β bir nechta kiritma maydonini bitta guruh qilib birlashtiradigan widget. U ichidagi barcha maydonlarni bir vaqtda tekshirish (validate()) va bir vaqtda saqlash (save()) imkonini beradi. GlobalKey<FormState> esa shu Formning holatiga tashqaridan murojaat qilish "dasta"sidir β _formKey.currentState orqali formaga validate(), save(), reset() buyruqlarini yuborasiz. Kalitsiz formani boshqarib bo'lmaydi.
2. Qiymat to'g'ri bo'lsa β validator null qaytaradi (xato yo'q). Qiymat xato bo'lsa β xato matnini (String) qaytaradi; bu matn maydon ostida avtomatik ko'rsatiladi.
3. validate() β barcha maydonlarning validatorini ishga soladi va hammasi to'g'ri bo'lsa true, biror xato bo'lsa false qaytaradi (xatolarni ekranda ko'rsatadi). save() β har bir maydonning onSaved callbackini chaqirib qiymatlarni yig'adi. Odatda avval validate() chaqiriladi, faqat u true qaytarsagina save() chaqiriladi.
4. onUserInteraction β forma dastlab xato ko'rsatmaydi, lekin foydalanuvchi birinchi marta maydon bilan ishlagandan keyin har bir o'zgarishda validatsiyani avtomatik ishga soladi. always β formani ochilishidanoq barcha (hatto bo'sh) maydonlarni tekshiradi va qizilga bo'yaydi. onUserInteraction yaxshiroq, chunki foydalanuvchini hali yozishni boshlamasdan turib xato bilan "qo'rqitmaydi".
5. TextEditingController xotirada joy egallaydi va State o'lganda avtomatik tozalanmaydi. dispose() qilinmasa β u xotirada qolib ketadi (xotira oqishi). Buni State klassining dispose() metodida qilamiz: _controller.dispose(); keyin super.dispose();.
6.
import 'package:flutter/services.dart'; // FilteringTextInputFormatter uchun
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: const InputDecoration(labelText: 'Yosh'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Yoshni kiriting';
}
return null;
},
)
7. Parol yashirinligini bool _parolYashirin = true; holati boshqaradi, u obscureText: _parolYashirin ga beriladi. suffixIcon ga IconButton qo'yamiz; uning onPressedida setState orqali holatni teskarisiga o'zgartiramiz. setState shuning uchun kerakki, obscureTextning yangi qiymati bilan UI qayta qurilishi kerak β aks holda ikonka va matn yashirinligi yangilanmaydi.
suffixIcon: IconButton(
icon: Icon(_parolYashirin ? Icons.visibility : Icons.visibility_off),
onPressed: () => setState(() => _parolYashirin = !_parolYashirin),
)
8.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email majburiy';
}
if (!value.contains('@')) {
return 'Email noto\'g\'ri';
}
return null;
}
9. "Parolni tasdiqlash" maydonining validatori asosiy parol qiymatini o'sha lahzada bilishi kerak (ularni solishtirish uchun). onSaved faqat save() chaqirilganda ishlaydi β ya'ni qiymat validatsiya paytida hali tayyor emas. TextEditingController esa matnni istalgan paytda beradi (controller.text), shuning uchun tasdiqlash validatorida uni to'g'ridan-to'g'ri ishlatish qulay:
final _parolController = TextEditingController(); // asosiy parol maydoniga ulanadi
// tasdiqlash maydonida:
validator: (value) {
if (value != _parolController.text) {
return 'Parollar mos kelmadi';
}
return null;
}
_parolControllerni dispose() qilishni unutmang.)
10. Xato: _formKey.currentState β bu null bo'lishi mumkin (FormState? turi), shuning uchun unga to'g'ridan-to'g'ri .validate() qo'llab bo'lmaydi β kompilyatsiya xatosi. Tuzatish: null-emasligini bildiruvchi ! qo'yamiz:
! β "bu yerda currentState null emas degan kafolat beraman" degani (6-bobdagi null safety). Form daraxtda qurilgan bo'lsa, currentState haqiqatan ham null bo'lmaydi.
β¬ οΈ Oldingi: 16 β StatefulWidget va setState Β· π README Β· Keyingi: 18 β Ro'yxatlar va scroll β‘οΈ