TextFormField

ما هو TextFormField؟

TextFormField هو ويدجت (Widget) لكتابة النصوص مبني فوق TextField، لكنه يضيف ميزة قوية جدًا:
✅ التكامل مع Form وFormState — يعني تقدر تتحقق (validate) من القيم، تحفظها (save)، وتتحكم فيها بسهولة.

باختصار:
TextField = إدخال نص بسيط
TextFormField = إدخال نص ضمن نموذج (Form) مع التحقق، الحفظ، وغيرها.

⚙️ كيف يعمل؟
  • يوضع داخل Form (عن طريق Form Widget).
  • يتم تعريف مفتاح (GlobalKey<FormState>) للتحكم في النموذج.
  • عند الضغط على زر “إرسال” أو “حفظ”، يمكنك استدعاء:
    • formKey.currentState!.validate() ← يتحقق من جميع الحقول.
    • formKey.currentState!.save() ← يحفظ القيم بعد تحققها.
📋 البنية العامة
TextFormField(
  controller: _controller,        // للتحكم بالنص
  focusNode: _focusNode,          // للتحكم بالـ focus
  decoration: InputDecoration(    // للتحكم بالشكل
    labelText: 'الاسم',
    hintText: 'ادخل اسمك الكامل',
    prefixIcon: Icon(Icons.person),
    border: OutlineInputBorder(),
  ),
  keyboardType: TextInputType.text, // نوع الكيبورد
  textInputAction: TextInputAction.next, // زر الإدخال
  obscureText: false,              // إخفاء النص؟ (كلمة مرور مثلاً)
  validator: (value) {             // التحقق من القيمة
    if (value == null || value.isEmpty) {
      return 'هذا الحقل مطلوب';
    }
    return null;
  },
  onSaved: (value) {               // حفظ القيمة بعد التحقق
    name = value!;
  },
  onChanged: (value) => print(value),
)
PHP
🎯 الأقسام الأساسية للخصائص (مقسّمة + الشرح + القيم الشائعة)
🧠 أولًا: إدارة النص والتحكم
الخاصيةالنوعالوصفالقيم الشائعة
controllerTextEditingController?للتحكم بالنص داخل الحقل (قراءة/تغيير)TextEditingController()
focusNodeFocusNode?التحكم بالتركيز (Focus)FocusNode()
initialValueString?تعيين قيمة ابتدائية للحقل (بدون controller)'Ahmed'
enabledbool?تفعيل/تعطيل الحقل بالكاملtrue / false
readOnlyboolعرض النص فقط بدون تعديلtrue / false

🔸 ملاحظة: لا يمكن استخدام controller وinitialValue معًا، لأنهما يحددان النص بطريقتين مختلفتين.

