NSTextAttachment: ما هو وكيفية إضافة صورة إلى النص في iOS

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

NSTextAttachment هي فئة من إطار UIKit تتيح تضمين الصور والكائنات الوسائط الأخرى في النص المنسق من خلال NSAttributedString. تعمل على مستوى TextKit و Core Text، مما يمنح المطورين التحكم في حجم وموضع وسلوك المرفقات داخل تدفق النص. وفقًا لـ Apple Documentation (2025)، يدعم NSTextAttachment الصور و PDF وحاويات العرض المخصصة، متكاملًا مع UITextView و UILabel. فهم هذه API ضروري لإنشاء Rich Text في تطبيقات iOS — من الدردشات والمحررات إلى خلاصات الأخبار مع أيقونات في التسميات التوضيحية.

النقاط الرئيسية

  • NSTextAttachment هي فئة من UIKit لتضمين الوسائط في النص المنسق في iOS.
  • تتم إضافة الصورة من خلال NSAttributedString باستخدام المفتاح NSAttachmentAttributeName.
  • الخاصية bounds تتحكم في حجم والإزاحة الرأسية للمرفق.
  • يدعم NSTextAttachment الصور و PDF والملفات المخصصة عبر حاوية بيانات.
  • تتكامل API مع UITextView و UILabel و TextKit لتخطيط نص مرن.

ما هو NSTextAttachment؟

NSTextAttachment هي فئة من إطار UIKit تتيح تضمين الكائنات الوسائط مباشرة في محتوى النص لـ NSAttributedString. على عكس UIImageView منفصل يوضع بجانب النص، يجعل NSTextAttachment الصورة جزءًا من تدفق النص: تنتقل الصورة مع الأسطر، وتشارك في المحاذاة، وتشغل مساحة مثل حرف عادي.

هذه الفئة هي جزء من بنية TextKit، التي تدير عرض النص على iOS و macOS. يقسم TextKit النص إلى حروف رسومية، مع مراعاة تقنين الأحرف والربط والمسافة بين الأسطر — ويندرج NSTextAttachment في هذا الخط كحرف خاص يُعرض ليس كحرف بل ككائن رسومي.

كل مثيل من NSTextAttachment يحتوي على contents (بيانات الملف)، fileType (نوع محتوى UTI)، و bounds (مستطيل بالنقاط يحدد الحجم والموضع). وفقًا لـ Apple Human Interface Guidelines، فإن bounds افتراضيًا هو حجم الصورة، ولكن يمكن تغييره لضبط دقيق مع الخط.

استخدم NSTextAttachment بدلاً من UIImageView منفصل عندما يجب أن تتصرف الصورة كجزء من النص — في الدردشات وخلاصات الأخبار ومحررات النصوص والنماذج ذات الأيقونات في حقول الإدخال.

كيفية إضافة صورة إلى النص عبر NSTextAttachment

يتكون سير العمل الأساسي مع NSTextAttachment من ثلاث خطوات: إنشاء مثيل، تعيين الصورة، وإرفاقها بـ NSAttributedString. دعونا نلقي نظرة على العملية باستخدام Swift.

swift
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "icon-star")

let attachmentString = NSAttributedString(attachment: attachment)

let text = NSMutableAttributedString(string: "Rating: ")
text.append(attachmentString)

let label = UILabel()
label.attributedText = text

بعد استدعاء NSAttributedString(attachment:)، يتم تحويل كائن NSTextAttachment إلى السمة NSAttachmentAttributeName، التي تُرفق بحرف استبدال كائن خاص (رمز 0xFFFC). لا يُعرض هذا الحرف كحرف — بدلاً من ذلك، تُرسم الصورة من خاصية image في مكانه.

إذا كان يجب وضع الصورة في منتصف سطر النص (على سبيل المثال، أيقونة بعد كلمة)، فما عليك سوى إدراج attachmentString في الموضع المطلوب في NSMutableAttributedString. سيقوم TextKit تلقائيًا بمراعاة ارتفاع السطر ومحاذاة الصورة مع خط الأساس.

هام: الخاصية image متاحة فقط على iOS (منذ iOS 7). على macOS، استخدم الخاصية contents مع NSImage. للتوافق مع الإصدارات السابقة، فضل دائمًا تعيين image مباشرة بدلاً من الاعتماد على حاوية البيانات.

ضبط bounds وموضع المرفق

افتراضيًا، يعرض NSTextAttachment الصورة بحجمها الأصلي بالنقاط. عمليًا، تحتاج دائمًا تقريبًا إلى ضبط الحجم والموضع الرأسي — ويتم ذلك باستخدام الخاصية bounds.

