UITextView: ما هو، الإدخال متعدد الأسطر ومبدأ العمل

المؤلف: IT Sectr نُشر: 2026-07-07 وقت القراءة: 8 دق

UITextView هو مكون نص متعدد الأسطر في UIKit، يرث من UIScrollView ويدعم تحرير النص المنسق مع تضمين الروابط والصور. وفقاً لوثائق Apple Developer (2025)، يوفر UITextView بروتوكول UITextViewDelegate مع استدعاءات textViewDidChange وshouldInteractWithURL وshouldInteractWithTextAttachment لمعالجة التفاعلات. على عكس UITextField، يدعم UITextView التمرير وأنماط النص عبر typingAttributes وdataDetectorTypes للكشف التلقائي عن الروابط والعناوين والتواريخ. هذا هو المكون الرئيسي لعرض المحتوى وإدخال النص متعدد الأسطر في تطبيقات iOS.

الخلاصة

  • UITextView — حقل نص متعدد الأسطر في UIKit، يرث UIScrollView مع دعم التحرير
  • NSAttributedString — دعم النص المنسق: الخطوط والألوان وتباعد الأسطر والروابط
  • UITextViewDelegate — الإدارة عبر textViewDidChange وshouldInteractWithURL وdidBeginEditing
  • Data Detector Types — الكشف التلقائي عن الروابط والعناوين والتواريخ وأرقام الهواتف
  • Text Container — نظام textContainer وexclusionPaths وlineFragmentPadding للتخطيط المخصص

ما هو UITextView

UITextView هو مكون UIKit مصمم لعرض وتحرير النص متعدد الأسطر. على عكس UILabel، يدعم UITextView تحديد النص والتحرير والتمرير عندما يتجاوز المحتوى الحجم والنص المنسق. بكونه فئة فرعية من UIScrollView، يشمل UITextView تلقائياً التمرير الرأسي والأفقي عندما يفيض المحتوى — يتم تكوين ذلك عبر isScrollEnabled. تدعم الفئة التحرير من خلال الخاصية isEditable: اضبطها على false لوضع العرض للقراءة فقط. يعمل UITextView مع NSLayoutManager عبر نظام TextKit: NSTextStorage (تخزين النص المنسق) → NSLayoutManager (تخطيط الأسطر) → NSTextContainer (هندسة منطقة النص). تسمح هذه البنية بالتخطيطات المخصصة مع التفاف الصور والنص متعدد الأعمدة وتخطيطات النص المعقدة. يُستخدم UITextView لعرض المقالات والوصف والسجلات والتعليقات وأي نصوص متعددة الأسطر في iOS.

UITextView مقابل UITextField: الاختلافات الرئيسية

الفرق بين UITextView وUITextField يتجاوز بكثير عدد الأسطر. UITextField هو UIControl أحادي السطر مع دعم placeholder وعرض يسار/يمين وزر مسح. UITextView هو UIScrollView متعدد الأسطر مع نظام TextKit كامل للنص المنسق. لا يدعم UITextField NSAttributedString على مستوى العرض (فقط عبر attributedText مع قيود)، بينما يتعامل UITextView مع NSAttributedString بالكامل بخطوط مختلفة وأنماط فقرة وصور مضمنة. يحتوي UITextField على زر مسح مدمج (clearButtonMode)، بينما لا يحتوي UITextView على ذلك — يلزم تنفيذ مخصص. يتغير حجم UITextField تلقائياً ليتناسب مع المحتوى (intrinsicContentSize)، ويتطلب UITextView إدارة يدوية للارتفاع عبر مراقبة contentSize أو قيود Auto Layout. يدعم UITextView dataDetectorTypes (الكشف التلقائي عن الروابط)، ويدعمه UITextField منذ iOS 16+. لإدخال النص متعدد الأسطر (التعليقات والملاحظات والرسائل) اختر UITextView. لحقول النموذج (الاسم والبريد الإلكتروني وكلمة المرور) استخدم UITextField.

الميزةUITextViewUITextField
الأسطرمتعدد الأسطرأحادي السطر
Placeholderلا (مخصص)مدمج
سمات النصNSAttributedString كاملمحدود
Data Detectorsدعم كاملiOS 16+
الصور المضمنةعبر NSTextAttachmentغير مدعوم
التمريرمدمج (UIScrollView)لا
عرض يسار/يمينلامدمج