🎨 ثانيًا: المظهر والديكور (عبر InputDecoration)
الخاصيةالنوعالشرحمثال
decorationInputDecorationتحكم في مظهر الحقل (نصوص، أيقونات، حدود…)InputDecoration(labelText: 'Email', prefixIcon: Icon(Icons.email))
styleTextStyle?تنسيق النص داخل الحقلTextStyle(fontSize: 18, color: Colors.blue)
textAlignTextAlignمحاذاة النص داخل الحقلTextAlign.center
textAlignVerticalTextAlignVertical?محاذاة رأسية للنصTextAlignVertical.center
cursorColorColor?لون المؤشرColors.red
cursorWidthdoubleعرض المؤشر2.0
cursorRadiusRadius?شكل طرف المؤشرRadius.circular(5)
⌨️ ثالثًا: نوع الإدخال وسلوك لوحة المفاتيح
الخاصيةالنوعالوصفالقيم الشائعة
keyboardTypeTextInputType?يحدد نوع لوحة المفاتيحTextInputType.text, number, emailAddress
textInputActionTextInputAction?الزر في لوحة المفاتيحnext, done, go, send
textCapitalizationTextCapitalizationكيف يتم تكبير الأحرفnone, words, sentences
keyboardAppearanceBrightness?لون لوحة المفاتيح (iOS)Brightness.dark
autofocusboolيبدأ الحقل بالتركيز تلقائيًاtrue / false
🔐 رابعًا: إخفاء النص وكلمات المرور
الخاصيةالنوعالوصفالقيم
obscureTextboolإخفاء الأحرف (كلمة مرور)true / false
obscuringCharacterStringالحرف المستخدم للإخفاء'•', '*'
enableSuggestionsboolتمكين اقتراحات الكيبوردtrue / false
autocorrectboolتمكين التصحيح التلقائيtrue / false
📏 خامسًا: طول وعدد الأسطر
الخاصيةالنوعالشرحالقيم
maxLengthint?الحد الأقصى للحروف50
minLinesint?أقل عدد أسطر1
maxLinesint?أكبر عدد أسطر1, null للمفتوح
expandsboolيملأ المساحة المتاحةtrue / false
🧾 سادسًا: التحقق والحفظ (الفارق الأكبر عن TextField!)
الخاصيةالنوعالشرحمثال
validatorString? Function(String?)?التحقق من صحة الإدخال (يعيد نص الخطأ إن وجد)if(value!.isEmpty) return 'مطلوب';
onSavedvoid Function(String?)?حفظ القيمة بعد تحققها(value) => userName = value!
autovalidateModeAutovalidateModeمتى يتم التحقق تلقائيًاdisabled, always, onUserInteraction
⚡ سابعًا: الأحداث (callbacks)
الخاصيةالنوعالوصف
onChangedValueChanged<String>?يستدعى عند كل تغيير للنص
onFieldSubmittedValueChanged<String>?عند الضغط على زر الإدخال (done)
onEditingCompleteVoidCallback?عند انتهاء التحرير
onTapVoidCallback?عند النقر على الحقل
🧰 ثامنًا: أدوات إضافية للتحكم والسلوك
الخاصيةالنوعالوصف
inputFormattersList<TextInputFormatter>?تحديد شكل النص المدخل (أرقام فقط، إلخ)
enableInteractiveSelectionboolتمكين تحديد/نسخ النص
scrollPaddingEdgeInsetsالمساحة لتفادي تغطية الكيبورد للحقل
autofillHintsIterable<String>?تلميحات للملء التلقائي (Email، Password…)
🎨 الخصائص الأهم في InputDecoration
الخاصيةالشرحمثال
labelTextالنص فوق الحقل'البريد الإلكتروني'
hintTextنص التلميح داخل الحقل'أدخل بريدك'
helperTextنص مساعد تحت الحقل'يجب أن يكون بريد صالح'
errorTextنص الخطأ'بريد غير صالح'
prefixIconأيقونة داخل الحقل يسارًاIcon(Icons.email)
suffixIconأيقونة يمين الحقلIcon(Icons.clear)
borderنوع الحدودOutlineInputBorder()
filled / fillColorتعبئة خلفية الحقلtrue, Colors.grey[200]
isDenseيجعل الحقل أقل ارتفاعًاtrue
contentPaddingالمسافة داخل الحقلEdgeInsets.all(8)
💡 أمثلة عملية
🧍‍♂️ مثال 1: حقل بسيط داخل Form مع التحقق
final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: Column(
    children: [
      TextFormField(
        decoration: InputDecoration(
          labelText: 'الاسم الكامل',
          prefixIcon: Icon(Icons.person),
          border: OutlineInputBorder(),
        ),
        validator: (value) {
          if (value == null || value.isEmpty) return 'الاسم مطلوب';
          if (value.length < 3) return 'الاسم قصير جدًا';
          return null;
        },
        onSaved: (value) {
          print('تم حفظ الاسم: $value');
        },
      ),
      SizedBox(height: 16),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            _formKey.currentState!.save();
          }
        },
        child: Text('إرسال'),
      ),
    ],
  ),
)
PHP

🔒 مثال 2: حقل كلمة مرور مع زر إظهار/إخفاء
class PasswordField extends StatefulWidget {
  @override
  _PasswordFieldState createState() => _PasswordFieldState();
}

class _PasswordFieldState extends State<PasswordField> {
  bool _obscure = true;

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      obscureText: _obscure,
      decoration: InputDecoration(
        labelText: 'كلمة المرور',
        prefixIcon: Icon(Icons.lock),
        suffixIcon: IconButton(
          icon: Icon(_obscure ? Icons.visibility : Icons.visibility_off),
          onPressed: () => setState(() => _obscure = !_obscure),
        ),
        border: OutlineInputBorder(),
      ),
      validator: (value) {
        if (value == null || value.isEmpty) return 'كلمة المرور مطلوبة';
        if (value.length < 6) return 'كلمة المرور قصيرة جدًا';
        return null;
      },
    );
  }
}
PHP

🔢 مثال 3: حقل رقم الهاتف (أرقام فقط + طول محدد)
TextFormField(
  keyboardType: TextInputType.phone,
  inputFormatters: [
    FilteringTextInputFormatter.digitsOnly,
    LengthLimitingTextInputFormatter(10),
  ],
  decoration: InputDecoration(
    labelText: 'رقم الهاتف',
    prefixIcon: Icon(Icons.phone),
    border: OutlineInputBorder(),
  ),
  validator: (value) {
    if (value == null || value.isEmpty) return 'الرقم مطلوب';
    if (value.length < 10) return 'الرقم غير مكتمل';
    return null;
  },
)
PHP
🧠 ملاحظات احترافية

✅ استخدم autovalidateMode: AutovalidateMode.onUserInteraction لتفعيل التحقق فورًا عند التعديل.
✅ لا تستخدم initialValue مع controller.
✅ يمكنك الوصول لقيمة الحقل من controller.text.
✅ استخدم ThemeData.inputDecorationTheme لتغيير مظهر كل الحقول دفعة واحدة.
✅ يفضل دائمًا داخل Form وضع كل TextFormField مع FormState للتحقق الشامل.