هيكل CGRect bounds يشمل origin (الإزاحة في X و Y) و size (العرض والارتفاع). إزاحة Y مهمة بشكل خاص: القيمة السالبة تخفض الصورة أسفل خط الأساس، والقيمة الموجبة ترفعها. السيناريو النموذجي هو محاذاة أيقونة إلى وسط سطر النص.

swift
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "icon-star")

let font = UIFont.systemFont(ofSize: 16)
let fontCapHeight = font.capHeight
let imageSize = CGSize(width: 18, height: 18)

attachment.bounds = CGRect(
    x: 0,
    y: (fontCapHeight - imageSize.height) / 2,
    width: imageSize.width,
    height: imageSize.height
)

يستخدم حساب المحاذاة capHeight للخط — ارتفاع الحرف الكبير، وليس الارتفاع الكامل للسطر. يضمن ذلك تطابق الأيقونة بصريًا مع الحافة العلوية للنص بدلاً من الطفو بين خط الأساس والصاعد. حجم الصورة في المثال هو 18×18 نقطة، وهو نموذجي للأيقونات في نص واجهة المستخدم.

إذا كان يجب أن تكون الصورة أكبر من سطر النص (على سبيل المثال، معاينة صورة في دردشة)، سيزيد TextKit تلقائيًا تباعد الأسطر للسطر الحالي. في هذه الحالة، يجب ضبط bounds على الحجم الطبيعي وإزاحة Y على صفر.

PDF والمرفقات المخصصة

يدعم NSTextAttachment ليس فقط PNG و JPEG ولكن أيضًا مستندات PDF، بالإضافة إلى الملفات التعسفية من خلال الخاصية contents. هذا يجعله أداة عالمية لـ Rich Text في تطبيقات iOS.

عند تعيين صورة PDF إلى attachment.image، يقوم النظام تلقائيًا بعرض الصفحة الأولى من المستند. ومع ذلك، للعرض الدقيق، استخدم البيانات مباشرة من خلال المُهيئ مع البيانات ونوع UTI:

swift
guard let pdfData = Bundle.main.url(forResource: "document",
                                  withExtension: "pdf") else { return }

let fileData = Data(contentsOf: pdfData)
let attachment = NSTextAttachment(data: fileData,
                                       ofType: "com.adobe.pdf")

attachment.bounds = CGRect(x: 0, y: -4,
                           width: 24, height: 24)

let pdfString = NSAttributedString(attachment: attachment)

يقبل المعامل ofType سلسلة UTI (Uniform Type Identifier). تشمل الأنواع القياسية: public.image (أي صورة)، public.jpeg، public.png، com.adobe.pdf. عند تحديد UTI الصحيح، يختار النظام طريقة العرض المناسبة — لـ PDF هي CGPDFDocument، وللصور هي CGImageSource.

لأنواع الملفات المخصصة (على سبيل المثال، الرسومات المتجهة بتنسيق SVG)، ستحتاج إلى فئة فرعية من NSTextAttachment تعيد تعريف طريقة image(forBounds:textContainer:characterIndex:). إذا كان العرض القياسي غير مناسب، قم بإرجاع nil وقم بتنفيذ الرسم عبر Core Graphics في طريقة draw.

NSTextAttachment في UITextView والتفويض

يعمل NSTextAttachment بشكل صحيح في كل من UILabel و UITextView. ومع ذلك، يوفر UITextView إمكانيات أكثر: التفاعل مع المرفقات (النقر على أيقونة)، تحرير النص مع الصور، ودعم NSAttachmentBehavior.

لمعالجة النقر على NSTextAttachment في UITextView، استخدم بروتوكول UITextViewDelegate وطريقة textView(_:shouldInteractWith:in:interaction:). يتم استدعاء هذه الطريقة عندما ينقر المستخدم على مرفق وتسمح بالانتقال إلى شاشة أو فتح نافذة منبثقة أو تشغيل رسم متحرك.

swift
func textView(_ textView: UITextView,
                shouldInteractWith attachment: NSTextAttachment,
                in characterRange: NSRange,
                interaction: UITextItemInteraction) -> Bool {
    if interaction == .preview {
        return false
    }
    // فتح شاشة التفاصيل
    showImageDetail(attachment.image)
    return false
}

تميز الطريقة أنواع التفاعل من خلال معامل interaction: .preview (3D Touch / Haptic Touch)، .default (نقرة عادية)، و.presentActions (قائمة سياقية). لكل نوع، يمكنك تحديد سلوكه الخاص أو تعطيله بإرجاع false.