NSAttributedString وتنسيق النص

NSAttributedString هي إمكانية أساسية في UITextView تميزه عن UITextField وUILabel. السلسلة المنسقة تسمح بتعيين خطوط وألوان وتباعد أسطر ومحاذاة وروابط مختلفة ضمن نص واحد. الخصائص: textView.attributedText = attributedString. السمات الرئيسية لـ NSAttributedString.Key: font (.systemFont, .boldSystemFont, UIFont مخصص)، foregroundColor، backgroundColor، paragraphStyle (NSMutableParagraphStyle مع lineSpacing وalignment وlineBreakMode)، link (URL للروابط التفاعلية)، underlineStyle، strikethroughStyle، shadow، baselineOffset، kern (تباعد الأحرف). لإنشاء attributedString استخدم init(string:, attributes:) أو NSMutableAttributedString لإضافة سمات إلى نطاقات مختلفة. يعرض UITextView تلقائياً الروابط (سمة link) كروابط تفاعلية — يؤدي الضغط عليها إلى تشغيل طريقة المفوض shouldInteractWithURL. لإعادة تعيين السمات للإدخال الجديد استخدم typingAttributes.

swift
import UIKit

let textView = UITextView()
textView.isEditable = false
textView.isScrollEnabled = true
textView.dataDetectorTypes = [.link, .phoneNumber]

let attributedString = NSMutableAttributedString(
    string: "Visit our website or call +1-800-555-0199"
)
attributedString.addAttributes([
    .font: UIFont.systemFont(ofSize: 16),
    .foregroundColor: UIColor.label,
], range: NSRange(location: 0, length: 11))

let linkRange = (attributedString.string as NSString)
    .range(of: "website")
attributedString.addAttributes([
    .link: URL(string: "https://example.com")!,
    .foregroundColor: UIColor.systemBlue,
], range: linkRange)

textView.attributedText = attributedString

UITextViewDelegate ومعالجة الروابط

UITextViewDelegate هو بروتوكول يدير التحرير والتفاعل مع النص. الطرق الرئيسية: textViewDidBeginEditing(textView) — يُستدعى عند بدء التحرير؛ textViewDidEndEditing — عند انتهاء التحرير؛ textViewDidChange — عند كل تغيير في النص؛ textViewDidChangeSelection — عند تغيير التحديد؛ textViewShouldInteractWithURL — عند النقر على رابط (يعيد Bool، يسمح بالانتقال)؛ textViewShouldInteractWithTextAttachment — عند النقر على صورة مضمنة. لمعالجة الروابط داخل UITextView تجاوز shouldInteractWithURL — يمكنك فيه: فتح URL في SFSafariViewController، عرض UIAlertController للتأكيد، معالجة مخططات URL المخصصة. مهم: إذا كان textView.isEditable = true، تصبح الروابط غير متاحة للنقرة الواحدة — يلزم النقر المزدوج. للروابط التفاعلية في textView قابل للتحرير استخدم gesture recognizers.

معالجة الروابط عبر SFSafariViewController

SFSafariViewController هي الطريقة القياسية لفتح الروابط في تطبيقات iOS. في طريقة shouldInteractWithURL أنشئ SFSafariViewController مع URL واعرضه بشكل مشروط أو عبر navigationController. للروابط العامة استخدم UIApplication.shared.open(url, options) — لكن هذا يخرج من التطبيق. لمنع فتح الرابط أعد false في shouldInteractWithURL وتعامل مع URL بنفسك.

نظام Text Container: الهوامش وExclusion Paths

NSTextContainer هو جزء من بنية TextKit، يحدد المنطقة الهندسية حيث يتم عرض نص UITextView. كل UITextView لديه textContainer قياسي، قابل للتكوين عبر: textView.textContainerInset — هوامش النص من حواف textView (UIEdgeInsets)؛ textView.textContainer.lineFragmentPadding — الحشو الأفقي داخل كل سطر؛ textView.textContainer.maximumNumberOfLines — حد الأسطر (0 = بدون حد)؛ textView.textContainer.exclusionPaths — مصفوفة UIBezierPath للمناطق التي يجب أن يلتف النص حولها (الصور والأشكال المخصصة). تسمح ExclusionPaths بتخطيطات معقدة: يلتف النص حول صورة ملف شخصي دائرية أو أيقونة أو أي شكل عشوائي. للارتفاع الديناميكي لـ UITextView راقب contentSize عبر KVO أو المفوض وقم بتحديث القيود.

