مقدمة: لماذا لا تغلق لوحة المفاتيح نفسها؟
\nمرحبًا، زميلي المطور! إذا سبق لك كتابة نموذج تسجيل دخول، أو شريط بحث، أو تطبيق مراسلة على iOS، فبالتأكيد واجهت موقفًا: أدخل المستخدم النص، لكن لوحة المفاتيح لا تزال عالقة على الشاشة. لم يتم الضغط على زر "تم"، ينقر المستخدم بإصبعه على مساحة فارغة، لكن لا يحدث شيء. كلاسيكي.
\n\nهذا أحد أكثر المواضيع شيوعًا على Stack Overflow، حيث حصد سؤال "Close iOS Keyboard by touching anywhere using Swift" آلاف المشاهدات. المشكلة ليست في صعوبة الأمر. المشكلة هي أن المبتدئين (وليس فقط) غالبًا ما يختارون طرقًا غير صحيحة أو "قذرة". دعنا نستعرض أهم 3 أخطاء، ثم ننظر إلى ثلاثة حلول صحيحة وعملية.
\n\nاليوم نتحدث عن Swift وUIKit. إذا كنت تستخدم SwiftUI — يمكنك الاطلاع أيضًا، المبادئ متشابهة.
\n\nالخطأ رقم 1: "إضافة TapGesture على كل شيء"
\nالخطأ الأكثر شيوعًا هو إضافة UITapGestureRecognizer إلى UIView، ولكن نسيان تعطيل cancelsTouchesInView. ونتيجة لذلك، تتوقف الأزرار والجداول عن الاستجابة للنقرات. ينقر المستخدم على زر "إرسال"، لكن يتم إغلاق لوحة المفاتيح بدلاً من إرسال النموذج.
مثال على الكود الخاطئ:
\noverride func viewDidLoad() {\n super.viewDidLoad()\n let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\n view.addGestureRecognizer(tap)\n}\n\n@objc func dismissKeyboard() {\n view.endEditing(true)\n}\n\nللوهلة الأولى — كل شيء على ما يرام. لكن عمليًا، إذا كان لديك UITableView أو UIButton، فقد يتم "ابتلاع" نقراتها بواسطة هذه الإيماءة. هذا ملحوظ بشكل خاص عند إضافة هذه الإيماءة إلى scrollView.
كيفية الإصلاح:
\nأضف السطر tap.cancelsTouchesInView = false. سيسمح هذا للعناصر الأخرى في الواجهة باستقبال أحداث اللمس.
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\ntap.cancelsTouchesInView = false\nview.addGestureRecognizer(tap)\n\nولكن حتى هذا ليس حلاً مثالياً إذا كان لديك واجهة معقدة.
\n\nالخطأ رقم 2: "النقر على مساحة فارغة يعطل الجدول"
\nالمشكلة الشائعة الثانية هي التفاعل غير الصحيح مع UIScrollView أو UITableView. إذا أضفت UITapGestureRecognizer إلى view التي تحتوي على جدول، فعند النقر على خلية قد يتم تفعيل كل من الإيماءة وطريقة didSelectRow في نفس الوقت. أو الأسوأ من ذلك، أن الإيماءة ستعترض اللمس، ولن يتم تمييز الخلية.
الحل: استخدم UIGestureRecognizerDelegate
\nقم بتنفيذ الطريقة gestureRecognizer(_:shouldReceive:) وتحقق مما إذا كان النقر قد وقع على حقل نصي أو عنصر آخر. إذا كان اللمس على UITextField أو UITextView — لا تمنع الإيماءة.
extension ViewController: UIGestureRecognizerDelegate {\n func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {\n // لا نعترض اللمسات إذا كانت على حقل نصي\n if touch.view is UITextField || touch.view is UITextView {\n return false\n }\n return true\n }\n}\n\nالآن ستعمل الإيماءة فقط عند النقر على المناطق الفارغة، بينما ستبقى الحقول النصية قابلة للتفاعل.
\n\nالخطأ رقم 3: "نسيان زر العودة من لوحة المفاتيح"
\nيقوم العديد من المطورين بتنفيذ الإغلاق عند النقر، لكنهم ينسون زر "Return" (Enter) على لوحة المفاتيح. قد يضغط المستخدم على "تم" ويتوقع إغلاق لوحة المفاتيح. إذا لم يتم ذلك — ستحصل على تجربة مستخدم سلبية.
\n\nكيفية الإصلاح:
\nقم بالاشتراك في بروتوكول UITextFieldDelegate ونفذ الطريقة textFieldShouldReturn:
class View