عند تحرير UITextView مع NSTextAttachment، من المهم تذكر: حذف حرف الاستبدال (0xFFFC) يحذف أيضًا المرفق. يرى المستخدم الصورة كعنصر واحد — يتم تحديدها ككل، وليس بكسل بكسل. لدعم السحب والإفلات للمرفقات في iOS 15+، استخدم NSTextAttachmentViewProvider.

الأخطاء الشائعة عند العمل مع NSTextAttachment

الخطأ الشائع الأول هو تجاهل bounds. غالبًا ما يعتمد المطورون على الحجم الأصلي للصورة، مما يؤدي إلى أيقونات عملاقة في النص أو، على العكس، صور بالكاد تُرى. قم دائمًا بتعيين bounds بشكل صريح مع مراعاة الخط والسياق.

الخطأ الثاني هو إزاحة Y غير صحيحة. القيمة الموجبة في bounds.origin.y تخفض الصورة (في نظام إحداثيات UIKit، يتجه المحور Y للأسفل — يبدو هذا غير منطقي، ولكن هكذا يعمل Core Graphics). للمحاذاة في وسط السطر، استخدم الصيغة مع capHeight للخط كما هو موضح في القسم 3.

المشكلة الثالثة هي فقدان الصورة عند تغيير traitCollection. عندما يبدل المستخدم الوضع الداكن أو Dynamic Type، قد يتغير حجم الخط، لكن bounds تبقى كما هي. الحل هو حساب bounds ديناميكيًا في طريقة layoutSubviews أو عبر KVO على font.

الخطأ الرابع المتكرر هو استخدام NSTextAttachment في UILabel مع numberOfLines > 1. في وضع متعدد الأسطر مع عرض محدود، يقوم TextKit بشكل صحيح بلف الأسطر مع الصورة. تنشأ المشكلة عندما يتجاوز ارتفاع المرفق ارتفاع السطر — تتداخل الأسطر المجاورة مع بعضها. الحل هو زيادة lineSpacing عبر NSMutableParagraphStyle.

الأسئلة المتكررة

ما الفرق بين NSTextAttachment و UIImageView في النص؟

NSTextAttachment يجعل الصورة جزءًا من تدفق النص: تنتقل وتتم محاذاتها وتتدرج مع النص. UIImageView مرتبط بإحداثيات العرض الفائق ولا يشارك في تخطيط النص.

هل يمكن إضافة NSTextAttachment إلى UILabel؟

نعم، إذا قمت بتعيين الخاصية attributedText بدلاً من text. يعرض UILabel بشكل صحيح NSTextAttachment ولكنه لا يدعم التفاعل. للنقر على المرفق، استخدم UITextView.

كيف يمكن تغيير حجم الصورة بعد إنشاء المرفق؟

قم بتغيير الخاصية bounds للمثيل الحالي من NSTextAttachment. سيتم إعادة عرض النص تلقائيًا بالأحجام الجديدة دون الحاجة لإنشاء NSAttributedString جديد.

هل يدعم NSTextAttachment الصور المتحركة؟

NSTextAttachment يدعم الصور الثابتة. بالنسبة لـ GIF والتنسيقات المتحركة، يلزم تطبيق مخصص عبر NSTextAttachmentViewProvider على iOS 15+ أو عبر CADisplayLink.

كيف يمكن إضافة NSTextAttachment إلى النص برمجيًا؟

قم بإنشاء مثيل NSTextAttachment، وضبط الصورة أو البيانات، وتعيين bounds، ولفه في NSAttributedString(attachment:)، وإدراجه في NSMutableAttributedString باستخدام طريقة insert(_:at:).

الخلاصة

  • NSTextAttachment هي فئة من UIKit لتضمين الصور و PDF والوسائط الأخرى في النص المنسق.
  • تتم إضافة الصورة عبر NSAttributedString(attachment:) وتصبح جزءًا من تدفق النص.
  • الخاصية bounds تتحكم في الحجم والموضع: قم دائمًا بتعيينها بشكل صريح مع مراعاة الخط.
  • لمحاذاة أيقونة في وسط السطر، استخدم الصيغة مع capHeight للخط الحالي.
  • مرفقات PDF مدعومة عبر المُهيئ مع data ونوع UTI الصحيح.
  • لمعالجة النقر على المرفقات، استخدم UITextViewDelegate وطريقة shouldInteractWith.
  • عند تغيير Dynamic Type، أعد حساب bounds ديناميكيًا لتجنب تداخل الأسطر.

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

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

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

اقرأ أيضًا