28 β Platforma, paketlar va moslashuv¶
β¬ οΈ Oldingi: 27 β Animatsiya Β· π README Β· Keyingi: 29 β Testing, debugging va ishlab chiqarish β‘οΈ
Bu bobda: shu paytgacha siz Flutter'ning "ichki dunyosi"da ishladingiz β widgetlar, holat, navigatsiya, animatsiya. Endi ilovangizni tashqi dunyoga ulaymiz. Avval paketlar va pub.dev ekotizimi bilan tanishamiz:
flutter pub addqanday ishlaydi,pubspec.yamldagi versiya cheklovlari (^), va yaxshi paketni qanday tanlash kerak. So'ng qurilma imkoniyatlarini paketlar orqali ishlatamiz βimage_picker(kamera/galereya),geolocator(joylashuv),url_launcher,permission_handler(ruxsatlar). Keyin platform channel g'oyasi bilan tanishamiz β paket bo'lmaganda native (Kotlin/Swift) kodga murojaat qilish. Undan keyin moslashuvchi (responsive) va adaptiv dizayn β telefon, planshet, desktop va orientatsiyaga moslashish. Oxirida xalqarolashtirish (i18n) β ilovani ikki tilda qilish β va qulaylik (accessibility) β ilovani hamma uchun ishlatsa bo'ladigan qilish. Bu bob keng, lekin har bir mavzu amaliy va loyihangizga darhol kerak bo'ladi.
Nega paketlar? G'ildirakni qaytadan ixtiro qilmang¶
Tasavvur qiling: ilovangizga foydalanuvchi suratini galereyadan tanlash imkoniyati kerak. Buni noldan yozish β kamera ruxsatlari, Android va iOS uchun alohida native kod, fayl yo'llarini boshqarish β bir necha kunlik mehnat. Ammo kimdir buni allaqachon yozib, sinab, minglab ilovalarda ishlatgan va bepul ulashgan. Siz uni bir buyruq bilan loyihangizga qo'shasiz.
Bu paket (package) β boshqalar yozgan, qayta ishlatsa bo'ladigan kod to'plami. Flutter'ning paket do'koni β pub.dev β minglab paketni saqlaydi. Bu xuddi JavaScript'dagi npm yoki Python'dagi PyPI'ga o'xshaydi: nima kerak bo'lsa, ehtimol kimdir uni yozib qo'ygan.
π‘ Nega o'zingiz yozmaysiz? Yaxshi paket yuzlab odam tomonidan sinalgan, turli qurilmalarda tekshirilgan va doimiy yangilanib turadi. Sizning bir kunda yozgan kodingiz hech qachon shu darajaga yetolmaydi. Dasturlashda "tayyor yechimni ishlatish" β dangasalik emas, donolik.
pubspec.yaml β ilovangizning pasporti¶
Har bir Flutter loyihasida pubspec.yaml nomli fayl bor. Bu β loyihangizning pasporti: nomi, versiyasi, bog'liqliklari (paketlari), shrift va rasm (asset)lari shu yerda e'lon qilinadi. Eng muhim qismi β dependencies:
name: mening_ilovam
description: Birinchi Flutter ilovam.
version: 1.0.0
environment:
sdk: ^3.10.0
dependencies:
flutter:
sdk: flutter
http: ^1.5.0 # tarmoq paketi (21-bobdan tanish)
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0 # faqat ishlab chiqishda kerak
Ikki turdagi bog'liqlik bor:
dependenciesβ ilovangiz ishlash uchun kerak bo'lgan paketlar (http,geolocator). Ular tayyor ilovaga ham qo'shiladi.dev_dependenciesβ faqat ishlab chiqish paytida kerak bo'lganlar (test paketlari, linter, kod generatorlari). Ular tayyor ilovaga kirmaydi, shuning uchun uning hajmini oshirmaydi.
β οΈ
pubspec.yamlβ YAML formatida. Bu yerda bo'shliqlar (indentatsiya) muhim: tab ishlatmang, har bosqichda 2 ta bo'shliq qo'ying. Bitta noto'g'ri bo'shliq butun faylni buzadi.
Paketni qo'shish: flutter pub add¶
Paketni qo'lda pubspec.yamlga yozish o'rniga, eng oson yo'l β terminalda buyruq berish. Loyiha papkasida:
Bu buyruq uch ishni qiladi: paketning eng so'nggi mos versiyasini topadi, uni pubspec.yamlning dependenciesiga yozadi, va yuklab oladi. Faylga shunday qator qo'shiladi:
dev_dependenciesga qo'shish uchun --dev bayrog'ini qo'shing:
Agar siz pubspec.yamlni qo'lda tahrirlasangiz (masalan, hamkasbingizning loyihasini ochib), paketlarni yuklash uchun:
flutter pub add aslida flutter pub getni o'zi chaqiradi, shuning uchun ko'pincha add yetarli. pub get β loyihani birinchi marta klonlaganingizda yoki faylni qo'lda o'zgartirganingizda kerak bo'ladi.
Versiya cheklovlari: ^ belgisi nimani anglatadi?¶
geolocator: ^14.0.0 dagi ^ (karet) belgisi muhim. U "14.0.0 va undan yuqori, lekin 15.0.0 dan past" degani. Ya'ni:
14.0.1,14.3.0,14.9.9β mumkin (kichik yangilanishlar, xatolar tuzatilishi).15.0.0β mumkin emas (katta versiya, buzuvchi o'zgarishlar bo'lishi mumkin).
Bu semantik versiya (semantic versioning) qoidasi: KATTA.KICHIK.TUZATISH. Katta raqam o'zgarsa β eski kod buzilishi mumkin; kichik raqam β yangi imkoniyat (eski kod ishlaydi); oxirgisi β xato tuzatish. ^ belgisi sizni avtomatik xato tuzatishlar bilan ta'minlaydi, lekin kutilmagan buzilishlardan himoya qiladi.
π‘
flutter pub upgradepaketlarni cheklov ichida eng yangiga ko'taradi.flutter pub outdatedesa qaysi paketlar eskirganini ko'rsatadi β vaqti-vaqti bilan tekshirib turing.
pub.dev sahifasini qanday o'qish kerak¶
pub.devda paket sahifasiga kirganingizda quyidagilarga e'tibor bering β bu sizga paket ishonchliligini baholashga yordam beradi:
- Platformalar β paket sahifasida qaysi platformalar (Android, iOS, Web, Windows, macOS, Linux) qo'llab-quvvatlanishi yozadi. Sizning ilovangiz veb-da ham ishlashi kerak bo'lsa, paket Web'ni qo'llab-quvvatlashini tekshiring.
- Likes (yoqtirishlar) va popularity (mashhurlik) β ko'p odam ishlatadigan paket odatda yaxshiroq sinalgan.
- Pub Points β pub.dev'ning avtomatik baho-ochkosi (hujjat, null-safety, kod sifati bo'yicha).
- Oxirgi yangilanish sanasi β paket faol qo'llab-quvvatlanayotganini ko'rsatadi. 2-3 yil yangilanmagan paketdan ehtiyot bo'ling.
- Null-safety β zamonaviy paketlar null-safety'ni qo'llab-quvvatlaydi (6-bobni eslang). Deyarli barcha hozirgi paketlar buni qiladi.
β οΈ Paket tanlashda "eng birinchi qidiruv natijasi"ni ko'r-ko'rona olmang. Platformalar, mashhurlik va oxirgi yangilanishni tekshiring. Notanish, kam ishlatiladigan paket loyihangizga keyinchalik bosh og'rig'i bo'lishi mumkin.
Qurilma imkoniyatlaridan foydalanish¶
Endi paketlarni amalda ishlatamiz. Telefonning haqiqiy imkoniyatlari β kamera, joylashuv, telefon qo'ng'irog'i β uchun maxsus paketlar bor. Mana eng ko'p ishlatiladiganlari:
| Paket | Nima qiladi |
|---|---|
image_picker |
Galereyadan rasm tanlash yoki kamera bilan suratga olish |
geolocator |
Qurilmaning GPS joylashuvini olish |
url_launcher |
Havola, telefon raqami yoki email'ni ochish |
permission_handler |
Ish vaqtidagi (runtime) ruxsatlarni so'rash va tekshirish |
connectivity_plus |
Internet aloqasi bor-yo'qligini bilish (Wi-Fi/mobil/yo'q) |
camera |
Ilova ichida to'liq kamera oqimini boshqarish |
shared_preferences |
Kichik sozlamalarni qurilmada saqlash |
package_info_plus / device_info_plus |
Ilova versiyasi / qurilma haqida ma'lumot |
Misol: galereyadan rasm tanlash (image_picker)¶
Avval paketni qo'shamiz:
So'ng foydalanish β galereyadan rasm tanlash:
import 'package:image_picker/image_picker.dart';
final picker = ImagePicker();
Future<void> rasmTanla() async {
final XFile? rasm = await picker.pickImage(source: ImageSource.gallery);
if (rasm == null) return; // foydalanuvchi bekor qildi
print('Tanlangan fayl: ${rasm.path}');
// rasm.path orqali uni Image.file(...) bilan ko'rsatishingiz mumkin
}
ImageSource.gallery o'rniga ImageSource.camera bersangiz, kamera ochiladi. XFile? β tanlangan fayl (null bo'lsa, foydalanuvchi bekor qilgan; har doim tekshiring).
Misol: joriy joylashuvni olish (geolocator)¶
import 'package:geolocator/geolocator.dart';
Future<Position?> joylashuvniOl() async {
// 1) Joylashuv xizmati (GPS) yoqilganmi?
final yoqilgan = await Geolocator.isLocationServiceEnabled();
if (!yoqilgan) return null;
// 2) Ruxsatni tekshirish va so'rash
var ruxsat = await Geolocator.checkPermission();
if (ruxsat == LocationPermission.denied) {
ruxsat = await Geolocator.requestPermission();
if (ruxsat == LocationPermission.denied) return null;
}
if (ruxsat == LocationPermission.deniedForever) return null;
// 3) Joylashuvni olish
return await Geolocator.getCurrentPosition();
}
E'tibor bering: joylashuvni so'rashdan oldin uch narsani tekshiramiz β GPS yoqilganmi, ruxsat bormi, agar yo'q bo'lsa so'raymiz. Bu naqsh (pattern) deyarli barcha qurilma imkoniyatlarida takrorlanadi.
Misol: tashqi havola, telefon, email (url_launcher)¶
import 'package:url_launcher/url_launcher.dart';
// Veb-sahifa ochish
await launchUrl(Uri.parse('https://ioqil.uz'));
// Telefon raqamini terish
await launchUrl(Uri.parse('tel:+998901234567'));
// Email yozish
await launchUrl(Uri.parse('mailto:salom@misol.uz'));
Uri.parse(...) matnni manzilga aylantiradi; tel:, mailto:, https: β turli sxemalar. Telefon qurilmasi shu sxemaga mos ilovani ochadi.
β οΈ Eng muhim qoida: ruxsatlarni e'lon qiling¶
Kamera, joylashuv, mikrofon kabi imkoniyatlardan foydalanish uchun ikki narsa kerak:
1) Platforma fayllarida e'lon qilish. Android'da bu android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CAMERA"/>
iOS'da bu ios/Runner/Info.plist β bu yerda foydalanuvchiga ko'rinadigan sabab ham yoziladi:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Yaqin atrofdagi do'konlarni ko'rsatish uchun joylashuvingiz kerak.</string>
<key>NSCameraUsageDescription</key>
<string>Profil rasmingizni olish uchun kameradan foydalanamiz.</string>
2) Ish vaqtida (runtime) so'rash. Zamonaviy telefonlarda ilova o'rnatilganida emas, balki kerak bo'lganda ruxsat so'raladi. Yuqoridagi geolocator misolida buni ko'rdik. Murakkabroq holatlar uchun permission_handler paketi yagona, qulay interfeys beradi:
import 'package:permission_handler/permission_handler.dart';
final holat = await Permission.camera.request();
if (holat.isGranted) {
// ruxsat berildi β kamerani ishlat
} else if (holat.isPermanentlyDenied) {
// foydalanuvchi "boshqa so'rama" dedi β sozlamalarni ochishni taklif qil
await openAppSettings();
}
π‘ Esda tuting: ruxsatni faqat platforma faylida e'lon qilsangiz, ish vaqtida so'ramaysiz β ilova ishlamaydi (yoki qulaydi). Ikkalasini ham qiling. Va har doim foydalanuvchi rad etishi mumkinligini hisobga oling β kodingiz buni boshqarishi shart.
Platform channel β paket bo'lmaganda¶
99% holatda kerakli imkoniyat uchun tayyor paket topiladi. Lekin ba'zan juda maxsus narsa kerak bo'ladi (masalan, kompaniyangizning xususiy qurilmasi bilan ishlash), va paket yo'q. Shunda siz native kodga (Android uchun Kotlin, iOS uchun Swift) to'g'ridan-to'g'ri murojaat qilishingiz mumkin β buning ko'prigi platform channel deyiladi.
G'oyasi oddiy: Dart tomoni va native tomoni xabarlar orqali gaplashadi. Dart "menga batareya darajasini ber" deb xabar yuboradi, native kod javob qaytaradi:
import 'package:flutter/services.dart';
// Ikkala tomon ham bir xil kanal nomini bilishi kerak
const battery = MethodChannel('app/battery');
Future<int> batareyaDarajasi() async {
// 'getLevel' β native tomonda biz yozadigan metod nomi
final int daraja = await battery.invokeMethod('getLevel');
return daraja;
}
Native tomonda (masalan Android β Kotlin) 'getLevel' so'rovini qabul qilib, batareya darajasini o'qib qaytaradigan kod yoziladi. Bu kitob doirasidan tashqarida, lekin g'oyani tushunish muhim: kanal nomi ('app/battery') va metod nomi ('getLevel') ikki tomonda bir xil bo'lishi kerak β aks holda xabar manzilini topmaydi.
π‘ Boshlovchi uchun amaliy maslahat: platform channel β ilg'or mavzu. Deyarli har doim avval pub.dev'da tayyor paket qidiring. Channel'ni faqat haqiqatan paket yo'q bo'lganda va siz native kod yoza oladigan paytda ishlatasiz. Uni bu yerda eslab qo'yganimizning sababi β Flutter'ning native qurilma bilan qanday "gaplashishi"ni tushunishingiz uchun.
Moslashuvchi (responsive) va adaptiv dizayn¶
Hozirgacha ilovamiz, ehtimol, faqat telefon ekranida yaxshi ko'ringan. Lekin Flutter bir kod bilan telefon, planshet, buklanadigan (foldable), veb va desktopda ishlaydi. Bularning ekran o'lchami juda har xil. Ilovangiz katta ekranda ham yaxshi ko'rinishi uchun unga moslashuvchi bo'lishni o'rgatish kerak.
Ikki yaqin tushunchani ajratamiz:
- Responsive (moslashuvchi) β o'lcham o'zgarganda joylashuv o'zgaradi. Masalan, telefonda bir ustun, planshetda ikki ustun.
- Adaptive (adaptiv) β platforma yoki kontekstga mos boshqa komponent ishlatiladi. Masalan, telefonda pastki menyu (
NavigationBar), planshetda yon menyu (NavigationRail).
Amalda ikkalasini birga ishlatasiz. Asboblarimiz:
MediaQuery β ekran haqida ma'lumot¶
MediaQuery β joriy ekran haqidagi ma'lumotlar manbai: o'lcham, orientatsiya, xavfsiz hududlar (notch), matn kattaligi:
final media = MediaQuery.of(context);
final kenglik = media.size.width; // ekran kengligi (piksellarda)
final balandlik = media.size.height;
final orientatsiya = media.orientation; // portrait yoki landscape
final tepaPadding = media.padding.top; // status bar / notch balandligi
LayoutBuilder β ota cheklovini o'qish¶
MediaQuery butun ekran o'lchamini beradi. LayoutBuilder esa ota-widget bergan joyni (constraints) o'qiydi β bu ko'pincha aniqroq, chunki sizning widget'ingiz ekranning faqat bir qismini egallashi mumkin. Buni 13-bobda ko'rgansiz:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const TelefonKorinishi(); // tor joy
} else {
return const KengKorinishi(); // keng joy
}
},
)
Breakpoint'lar (chegaralar)¶
Ekran kengligi bo'yicha "telefon / planshet / desktop"ni ajratish uchun chegara qiymatlar (breakpoints) ishlatiladi. Material dizayn tavsiyasiga yaqin amaliy chegaralar:
enum Qurilma { telefon, planshet, desktop }
Qurilma qurilmaTuri(double kenglik) {
if (kenglik < 600) return Qurilma.telefon;
if (kenglik < 1200) return Qurilma.planshet;
return Qurilma.desktop;
}
Adaptiv navigatsiya: NavigationBar β NavigationRail¶
Endi amalda quramiz: tor ekranda pastki menyu (NavigationBar), keng ekranda yon menyu (NavigationRail). Bu β adaptiv dizaynning klassik misoli:
class AdaptivKorinish extends StatefulWidget {
const AdaptivKorinish({super.key});
@override
State<AdaptivKorinish> createState() => _AdaptivKorinishState();
}
class _AdaptivKorinishState extends State<AdaptivKorinish> {
int _tanlangan = 0;
// Uchta bo'lim uchun oddiy sahifalar
final _sahifalar = const [
Center(child: Text('Uy')),
Center(child: Text('Qidiruv')),
Center(child: Text('Profil')),
];
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final keng = constraints.maxWidth >= 600;
if (keng) {
// KENG: yon NavigationRail + tarkib yonma-yon
return Scaffold(
body: Row(
children: [
NavigationRail(
selectedIndex: _tanlangan,
onDestinationSelected: (i) =>
setState(() => _tanlangan = i),
labelType: NavigationRailLabelType.all,
destinations: const [
NavigationRailDestination(
icon: Icon(Icons.home), label: Text('Uy')),
NavigationRailDestination(
icon: Icon(Icons.search), label: Text('Qidiruv')),
NavigationRailDestination(
icon: Icon(Icons.person), label: Text('Profil')),
],
),
const VerticalDivider(width: 1),
Expanded(child: _sahifalar[_tanlangan]),
],
),
);
} else {
// TOR: pastki NavigationBar
return Scaffold(
body: _sahifalar[_tanlangan],
bottomNavigationBar: NavigationBar(
selectedIndex: _tanlangan,
onDestinationSelected: (i) =>
setState(() => _tanlangan = i),
destinations: const [
NavigationDestination(icon: Icon(Icons.home), label: 'Uy'),
NavigationDestination(
icon: Icon(Icons.search), label: 'Qidiruv'),
NavigationDestination(
icon: Icon(Icons.person), label: 'Profil'),
],
),
);
}
},
);
}
}
Diqqat qiling: tanlangan indeks (_tanlangan) bitta β telefonda ham, planshetda ham bir xil holat ishlatiladi. Faqat ko'rinish o'zgaradi. Bu β adaptiv dizaynning go'zalligi: bir mantiq, ikki tashqi ko'rinish.
π‘ Sinash: desktop yoki veb-da ilovani ishga tushirib, oynani sichqoncha bilan torayting-kengaytiring. 600px chegarasidan o'tganda menyu pastdan yonga (yoki teskari) o'tib turishini ko'rasiz.
OrientationBuilderesa shunga o'xshash, lekin orientatsiya (portret/landshaft) o'zgarganda ishlaydi.
Xalqarolashtirish (i18n) β ilovani ko'p tilda qilish¶
Ilovangizni o'zbek va ingliz tillarida ko'rsatmoqchimisiz? Buni i18n (internationalization β "xalqarolashtirish", 18 ta harf orasida bo'lgani uchun shunday qisqartiriladi) deyiladi. Matnlarni kodga to'g'ridan-to'g'ri yozish o'rniga, ularni alohida til fayllariga ajratasiz, Flutter esa qurilma tiliga qarab to'g'risini tanlaydi.
1-qadam: paketlarni qo'shish¶
Va pubspec.yamlga generatsiyani yoqamiz:
2-qadam: ARB fayllari (tarjimalar)¶
Loyihada lib/l10n/ papkasini yarating va har bir til uchun bitta ARB fayl (.arb β JSON'ga o'xshash format). Ingliz tili β app_en.arb:
{
"greeting": "Hello!",
"itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
"@itemCount": {
"placeholders": { "count": { "type": "int" } }
}
}
O'zbek tili β app_uz.arb:
{
"greeting": "Salom!",
"itemCount": "{count, plural, =0{Element yo'q} =1{1 ta element} other{{count} ta element}}"
}
itemCount β ko'plik (plural) misoli: count qiymatiga qarab to'g'ri shakl tanlanadi. {count} β o'rin tutuvchi (placeholder), unga haqiqiy son qo'yiladi.
3-qadam: kod generatsiya qilish¶
Bu buyruq ARB fayllaridan AppLocalizations klassini avtomatik yaratadi. (Agar generate: true qo'ygan bo'lsangiz, flutter run paytida ham avtomatik ishlaydi.)
4-qadam: MaterialAppga ulash¶
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales, // [en, uz]
// locale: const Locale('uz'), // majburan bitta tilni qo'yish (ixtiyoriy)
home: const BoshSahifa(),
)
5-qadam: matnlardan foydalanish¶
Endi kodda matnni AppLocalizationsdan olasiz:
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Column(
children: [
Text(l10n.greeting), // "Salom!" yoki "Hello!"
Text(l10n.itemCount(5)), // "5 ta element" / "5 items"
],
);
}
AppLocalizations.of(context)! β joriy tilga mos tarjimalarni beradi. Qurilma tili o'zbek bo'lsa β o'zbekcha, ingliz bo'lsa β inglizcha matn chiqadi. Sehr shu yerda: matn endi bir joyda (ARB fayl), kodda esa faqat kalit (greeting).
π‘ RTL (o'ngdan-chapga) qo'llab-quvvatlash. Arab yoki ibroniy kabi o'ngdan-chapga yoziladigan tillar uchun Flutter
Directionalityni avtomatik boshqaradi:Row,padding'dagistart/endto'g'ri tomonga aylanadi. Shuning uchunleft/righto'rnigastart/end(masalanEdgeInsetsDirectional) ishlatish β yaxshi odat.
Qulaylik (accessibility, a11y) β ilovani hamma uchun¶
Qulaylik (accessibility, qisqacha a11y) β ilovangizni ko'rish, eshitish yoki harakat qiyinchiligi bor odamlar ham ishlata olishini ta'minlash. Bu nafaqat insoniy mas'uliyat, balki App Store va Google Play talablariga ham kiradi. Yaxshi xabar: Flutter buning ko'p qismini avtomatik qiladi, sizdan esa bir nechta odatlar talab etiladi.
Ekran o'quvchilarga (screen reader) yordam: Semantics¶
Ko'zi ojiz foydalanuvchilar ekran o'quvchi (Android'da TalkBack, iOS'da VoiceOver) bilan ishlaydi β u ekrandagi narsalarni ovoz bilan o'qib beradi. Matnli widgetlarni Flutter o'zi tushuntiradi, lekin rasm yoki ikonka tugmasi nima ekanini bilmaydi. Shuning uchun ularga yorliq (label) berasiz:
// Rasm uchun semanticLabel:
Image.asset('rasmlar/logo.png', semanticLabel: 'Kompaniya logotipi')
// Ikonka uchun:
Icon(Icons.favorite, semanticLabel: 'Sevimlilarga qo\'shilgan')
// Murakkabroq holat uchun Semantics widgeti:
Semantics(
label: 'Yangi xabar yozish',
button: true,
child: GestureDetector(
onTap: _yozish,
child: const Icon(Icons.edit),
),
)
Aksincha, bezak uchun (hech qanday ma'no bermaydigan) rasmni ekran o'quvchidan yashirish kerak bo'lsa β ExcludeSemantics:
Matn kattaligini hurmat qiling: textScaler¶
Ko'zi xira foydalanuvchilar telefon sozlamalarida matnni kattalashtiradi. Agar siz balandlikni qattiq belgilab qo'ysangiz (SizedBox(height: 40) ichida katta matn), matn sig'maydi va kesiladi. Yechim: qattiq balandlik bermang, matnga o'sishiga ruxsat bering. Joriy masshtabni MediaQuerydan o'qishingiz mumkin:
β οΈ Eng keng tarqalgan a11y xatosi β matn o'lchamini kattalashtirgan foydalanuvchida buziladigan dizayn. Sinash uchun: telefon sozlamalarida shrift o'lchamini eng kattaga qo'ying va ilovangizni tekshiring β hamma narsa ko'rinib turibdimi?
Yetarli kontrast va katta bosish maydoni¶
- Rang kontrasti. Matn va orqa fon orasida yetarli farq bo'lishi kerak (och kulrang fonda och kulrang matn β yomon). WCAG tavsiyasi: oddiy matn uchun kamida 4.5:1 kontrast nisbati.
- Bosish maydoni (tap target). Tugmalar va bosiladigan elementlar kamida 48Γ48 piksel bo'lishi kerak β aks holda barmoq bilan aniq bosish qiyin. Material widgetlari (
IconButton,ElevatedButton) buni odatda o'zi ta'minlaydi.
Birlashtirib: qulay rasm-tugma¶
Mana, hammasini birlashtirgan kichik misol β qulay (accessible) rasm-tugma:
Semantics(
label: 'Profil rasmini o\'zgartirish',
button: true,
child: InkWell(
onTap: _rasmTanla,
child: Padding(
padding: const EdgeInsets.all(12), // 48x48 ga yetkazadi
child: const Icon(Icons.camera_alt, size: 24),
),
),
)
Bunda: Semantics ekran o'quvchiga "Profil rasmini o'zgartirish, tugma" deydi; Padding bosish maydonini 48Γ48 ga yetkazadi; InkWell bosilganda to'lqin effekti beradi. Bir nechta qator β katta foyda.
π‘ Nega bu muhim? Dunyoda milliardlab odam u yoki bu darajada qulaylik imkoniyatlariga muhtoj. Ilovangiz ularni ham qamrab olsa β siz auditoriyangizni kengaytirasiz va to'g'ri ish qilasiz. Bundan tashqari, App Store/Play Store ilovani tekshirganda a11y'ni hisobga oladi.
Birgalikda: keng, ko'p tilli va qulay ilova¶
Endi o'rgangan uch g'oyani bitta MaterialAppda birlashtiramiz β adaptiv navigatsiya (AdaptivKorinish, yuqorida), ikki tilli i18n va qulay tugmalar:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Moslashuvchi ilova',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
),
// i18n: ikki til (en + uz)
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
// Adaptiv navigatsiya: telefon NavigationBar β planshet NavigationRail
home: const AdaptivKorinish(),
);
}
}
Bu ilova endi: katta ekranlarda yon menyu, kichik ekranlarda pastki menyu ko'rsatadi; qurilma tiliga qarab o'zbekcha yoki inglizcha matn chiqaradi; ekran o'quvchilar va katta matn bilan ham to'g'ri ishlaydi. Bularning hammasini bir kod bazasi bilan β Flutter'ning kuchi shunda.
Keyingi qadam¶
Bu bobda ilovangizni tashqi dunyoga uladingiz: paketlar va pub.dev, qurilma imkoniyatlari (kamera, joylashuv, ruxsatlar), platform channel g'oyasi, moslashuvchi va adaptiv dizayn, xalqarolashtirish va qulaylik. Endi ilovangiz turli qurilma, til va foydalanuvchiga moslasha oladi.
Lekin yaxshi ilova β nafaqat ishlaydigan, balki ishonchli ilova. Keyingi 29-bobda testing, debugging va ishlab chiqarish mavzusiga o'tamiz: kodingizni avtomatik test bilan qanday himoyalash, xatolarni topish (debugging), unumdorlikni (performance) yaxshilash va ilovani do'konga chiqarishga tayyorlash. Shu paytda bu bobdagi paketlar va adaptiv kodlarni ham test bilan mustahkamlaymiz.
Mashqlar¶
Oson¶
dependenciesvadev_dependenciesorasidagi farq nima?flutter_lintsqaysi biriga kiradi va nega?http: ^1.5.0cheklovi qaysi versiyalarni ruxsat etadi va qaysilarini etmaydi?1.9.0va2.0.0β qaysi biri mumkin?- Galereyadan rasm tanlash uchun qaysi paketni qo'shasiz va terminal buyrug'i qanday bo'ladi?
pickImageqaytaradigan qiymatnullbo'lsa, bu nimani anglatadi? - Responsive va adaptive dizayn orasidagi farqni o'z so'zlaringiz bilan, bittadan misol bilan tushuntiring.
O'rta¶
- Bir o'quvchi
geolocatorbilan joylashuvni olmoqchi,AndroidManifest.xmlga ruxsatni qo'shgan, lekin ilova hech narsa qaytarmayapti. U nimani unutgan bo'lishi mumkin? Joylashuvni olishdan oldin tekshirilishi kerak bo'lgan uch narsani sanang. LayoutBuilderbilan shunday widget yozing: agar ota kengligi 600 dan kichik bo'lsaColumn, aks holdaRowqaytarsin (ichida ixtiyoriy ikkita matn bo'lsin).MediaQueryo'rnigaLayoutBuilderishlatishning afzalligi nima?- i18n sozlashda
app_en.arbvaapp_uz.arbfayllarining vazifasi nima?flutter gen-l10nbuyrug'i nima qiladi va kodda matnni qanday olasiz?
Qiyin¶
- Quyidagi tugma a11y nuqtai nazaridan yomon:
GestureDetector(onTap: ..., child: Icon(Icons.delete, size: 18)). Uni qulayroq qiling β kamida ikkita muammoni toping va tuzating. - Platform channel qachon kerak bo'ladi va u qanday ishlaydi (xabar oqimini tushuntiring)? Nega boshlovchiga avval pub.dev'da paket qidirish tavsiya etiladi? Kanal nomi ikki tomonda bir xil bo'lmasa nima bo'ladi?
- Bir ilova telefonda yaxshi ishlaydi, lekin planshetda matn juda kichik va menyu pastda noqulay. Adaptiv qilish uchun siz qaysi uch narsani o'zgartirasiz? Har biri uchun qaysi widget yoki yondashuvni ishlatishingizni ayting.
Yechimlar
1. dependencies β ilova ishlash uchun kerak bo'lgan paketlar; ular tayyor ilovaga ham qo'shiladi. dev_dependencies β faqat ishlab chiqish paytida kerak bo'lganlar (testlar, linterlar, generatorlar); ular tayyor ilovaga kirmaydi. flutter_lints β dev_dependenciesga kiradi, chunki u faqat kod yozish paytida tahlil/maslahat beradi; tayyor ilova ishlashiga aloqasi yo'q, shuning uchun uni ilova hajmiga qo'shish keraksiz.
2. ^1.5.0 β "1.5.0 dan yuqori, lekin 2.0.0 dan past" degani. 1.9.0 β mumkin (hali 2.0.0 dan past, kichik versiya). 2.0.0 β mumkin emas (katta versiya, buzuvchi o'zgarish bo'lishi mumkin, shuning uchun ^ uni o'tkazmaydi).
3. Paket β image_picker, buyruq:
pickImage(...) null qaytarsa β bu foydalanuvchi bekor qilgani (rasm tanlamay chiqib ketgani) degani. Shuning uchun har doim if (rasm == null) return; bilan tekshirish kerak.
4. Responsive β o'lcham o'zgarganda joylashuv moslashadi (masalan, telefonda bir ustun, planshetda ikki ustun β bir xil widgetlar, boshqa joylashuv). Adaptive β kontekstga mos boshqa komponent ishlatiladi (masalan, telefonda NavigationBar, planshetda NavigationRail β boshqa widget). Qisqasi: responsive = "qayta joylashtirish", adaptive = "boshqa komponent tanlash".
5. U ish vaqtida (runtime) ruxsat so'rashni unutgan bo'lishi mumkin β AndroidManifest.xmlda e'lon qilish yetarli emas, zamonaviy Android'da ruxsatni kod orqali ham so'rash kerak. Joylashuvdan oldin tekshirilishi kerak bo'lgan uch narsa:
1. Joylashuv xizmati (GPS) yoqilganmi β Geolocator.isLocationServiceEnabled().
2. Ruxsat holatini tekshirish β Geolocator.checkPermission().
3. Agar denied bo'lsa, ruxsat so'rash β Geolocator.requestPermission() (va deniedForever holatini boshqarish).
6.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return const Column(
children: [Text('Birinchi'), Text('Ikkinchi')],
);
} else {
return const Row(
children: [Text('Birinchi'), Text('Ikkinchi')],
);
}
},
)
MediaQuery butun ekran o'lchamini beradi, LayoutBuilder esa ota-widget bergan haqiqiy joyni (constraints) beradi. Agar widget'ingiz ekranning faqat bir qismida (masalan, yon panel ichida) bo'lsa, LayoutBuilder aniqroq qaror beradi.
7. app_en.arb va app_uz.arb β har bir til uchun tarjima fayllari (kalit β matn juftliklari). flutter gen-l10n ulardan AppLocalizations klassini avtomatik generatsiya qiladi. Kodda matnni shunday olasiz:
8. Ikki (yoki undan ko'p) muammo: (a) ekran o'quvchi tugmaning nima ekanini bilmaydi β semanticLabel/Semantics yo'q; (b) bosish maydoni juda kichik (size: 18, hech qanday padding yo'q) β 48Γ48 ga yetmaydi. Tuzatilgan versiya:
Semantics(
label: 'O\'chirish',
button: true,
child: InkWell(
onTap: _ochir,
child: const Padding(
padding: EdgeInsets.all(14), // bosish maydonini kattalashtiradi
child: Icon(Icons.delete, size: 24),
),
),
)
IconButton(onPressed: _ochir, icon: Icon(Icons.delete), tooltip: 'O\'chirish') β u 48Γ48 va semantikani o'zi ta'minlaydi.)
9. Platform channel β kerakli imkoniyat uchun tayyor paket yo'q bo'lganda, native (Kotlin/Swift) kodga to'g'ridan-to'g'ri murojaat qilish uchun kerak. Xabar oqimi: Dart MethodChannel('nom').invokeMethod('metod') bilan so'rov xabari yuboradi β ko'prik orqali native tomonga o'tadi β native kod uni bajarib, javob xabarini qaytaradi β natija Dart'da await orqali olinadi. Boshlovchiga avval paket qidirish tavsiya etiladi, chunki channel ilg'or mavzu (native kod yozishni talab qiladi) va 99% holatda tayyor, sinalgan paket allaqachon mavjud. Kanal nomi ikki tomonda bir xil bo'lmasa, xabar manzilini topmaydi β native kod chaqirilmaydi (xato yoki javobsizlik bo'ladi).
10. Uch o'zgarish:
1. Navigatsiyani adaptiv qilish β keng ekranda pastki NavigationBar o'rniga yon NavigationRail ko'rsatish. Buni LayoutBuilder + kenglik chegarasi (masalan >= 600) bilan tanlash.
2. Joylashuvni moslashtirish β LayoutBuilder/MediaQuery bilan kenglikni o'lchab, keng ekranda tarkibni ikki ustun qilib yoki maksimal kenglik berib (juda cho'zilmasligi uchun) joylashtirish.
3. Matnni moslashtirish β qattiq kichik shrift o'lchamlarini ishlatmaslik; Themedagi matn uslublariga tayanish va MediaQuery.textScalerOf(context)ni hurmat qilish, balandlikni qattiq belgilamaslik β shunda katta ekranda ham, kattalashtirilgan matnda ham to'g'ri ko'rinadi.
β¬ οΈ Oldingi: 27 β Animatsiya Β· π README Β· Keyingi: 29 β Testing, debugging va ishlab chiqarish β‘οΈ