swift
// Dynamic UITextView height via contentSize
func textViewDidChange(textView: UITextView) {
    let fixedWidth = textView.frame.size.width
    let newSize = textView.sizeThatFits(
        CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude)
    )
    heightConstraint.constant = newSize.height
    UIView.animate(withDuration: 0.1) {
        self.view.layoutIfNeeded()
    }
}

// ExclusionPath for image wrapping
let imageFrame = CGRect(x: 16, y: 100, width: 80, height: 80)
let exclusionPath = UIBezierPath(rect: imageFrame)
textView.textContainer.exclusionPaths = [exclusionPath]

Data Detector Types: الكشف التلقائي

dataDetectorTypes هي خاصية UITextView تتعرف تلقائياً وتجعل أنواعاً معينة من البيانات تفاعلية في النص: .link (URL، بريد إلكتروني)، .phoneNumber (أرقام الهواتف)، .address (عناوين)، .calendarEvent (تواريخ وأحداث)، .flightNumber (أرقام رحلات)، .lookupSuggestion (اقتراحات بحث)، .trackingNumber (أرقام تتبع)، .money (مبالغ)، .shipmentTrackingNumber، .all (جميع الأنواع). يعمل Data Detector مع NSDataDetector وURL، مسلطاً الضوء تلقائياً على البيانات المكتشفة. لتخصيص المعالجة قم بتعيين dataDetectorTypes وتجاوز shouldInteractWithURL في المفوض. مهم: يعمل dataDetectorTypes فقط لـ URL وphoneNumber بدون إعداد إضافي — قد تتطلب الأنواع الأخرى iOS 16+. لا يتعارض Data Detector مع سمة link في NSAttributedString — تعمل كلتا الآليتين بالتوازي. لـ UITextView للقراءة فقط مع محتوى (أخبار، مقالات) قم بتعيين dataDetectorTypes = [.link, .phoneNumber].

  • .link — عناوين URL والبريد الإلكتروني؛ تظهر كروابط زرقاء
  • .phoneNumber — أرقام الهواتف؛ النقر يعرض إجراء الاتصال
  • .address — عناوين بريدية؛ النقر يفتح Maps
  • .calendarEvent — تواريخ وأوقات؛ النقر ينشئ حدث تقويم
  • .flightNumber — أرقام رحلات (iOS 16+)؛ فحص سريع للرحلة

أمثلة برمجية مع UITextView

لننظر إلى مثالين عمليين لاستخدام UITextView في تطبيقات iOS. الأول — عرض نص للقراءة فقط مع نص منسق وكاشف بيانات لعرض المحتوى. الثاني — عرض نص قابل للتحرير مع placeholder كسول وارتفاع ديناميكي لنموذج تعليق. يستخدم كلا المثالين أفضل ممارسات UIKit: بروتوكول المفوض وAuto Layout وTextKit.

UITextView للقراءة فقط مع محتوى وروابط

يتم تمكين وضع القراءة فقط بتعيين isEditable = false وisSelectable = true. يتيح ذلك للمستخدم تحديد النص والنقر على الروابط، ولكن ليس التحرير. قم بتعيين dataDetectorTypes للكشف التلقائي عن الروابط، backgroundColor = .clear لخلفية شفافة. للمحتوى الطويل استخدم attributedText مع NSMutableParagraphStyle lineSpacing لسهولة القراءة. أضف سمات link للروابط الرئيسية داخل النص.

swift
import UIKit

class ArticleViewController: UIViewController {
    let contentView = UITextView()

    override func viewDidLoad() {
        super.viewDidLoad()
        contentView.isEditable = false
        contentView.isSelectable = true
        contentView.dataDetectorTypes = [.link, .phoneNumber]
        contentView.backgroundColor = .clear
        contentView.textContainerInset = UIEdgeInsets(
            top: 8, left: 16,
            bottom: 8, right: 16
        )
        contentView.delegate = self
        loadArticleContent()
    }

