ودجات Cupertino (نمط iOS)
ودجات نمط iOS في Flutter
يتضمن Flutter مجموعة كاملة من ودجات نمط iOS تحت مكتبة cupertino. هذه الودجات تحاكي المظهر والإحساس الأصلي لتطبيقات iOS مما يجعل تطبيق Flutter يبدو مألوفاً على أجهزة Apple. يمكنك حتى مزج ودجات Material و Cupertino في نفس التطبيق لإنشاء واجهات متكيفة مع المنصة.
package:flutter/cupertino.dart. يمكنك استيراد كلا material.dart و cupertino.dart في نفس الملف دون تعارضات.CupertinoApp و CupertinoPageScaffold
CupertinoApp هو مكافئ iOS لـ MaterialApp. يُعد سمات Cupertino. CupertinoPageScaffold يوفر هيكل الصفحة الأساسي مع شريط تنقل ومنطقة محتوى.
تطبيق Cupertino أساسي
import 'package:flutter/cupertino.dart';
void main() => runApp(const MyCupertinoApp());
class MyCupertinoApp extends StatelessWidget {
const MyCupertinoApp({super.key});
@override
Widget build(BuildContext context) {
return const CupertinoApp(
title: 'تطبيق نمط iOS',
theme: CupertinoThemeData(
primaryColor: CupertinoColors.activeBlue,
brightness: Brightness.light,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('الرئيسية'),
),
child: Center(
child: Text('مرحباً iOS!'),
),
);
}
}
CupertinoNavigationBar
شريط التنقل بنمط iOS يقع في الأعلى مع عنوان في الوسط وودجات اختيارية في البداية والنهاية.
شريط تنقل مع إجراءات
CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: const Text('الإعدادات'),
leading: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () => Navigator.pop(context),
child: const Icon(CupertinoIcons.back),
),
trailing: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
debugPrint('تم الضغط على تعديل');
},
child: const Text('تعديل'),
),
),
child: const SafeArea(
child: Center(child: Text('المحتوى هنا')),
),
)
CupertinoButton
زر بنمط iOS مع تأثير شفافية عند الضغط بدلاً من تموج Material.
أزرار Cupertino
Column(
children: [
// زر افتراضي (نصي)
CupertinoButton(
onPressed: () => debugPrint('تم الضغط'),
child: const Text('زر نصي'),
),
// زر مملوء
CupertinoButton.filled(
onPressed: () => debugPrint('تم الضغط على المملوء'),
child: const Text('زر مملوء'),
),
// زر معطّل
const CupertinoButton(
onPressed: null,
child: Text('معطّل'),
),
// زر بتنسيق مخصص
CupertinoButton(
color: CupertinoColors.destructiveRed,
borderRadius: BorderRadius.circular(8),
onPressed: () => debugPrint('حذف'),
child: const Text('حذف الحساب'),
),
],
)
CupertinoTextField
حقل نص بنمط iOS مع حدود مستديرة ونص عنصر نائب.
أمثلة CupertinoTextField
Column(
children: [
// حقل نص أساسي
const CupertinoTextField(
placeholder: 'أدخل اسمك',
padding: EdgeInsets.all(12),
),
const SizedBox(height: 16),
// حقل نص منسق مع بادئة
CupertinoTextField(
placeholder: 'بحث...',
prefix: const Padding(
padding: EdgeInsets.only(left: 8),
child: Icon(
CupertinoIcons.search,
color: CupertinoColors.systemGrey,
),
),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
borderRadius: BorderRadius.circular(10),
),
padding: const EdgeInsets.all(12),
clearButtonMode: OverlayVisibilityMode.editing,
),
const SizedBox(height: 16),
// حقل كلمة المرور
const CupertinoTextField(
placeholder: 'كلمة المرور',
obscureText: true,
padding: EdgeInsets.all(12),
suffix: Padding(
padding: EdgeInsets.only(right: 8),
child: Icon(
CupertinoIcons.eye_slash,
color: CupertinoColors.systemGrey,
),
),
),
],
)
CupertinoSwitch و CupertinoSlider
مفاتيح التبديل ومنزلقات بنمط iOS.
المفتاح والمنزلق
class ControlsExample extends StatefulWidget {
const ControlsExample({super.key});
@override
State<ControlsExample> createState() => _ControlsExampleState();
}
class _ControlsExampleState extends State<ControlsExample> {
bool _wifiEnabled = true;
double _brightness = 0.7;
@override
Widget build(BuildContext context) {
return CupertinoListSection.insetGrouped(
header: const Text('العرض والشبكة'),
children: [
CupertinoListTile(
title: const Text('Wi-Fi'),
trailing: CupertinoSwitch(
value: _wifiEnabled,
onChanged: (bool value) {
setState(() => _wifiEnabled = value);
},
),
),
CupertinoListTile(
title: const Text('السطوع'),
trailing: SizedBox(
width: 180,
child: CupertinoSlider(
value: _brightness,
onChanged: (double value) {
setState(() => _brightness = value);
},
),
),
),
],
);
}
}
CupertinoListSection.insetGrouped لإنشاء تخطيط الإعدادات المجمعة الشائع في تطبيقات iOS. يتعامل تلقائياً مع الزوايا المستديرة ورؤوس الأقسام.CupertinoAlertDialog
مربع حوار التنبيه بنمط iOS مع زوايا مستديرة وأزرار إجراءات مكدسة أو جنباً إلى جنب.
حوار تنبيه Cupertino
void _showCupertinoAlert(BuildContext context) {
showCupertinoDialog(
context: context,
builder: (BuildContext ctx) {
return CupertinoAlertDialog(
title: const Text('حذف الصورة'),
content: const Text(
'سيتم حذف هذه الصورة من جميع أجهزتك. '
'يمكنك استعادتها من المحذوفة مؤخراً لمدة 30 يوماً.',
),
actions: [
CupertinoDialogAction(
onPressed: () => Navigator.pop(ctx),
child: const Text('إلغاء'),
),
CupertinoDialogAction(
isDestructiveAction: true,
onPressed: () {
Navigator.pop(ctx);
debugPrint('تم حذف الصورة');
},
child: const Text('حذف'),
),
],
);
},
);
}
CupertinoActionSheet
ورقة الإجراءات تنزلق من الأسفل وتعرض مجموعة خيارات. تتضمن دائماً زر إلغاء.
ورقة إجراءات Cupertino
void _showActionSheet(BuildContext context) {
showCupertinoModalPopup(
context: context,
builder: (BuildContext ctx) {
return CupertinoActionSheet(
title: const Text('مشاركة الصورة'),
message: const Text('اختر كيف تريد مشاركة هذه الصورة.'),
actions: [
CupertinoActionSheetAction(
onPressed: () {
Navigator.pop(ctx);
debugPrint('AirDrop');
},
child: const Text('AirDrop'),
),
CupertinoActionSheetAction(
onPressed: () {
Navigator.pop(ctx);
debugPrint('الرسائل');
},
child: const Text('الرسائل'),
),
CupertinoActionSheetAction(
isDestructiveAction: true,
onPressed: () {
Navigator.pop(ctx);
debugPrint('حذف');
},
child: const Text('حذف الصورة'),
),
],
cancelButton: CupertinoActionSheetAction(
isDefaultAction: true,
onPressed: () => Navigator.pop(ctx),
child: const Text('إلغاء'),
),
);
},
);
}
CupertinoPicker و CupertinoDatePicker
منتقيات عجلة التمرير بنمط iOS لاختيار القيم والتواريخ.
منتقي Cupertino
void _showPicker(BuildContext context) {
final List<String> countries = [
'السعودية', 'الإمارات', 'مصر',
'الأردن', 'الكويت', 'قطر',
];
showCupertinoModalPopup(
context: context,
builder: (ctx) {
return Container(
height: 250,
color: CupertinoColors.systemBackground,
child: CupertinoPicker(
itemExtent: 36,
onSelectedItemChanged: (int index) {
debugPrint('تم الاختيار: \${countries[index]}');
},
children: countries.map((c) => Center(child: Text(c))).toList(),
),
);
},
);
}
منتقي التاريخ Cupertino
void _showDatePicker(BuildContext context) {
showCupertinoModalPopup(
context: context,
builder: (ctx) {
return Container(
height: 300,
color: CupertinoColors.systemBackground,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CupertinoButton(
child: const Text('إلغاء'),
onPressed: () => Navigator.pop(ctx),
),
CupertinoButton(
child: const Text('تم'),
onPressed: () => Navigator.pop(ctx),
),
],
),
Expanded(
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: DateTime.now(),
minimumDate: DateTime(2000),
maximumDate: DateTime(2030),
onDateTimeChanged: (DateTime date) {
debugPrint('التاريخ: \$date');
},
),
),
],
),
);
},
);
}
ودجات متكيفة مع المنصة
يمكنك بناء ودجات تتبدل تلقائياً بين أنماط Material و Cupertino بناءً على المنصة.
حوار متكيف
import 'dart:io' show Platform;
void showAdaptiveAlert(BuildContext context) {
if (Platform.isIOS || Platform.isMacOS) {
showCupertinoDialog(
context: context,
builder: (ctx) => CupertinoAlertDialog(
title: const Text('تنبيه'),
content: const Text('حدث شيء ما.'),
actions: [
CupertinoDialogAction(
onPressed: () => Navigator.pop(ctx),
child: const Text('حسناً'),
),
],
),
);
} else {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('تنبيه'),
content: const Text('حدث شيء ما.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('حسناً'),
),
],
),
);
}
}
مفتاح متكيف (مدمج)
// يوفر Flutter 3.x Switch.adaptive وغيرها
Switch.adaptive(
value: _isEnabled,
onChanged: (bool value) {
setState(() => _isEnabled = value);
},
)
// متاحة أيضاً:
// Slider.adaptive(...)
// CircularProgressIndicator.adaptive()
dart:io غير متاحة على Flutter Web. إذا كان تطبيقك يستهدف الويب استخدم Theme.of(context).platform أو defaultTargetPlatform من foundation.dart بدلاً من Platform.isIOS.مثال عملي: نسخة إعدادات iOS
صفحة إعدادات iOS واقعية مبنية بالكامل بودجات Cupertino.
شاشة إعدادات iOS
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _airplaneMode = false;
bool _wifi = true;
bool _bluetooth = true;
bool _notifications = true;
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text('الإعدادات'),
),
child: SafeArea(
child: ListView(
children: [
CupertinoListSection.insetGrouped(
children: [
CupertinoListTile(
leading: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: CupertinoColors.systemOrange,
borderRadius: BorderRadius.circular(6),
),
child: const Icon(
CupertinoIcons.airplane,
color: CupertinoColors.white,
size: 20,
),
),
title: const Text('وضع الطيران'),
trailing: CupertinoSwitch(
value: _airplaneMode,
onChanged: (v) => setState(() => _airplaneMode = v),
),
),
CupertinoListTile(
leading: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: CupertinoColors.activeBlue,
borderRadius: BorderRadius.circular(6),
),
child: const Icon(
CupertinoIcons.wifi,
color: CupertinoColors.white,
size: 20,
),
),
title: const Text('Wi-Fi'),
additionalInfo: Text(_wifi ? 'الشبكة المنزلية' : 'معطّل'),
trailing: const CupertinoListTileChevron(),
),
CupertinoListTile(
leading: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: CupertinoColors.activeBlue,
borderRadius: BorderRadius.circular(6),
),
child: const Icon(
CupertinoIcons.bluetooth,
color: CupertinoColors.white,
size: 20,
),
),
title: const Text('البلوتوث'),
additionalInfo: Text(_bluetooth ? 'مفعّل' : 'معطّل'),
trailing: const CupertinoListTileChevron(),
),
],
),
CupertinoListSection.insetGrouped(
children: [
CupertinoListTile(
leading: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: CupertinoColors.systemRed,
borderRadius: BorderRadius.circular(6),
),
child: const Icon(
CupertinoIcons.bell_fill,
color: CupertinoColors.white,
size: 20,
),
),
title: const Text('الإشعارات'),
trailing: const CupertinoListTileChevron(),
),
],
),
],
),
),
);
}
}
ملخص
CupertinoApp+CupertinoPageScaffold-- هيكل تطبيق iOS وتخطيط الصفحةCupertinoNavigationBar-- شريط علوي بنمط iOS مع عنوان في الوسطCupertinoButton-- زر ضغط بالشفافية (نصي ومملوء)CupertinoTextField-- إدخال نص iOS مستدير مع عنصر نائبCupertinoSwitch/CupertinoSlider-- عناصر تحكم تبديل ونطاق iOSCupertinoAlertDialog-- تنبيه iOS مستدير مع إجراءات مكدسةCupertinoActionSheet-- ورقة إجراءات سفلية مع زر إلغاءCupertinoPicker/CupertinoDatePicker-- اختيار بعجلة التمرير- ودجات متكيفة مع المنصة:
Switch.adaptiveوفحوصات المنصة الشرطية
تمرين عملي
ابنِ شاشة إعدادات iOS كاملة باستخدام ودجات Cupertino فقط. أضف مفتاح وضع الطيران وصفوف Wi-Fi و Bluetooth مع أسهم التنقل وقسم الإشعارات وإجراء "تسجيل الخروج" الذي يعرض CupertinoActionSheet يطلب من المستخدم التأكيد. استخدم CupertinoListSection.insetGrouped للتخطيط المجمع.