إنشاء النماذج والتحقق من صحة البيانات في Flutter

Amine
11/12/2024

النماذج هي جزء أساسي من معظم التطبيقات الحديثة. سواء كنت تبني تطبيق تسجيل دخول، أو نموذج حجز، أو استمارة طلب، فإن فهم كيفية إنشاء وإدارة النماذج في Flutter أمر ضروري لأي مطور.

في هذا الدرس، سنتعلم كيفية إنشاء نماذج فعالة والتحقق من صحة البيانات في Flutter. سنبدأ من الأساسيات وننتقل تدريجياً إلى المفاهيم المتقدمة.

  • إنشاء نماذج باستخدام Form و TextFormField
  • التحقق من صحة المدخلات
  • معالجة حالات الخطأ
  • تخصيص مظهر النماذج
  • أفضل الممارسات في تصميم النماذج

مفاهيم أساسية في النماذج

  • Form Widget: هو الحاوية الرئيسية للنموذج. يقوم بتنظيم وإدارة حالة جميع حقول النموذج.
  • GlobalKey: مفتاح فريد يسمح لنا بالوصول إلى حالة النموذج والتحكم فيه.
  • TextFormField: حقل إدخال متطور يدعم التحقق من الصحة والتخصيص.
  • InputDecoration: يتحكم في مظهر حقل الإدخال (الحدود، التسميات، الأيقونات).
  • Validator: دالة تتحقق من صحة القيمة المدخلة وترجع رسالة خطأ إذا كانت غير صالحة.
class RegistrationForm extends StatefulWidget {
  @override
  _RegistrationFormState createState() => _RegistrationFormState();
}

class _RegistrationFormState extends State {
  final _formKey = GlobalKey();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            controller: _emailController,
            decoration: InputDecoration(
              labelText: 'البريد الإلكتروني',
              border: OutlineInputBorder(),
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'الرجاء إدخال البريد الإلكتروني';
              }
              return null;
            },
          ),
          SizedBox(height: 16),
          TextFormField(
            controller: _passwordController,
            decoration: InputDecoration(
              labelText: 'كلمة المرور',
              border: OutlineInputBorder(),
            ),
            obscureText: true,
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'الرجاء إدخال كلمة المرور';
              }
              return null;
            },
          ),
          SizedBox(height: 16),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                // معالجة النموذج
              }
            },
            child: Text('تسجيل'),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }
}
  • GlobalKey: يتيح لنا الوصول إلى حالة النموذج والتحقق من صحته.
  • TextEditingController: يدير حالة كل حقل نص ويتيح لنا الوصول إلى قيمته وتغييرها.
  • InputDecoration: يحدد مظهر الحقل مثل التسمية والحدود والأيقونات.
  • validator: دالة تُستدعى عند التحقق من صحة الحقل.

التحقق المتقدم من صحة المدخلات

class Validators {
  static String? validateEmail(String? value) {
    if (value == null || value.isEmpty) {
      return 'الرجاء إدخال البريد الإلكتروني';
    }
    final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
    if (!emailRegex.hasMatch(value)) {
      return 'الرجاء إدخال بريد إلكتروني صحيح';
    }
    return null;
  }

  static String? validatePassword(String? value) {
    if (value == null || value.isEmpty) {
      return 'الرجاء إدخال كلمة المرور';
    }
    if (value.length < 8) {
      return 'كلمة المرور يجب أن تكون 8 أحرف على الأقل';
    }
    if (!value.contains(RegExp(r'[A-Z]'))) {
      return 'كلمة المرور يجب أن تحتوي على حرف كبير واحد على الأقل';
    }
    if (!value.contains(RegExp(r'[0-9]'))) {
      return 'كلمة المرور يجب أن تحتوي على رقم واحد على الأقل';
    }
    return null;
  }

  static String? validatePhone(String? value) {
    if (value == null || value.isEmpty) {
      return 'الرجاء إدخال رقم الهاتف';
    }
    final phoneRegex = RegExp(r'^\+?[\d\s-]{8,}$');
    if (!phoneRegex.hasMatch(value)) {
      return 'الرجاء إدخال رقم هاتف صحيح';
    }
    return null;
  }
}

تحسين تجربة المستخدم

class FormTheme {
  static InputDecoration buildInputDecoration(String label, IconData? icon) {
    return InputDecoration(
      labelText: label,
      prefixIcon: icon != null ? Icon(icon) : null,
      border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(8),
      ),
      enabledBorder: OutlineInputBorder(
        borderRadius: BorderRadius.circular(8),
        borderSide: BorderSide(color: Colors.grey.shade300),
      ),
      focusedBorder: OutlineInputBorder(
        borderRadius: BorderRadius.circular(8),
        borderSide: BorderSide(color: Colors.blue, width: 2),
      ),
      errorBorder: OutlineInputBorder(
        borderRadius: BorderRadius.circular(8),
        borderSide: BorderSide(color: Colors.red, width: 2),
      ),
      filled: true,
      fillColor: Colors.grey.shade50,
    );
  }
}

class AdvancedForm extends StatefulWidget {
  @override
  _AdvancedFormState createState() => _AdvancedFormState();
}

class _AdvancedFormState extends State {
  final _formKey = GlobalKey();
  bool _isLoading = false;

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            decoration: FormTheme.buildInputDecoration(
              'البريد الإلكتروني',
              Icons.email,
            ),
            validator: Validators.validateEmail,
            autovalidateMode: AutovalidateMode.onUserInteraction,
          ),
          SizedBox(height: 16),
          TextFormField(
            decoration: FormTheme.buildInputDecoration(
              'كلمة المرور',
              Icons.lock,
            ),
            obscureText: true,
            validator: Validators.validatePassword,
            autovalidateMode: AutovalidateMode.onUserInteraction,
          ),
          SizedBox(height: 24),
          ElevatedButton(
            onPressed: _isLoading
                ? null
                : () async {
                    if (_formKey.currentState!.validate()) {
                      setState(() => _isLoading = true);
                      try {
                        await Future.delayed(Duration(seconds: 2)); // محاكاة طلب الشبكة
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('تم التسجيل بنجاح')),
                        );
                      } finally {
                        setState(() => _isLoading = false);
                      }
                    }
                  },
            child: _isLoading
                ? CircularProgressIndicator(color: Colors.white)
                : Text('تسجيل'),
          ),
        ],
      ),
    );
  }
}

أفضل الممارسات

  • التحقق الفوري: قم بالتحقق من صحة المدخلات أثناء الكتابة لتوفير تغذية راجعة فورية
  • رسائل خطأ واضحة: استخدم رسائل خطأ مفهومة وموجهة للمستخدم
  • تعطيل الأزرار: عطل أزرار الإرسال أثناء معالجة النموذج لمنع الإرسال المتكرر
  • حالة التحميل: أظهر مؤشر التحميل عند معالجة النموذج لإعلام المستخدم بالتقدم
  • إعادة التعيين: امسح النموذج بعد الإرسال الناجح وأظهر رسالة نجاح

التعليقات

اترك تعليقاً