    func loadArticleContent() {
        guard let url = URL(string: "https://example.com/article")
        else { return }
        // Load content from URL and set attributedText
    }
}

UITextView قابل للتحرير مع Placeholder

Placeholder لـ UITextView غير مدمج — قم بتنفيذه عبر UILabel فوق textView أو عبر attributedText مع فحص isEmpty. نهج بسيط: UILabel بنص رمادي يختفي عند بدء التحرير. في textViewDidChange تحقق من وجود النص وأخفِ/أظهر placeholder. لحل أكثر أناقة استخدم خاصية typingAttributes لتعيين لون نص الإدخال. يتم تحقيق الارتفاع الديناميكي للنص عبر مراقبة contentSize وتحديث القيود — هذا نمط قياسي للدردشات ونماذج التعليقات.

الأسئلة الشائعة

كيف أضيف placeholder إلى UITextView؟

UITextView ليس لديه placeholder مدمج. الحل القياسي: أضف UILabel بنص رمادي فوق textView. في textViewDidBeginEditing أخفِ التسمية، في textViewDidEndEditing أظهرها إذا كان النص فارغاً. بدلاً من ذلك: استخدم attributedText بلون رمادي كـ placeholder وأعد تعيينه عند بدء التحرير. للحل الجاهز استخدم مكتبة KMPlaceholderTextView أو ReactorKit.

كيف أزيل الهوامش في UITextView؟

اضبط textContainerInset = .zero وlineFragmentPadding = 0: textView.textContainerInset = UIEdgeInsets.zero; textView.textContainer.lineFragmentPadding = 0. إضافياً: textView.contentInset = .zero. سيزيل هذا الهوامش بالكامل من حواف textView إلى النص. ضع في اعتبارك أن lineFragmentPadding الافتراضي هو 5.

لماذا لا يفتح UITextView الروابط؟

تحقق من: isSelectable = true (ضروري للتفاعل)، dataDetectorTypes يتضمن .link، المفوض لا يعيد false في shouldInteractWithURL. إذا كان textView.isEditable = true، الروابط غير متاحة للنقرة الواحدة — يلزم النقر المزدوج. للروابط التفاعلية في textView قابل للتحرير أضف UITapGestureRecognizer فوق textView وتعامل مع URL يدوياً.

كيف أصنع UITextView بارتفاع ثابت مع تمرير؟

اضبط isScrollEnabled = true وأضف قيد ارتفاع بقيمة ثابتة. النص الذي يتجاوز الارتفاع سيتمرر. لتجربة مستخدم مثالية استخدم maxHeight: راقب contentSize واضبط قيد الارتفاع بما لا يتجاوز maxHeight. عند تجاوز maxHeight فعّل scrollEnabled. هذا نمط قياسي لحقول إدخال الرسائل والتعليقات.

كيف أدخل صورة في UITextView؟

استخدم NSTextAttachment: أنشئ كائناً، واضبط الصورة وbounds، ثم أنشئ NSAttributedString من المرفق وأدرجه في textView.attributedText. مثال: let attachment = NSTextAttachment(); attachment.image = image; attachment.bounds = CGRect(x, y, width, height); let attributedString = NSAttributedString(attachment: attachment). ستظهر الصورة بشكل مضمن في النص وستتمرر معه.

الملخص

  • UITextView — مكون نص متعدد الأسطر في UIKit، وراث UIScrollView مع دعم TextKit
  • NSAttributedString — إمكانية رئيسية لتنسيق الخطوط والألوان والروابط والفقرات
  • UITextViewDelegate — إدارة التحرير ومعالجة النقرات على الروابط والمرفقات
  • Data Detector Types — الكشف التلقائي عن URL والهواتف والعناوين والتواريخ عبر NSDataDetector
  • Text Container — نظام مع exclusionPaths وlineFragmentPadding وtextContainerInset للتخطيط
  • Placeholder — غير مدمج، يُنفذ عبر UILabel أو attributedText بلون رمادي
  • ارتفاع ديناميكي — مراقبة contentSize وتحديث القيود للارتفاع التلقائي
  • يختلف UITextView عن UITextField بدعمه للأسطر المتعددة والسمات والتمرير وكاشفات البيانات

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا