المكون Text في React Native

من موسوعة حسوب
مراجعة 14:02، 9 أكتوبر 2021 بواسطة جميل-بيلوني (نقاش | مساهمات)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

مكوّن React لعرض النصوص.

يدعم المكوّن ‎‎Text‎‎ النصوص المتداخلة والتنسيق ومعالجة اللمسات.

في المثال التالي، يرث العنوان المتداخل والنص الأساسي خاصيّة fontFamily من ‎‎styles.baseText‎‎، لكن العنوان يوفّر أنماطا إضافية خاصة به. سيتم تكديس العنوان والنص الأساسي فوق بعضهما البعض عند الوصول إلى محارف الأسطر الجديدة (literal newlines):

import React, { useState } from "react";
import { Text, StyleSheet } from "react-native";

const TextInANest = () => {
  const [titleText, setTitleText] = useState("Bird's Nest");
  const bodyText = "This is not really a bird nest.";

  const onPressTitle = () => {
    setTitleText("Bird's Nest [pressed]");
  };

  return (
    <Text style={styles.baseText}>
      <Text style={styles.titleText} onPress={onPressTitle}>
        {titleText}
        {"\n"}
        {"\n"}
      </Text>
      <Text numberOfLines={5}>{bodyText}</Text>
    </Text>
  );
};

const styles = StyleSheet.create({
  baseText: {
    fontFamily: "Cochin"
  },
  titleText: {
    fontSize: 20,
    fontWeight: "bold"
  }
});

export default TextInANest;
import React, { Component } from "react";
import { Text, StyleSheet } from "react-native";

class TextInANest extends Component {
  constructor(props) {
    super(props);
    this.state = {
      titleText: "Bird's Nest",
      bodyText: "This is not really a bird nest."
    };
  }

  onPressTitle = () => {
    this.setState({ titleText: "Bird's Nest [pressed]" });
  };

  render() {
    return (
      <Text style={styles.baseText}>
        <Text
          style={styles.titleText}
          onPress={this.onPressTitle}
        >
          {this.state.titleText}
          {"\n"}
          {"\n"}
        </Text>
        <Text numberOfLines={5}>{this.state.bodyText}</Text>
      </Text>
    );
  }
}

const styles = StyleSheet.create({
  baseText: {
    fontFamily: "Cochin"
  },
  titleText: {
    fontSize: 20,
    fontWeight: "bold"
  }
});

export default TextInANest;

النصوص المتداخلة

يتيح كل من نظامي iOS وAndroid عرض نص منسق عن طريق التعليق (annotating) على نطاقاتِ سلسلةٍ نصيّة بتنسيقات محددة لجعله نصًّا غامقًا أو ملونًا مثلًا (‎‎NSAttributedString‎‎ على iOS و‎‎SpannableString‎‎ على Android). عمليًّا، هذا شاق للغاية. في React Native، يُمكن استخدام صيغة الويب لهذا الغرض، حيث يمكنك تدخيل النص لتحقيق التأثير نفسه.

إليك المثال التالي (تجربة حية):

import React from 'react';
import { Text, StyleSheet } from 'react-native';

const BoldAndBeautiful = () => {
  return (
    <Text style={styles.baseText}>
      I am bold
      <Text style={styles.innerText}> and red</Text>
    </Text>
  );
};

const styles = StyleSheet.create({
  baseText: {
    fontWeight: 'bold'
  },
  innerText: {
    color: 'red'
  }
});

export default BoldAndBeautiful;

وراء الكواليس، يُحوِّل React Native هذا إلى سلسلة NSAttributedString نصيّة مسطحة أو سلسلة SpannableString نصيّة تحتوي على المعلومات التالية:

"I am bold and red"
0-9: bold
9-17: bold, red

الحاويات

عنصرُ ‎‎<Text>‎‎ فريدٌ (unique) بالنسبة إلى التخطيط (relative to layout): لم يعد كل شيء بداخله يستخدم تخطيط flexbox بل يستخدم تخطيط النص. هذا يعني أن العناصر الموجودة داخل عنصر ‎‎<Text>‎‎ لم تعد مستطيلة الشكل، ولكنها تلتف (wrap) عندما تصل إلى نهاية السطر.

<Text>
  <Text>First part and </Text>
  <Text>second part</Text>
</Text>
// Text حاوية
// سيكون النص في نفس السطر إن سمحت المساحة بذلك
// |First part and second part|

// إن نفِدَت المساحة، فسيتصرف النص وكأنه كتلة واحدة
// |First part |
// |and second |
// |part       |

<View>
  <Text>First part and </Text>
  <Text>second part</Text>
</View>

// View حاوية
// كل نصّ يُعدّ كتلة منفصلة

// |First part and|
// |second part   |

// إن نفِدَت المساحة، سيجري النص داخل كتلته الخاصة
// |First part |
// |and        |
// |second part|

وراثة أنماط محدودة

على الويب، الطريقة المعتادة لتعيين خطٍّ وحجم خطٍّ للمستند بأكمله هي الاستفادة من خصائص CSS الموروثة كما يلي:

html {
  font-family: 'lucida grande', tahoma, verdana, arial, sans-serif;
  font-size: 11px;
  color: #141823;
}

سوف ترث جميع العناصر الموجودة في المستند هذا الخط ما لم تُحدِّد هي (أي العناصر) أو أحد عناصرها الأجداد قاعدةً جديدة.

في React Native، الأمر أشدّ صرامة، إذ عليك تغليف جميع العقد النصية (text nodes) داخل مكوّن ‎‎<Text>‎‎. لا يمكن وضع عقدة نصية مباشرة أسفل مكوّن ‎‎<View>‎‎.

// سيرمي هذا خطأً، لا يمكن وضع عقدة نصية داخل المكون
// <View>
<View>
  Some text
</View>

// هذا هو الصواب
<View>
  <Text>
    Some text
  </Text>
</View>

ستفقد أيضًا القدرة على تعيين خطٍّ افتراضيّ لشجرة فرعية بالكامل. و الخاصيّة fontFamily لا تقبل سوى اسم خط واحد، وهذا مختلف عن الخاصية ‎‎font-family‎‎ في CSS. الطريقة الموصى بها لاستخدام خطوطٍ وأحجامٍ موحّدة عبر تطبيقك هي إنشاء مكوّن باسم ‎‎MyAppText‎‎ مثلًا يتضمن هذه الخاصيات واستخدام هذا المكون في تطبيقك. يمكنك أيضًا استخدام هذا المكون لإنشاء مكونات أكثر تحديدًا مثل مكوّنِ MyAppHeaderText لأنواع أخرى من النصوص.

<View>
  <MyAppText>
    Text styled with the default font for the entire application
  </MyAppText>
  <MyAppHeaderText>Text styled as a header</MyAppHeaderText>
</View>

بافتراض أن MyAppText مكونٌ لا يعرض سوى مكوناته الأبناء داخل مُكون Text مع تنسيق محدّد، فيمكن تعريف المكوّن MyAppHeaderText على النحو التالي:

class MyAppHeaderText extends Component {
  render() {
    return (
      <MyAppText>
        <Text style={{ fontSize: 20 }}>
          {this.props.children}
        </Text>
      </MyAppText>
    );
  }
}

تركيب المكوّن MyAppText بهذه الطريقة يضمن الحصول على الأنماط من أحد مكوّنات المستوى الأعلى، مع إمكانية تعديلها أو إضافة أنماط جديدة في حالات استخدامٍ محددة.

مفهوم وراثة الأنماط ما زال موجودًا في React Native، ولكنّه يقتصر على أشجار النصوص الفرعيّة (text subtrees). في هذه الحالة، سيكون الجزء الثاني غامقًا وأحمرًا:

<Text style={{fontWeight: 'bold'}}>
  I am bold
  <Text style={{color: 'red'}}>and red</Text>
</Text>

نعتقد أن هذه الطريقة الأكثر تقييدًا لتنسيق النصوص ستوفر تطبيقاتٍ أفضل:

  • (المطور) صُمِّمَت مكوّنات React مع أخذ العزل التام بعين الاعتبار: يجب أن تكون قادرًا على إسقاط مكون في أي مكان في تطبيقك، واثقًا من أنه طالما أن الخاصيّات متشابهة، فستبدو وتتصرف بنفس الطريقة. خصائص النصوص القادرة على الوراثة من خارج الخاصيات ستكسر هذا العزل.
  • (المُطبِّق [Implementor]) تطبيق شيفرة React Native تُبسَّط كذلك: لا نحتاج إلى حقلِ fontFamily في كل عنصرٍ، ولا نحتاج إلى عبور الشجرة إلى الجذر في كل مرة تُعرَض فيها عقدة نصية. لا تُشفَّر وراثة النمط إلا داخل مكون النص الأصيل ولا يُسرَّبُ إلى مُكوِّنات أخرى أو إلى النظام نفسه.

الخاصيات

‎‎accessible‎‎

عندما تكون قيمتُها القيمةَ ‎‎true‎‎ (القيمة الافتراضية)، فهذا يُشير إلى أنّ العرضَ هو عنصرُ سهل الوصول (accessibility element) لمن يملك أي إعاقة (سواءً دائمة أو مؤقتة). افتراضيًّا، جميع العناصر القابلة للمس هي عناصر مهيأة لتكون سهلة الوصول.

انظر دليل إمكانية الوصول لمزيد من المعلومات.

النوع مطلوب
قيمة منطقيّة لا

‎‎accessibilityLabel‎‎

يستبدِل النص الذي يقرأه قارئ الشاشة عندما يتفاعل المستخدم مع العنصر. افتراضيًا، يُنشأ الملصق (label) عن طريق العبور عبر جميع المكوّنات الأبناء وتجميع كافة العقد النصية مفصولةً بمسافة.

النوع مطلوب
سلسلة نصيّة لا

‎‎accessibilityHint‎‎

يُساعد تلميح سهولة الوصول (accessibility hint) المستخدمينَ على فهم ما سيحدث عندما يقومون بإجراءٍ على عنصر مهيئأة ليكون سهل الوصول عندما لا تكون النتيجة واضحةً من العنوان المساعد لسهولة الوصول accessibilityLabel.

النوع مطلوب
سلسلة نصيّة لا

‎‎accessibilityRole‎‎

تقوم الخاصيّة accessibilityRole بتوصيل الغرض من المكون (أي دَوره) إلى المستخدم عبر تقنيةٍ مساعدة (assistive technology) مثل قارئات الشاشة.

تترجم هذه الأدوار إلى تقنية Accessibility Traits المقابلة على نظام iOS. الزر Image يملك الوظيفة نفسها كما لو أن صفته (دوره) حُدِّد إلى 'image' أو 'button'. انظر دليل سهولة الوصول لمزيد من التفاصيل.

أما على نظام Android، فلهذه الأدوار قيمة مقابلة على تقنية TalkBack بالمثل كما في نظام iOS الذي تحدثنا عنه آنفًا.

النوع مطلوب
النوع accessibilityRole لا

‎‎accessibilityState‎‎

تحدد قيمة هذه الخاصية التقنيةٍ المساعدة مثل قارئ الشاشة بحالة العنصر المحدد (المركز) عليه آنذاك، ويمكنك أن لا تحدد أي حالة أو تحدد حالة واحدة أو عدة حالات بتمريرها عبر كائن مثل {selected: true, disabled: true}.

النوع مطلوب
AccessibilityState لا

‎‎adjustsFontSizeToFit‎‎

تُحدِّد ما إذا كان يجب تصغير الخطوط تلقائيًا لتناسب قيود النمط المُعطاة. القيمة الافتراضية false.

النوع مطلوب المنصة
قيمة منطقيّة لا iOS

‎‎allowFontScaling‎‎

لتحديد ما إذا كان يجب تغيير حجم الخطوط لاحترام إعدادات حجم النص الخاصة بإمكانية الوصول. القيمة الافتراضية هي ‎‎true‎‎.

النوع مطلوب
قيمة منطقيّة لا

android_hyphenationFrequency

تحدد تكرار عملية فصل الكلمات الأجنبية بفاصلة (شرطة - ) التلقائية لتُستخدَم متى ما سُمِح بفصل الكلمات الواحدة بفاصل على واجهة Android API المستوى 23 وما بعد. القيمة الافتراضية 'none'.

النوع مطلوب المنصة
('none', 'full', 'balanced', 'high') لا Android API Level 23+‎

‎‎dataDetectorType‎‎

يُحدِّد أنواع البيانات المحوَّلَة إلى عناوين URL قابلةٍ للنقر في عنصر النص. افتراضيًا، لا يتم اكتشاف أي أنواع بيانات.

يمكنك تحديد نوع واحد فقط.

القيم المحتملة للخاصيّة ‎‎dataDetectorType‎‎ موضحة بالجدول. القيمة الافتراضية 'none'.

النوع مطلوب المنصة
‎‎('phoneNumber', 'link', 'email', 'none', 'all')‎‎ لا Android

‎‎disabled‎‎

يُحدّد الحالة المعطلة لعرض النص لأغراض الاختبار. القيمة الافتراضية false.

النوع مطلوب المنصة
قيمة منطقيّة لا Android

‎‎ellipsizeMode‎‎

عندما تُعيَّن قيمة للخاصيّة ‎‎numberOfLines‎‎، فإنّ هذه الخاصيَّة تُحدِّد كيفية اقتطاع النص. يجب تعيين قيمة للخاصيّة numberOfLines بالتزامن مع هذه الخاصيّة.

يمكن أن تحمل أحد القيم التالية:

  • ‎‎head‎‎: يُعرَض السطر بحيث توضع النهاية في الحاوية ويتم الإشارة إلى النص المفقود في بداية السطر بواسطة علامة إضمار. أي ‎‎...wxyz‎‎ مثلا.
  • ‎‎middle‎‎: يُعرض السطر بحيث يتم احتواء البداية والنهاية في الحاوية ويتم الإشارة إلى النص المفقود في المنتصف بواسطة علامة إضمار. أي ‎‎ab...yz‎‎ مثلا.
  • ‎‎tail‎‎: (القيمة الافتراضية) يتم عرض السطر بحيث يتم احتواء البداية في الحاوية ويتم الإشارة إلى النص المفقود في نهاية السطر بواسطة علامة إضمار. أي ‎‎abcd...‎‎ مثلا.
  • ‎‎clip‎‎: لا يتم رسم الأسطر بعد حافة حاوية النص.

القيمة الافتراضيّة هي ‎‎tail‎‎.

إن ضبط قيمة الخاصة numberOfLines في نظام Android إلى قيمة أعلى من 1، فلن تعمل سوى القيمة 'tail' مع هذه الخاصية.

النوع مطلوب
‎‎('head', 'middle', 'tail', 'clip')‎‎ لا

‎‎maxFontSizeMultiplier‎‎

يُحدد أكبر مقياس ممكن يمكن أن يصل إليه الخط عند تمكين الخاصيّة ‎‎allowFontScaling‎‎. القيم الممكنة:

  • ‎‎null/undefined‎‎: (القيمة الافتراضية): ترث من العقدة الأب أو القيمة الافتراضيّة العامّة (‎‎0‎‎).
  • ‎‎0‎: لا حدَّ أقصى، وتَجاهَل قيمة الأب أو القيمة الافتراضية العامّة.
  • ‎‎>= 1‎: تُعيِّن قيمةَ الخاصيّةِ ‎‎maxFontSizeMultiplier‎‎ الخاصة بهذه العقدة إلى هذه القيمة.
النوع مطلوب
عدد لا

‎‎minimumFontScale‎‎

يُحدِّد أصغر مقياس ممكن يمكن أن يصل إليه الخط عند تمكين الخاصية ‎‎adjustsFontSizeToFit‎‎. (القيم من ‎‎0.01‎‎ إلى ‎‎1.0‎‎).

النوع مطلوب المنصة
عدد لا iOS

‎‎nativeID‎‎

تُستخدَم لتحديد موقع هذا العرض من الشيفرة الأصيلة.

النوع مطلوب
سلسلة نصيّة لا

‎‎numberOfLines‎‎

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

تُستخدم هذه الخاصيّة بشكل شائع مع الخاصية ‎‎ellipsizeMode‎‎. القيمة الافتراضية 0.

النوع مطلوب
عدد لا

‎‎onLayout‎‎

دالةٌ تُستدعى عند وصل العنصر (تصييره أول مرة) أو حدوث تغيّرات في التخطيط‎‎.

النوع مطلوب
دالة

‎({ nativeEvent: LayoutEvent }) => void

لا

‎‎onLongPress‎‎

تُستدعى هذه الدالة عند الضغط لفترة طويلة.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onMoveShouldSetResponder‎‎

هل هذا العرض "يتطلّب" الاستجابة للّمس (touch responsiveness)؟ تُستدعى هذه الدالة في كل حركة لمسٍ على المكوّن ‎‎View‎‎ عندما لا يكون المستجيب (the responder).

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onPress‎‎

تُستدعى هذه الدالة عند الضغط على العرض.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onResponderGrant‎‎

يستجيب العرض الآن لأحداث اللمس. هذا هو الوقت المناسب لإبراز وإظهار ما يحدث للمستخدم.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onResponderMove‎‎

عندما يُحرِّك المستخدمُ إصبعه.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onResponderRelease‎‎

دالةٌ تُستدعى عند نهاية اللمس.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onResponderTerminate‎‎

دالةٌ تُستدعى عندما يُأخَذ المستجيب من العرض. قد تأخذه عروض أخرى بعد استدعاء ‎‎onResponderTerminationRequest‎‎، أو قد يأخذه نظام التشغيل دون طلب (يحدث هذا مع مركز التحكم أو مركز التنبيهات على iOS مثلًا).

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onResponderTerminationRequest‎‎

دالة تُستدعى عندما يريد عرضٌ آخر أن يصبح مستجيبًا ويطلب من هذا العرض تحرير المستجيب الخاص به. إعادة القيمة ‎‎true‎‎ يسمح بإطلاقه.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onStartShouldSetResponderCapture‎‎

إذا أراد مُكوِّن ‎‎View‎‎ منع مُكوِّنِ ‎‎View‎‎ ابنٍ من أن يصبح مستجيبًا عند بداية اللمس، فيجب أن يحتويَ على هذا المعالج مُعيدًا القيمة ‎‎true‎‎.

النوع مطلوب
دالة

‎({ nativeEvent: PressEvent }) => void

لا

‎‎onTextLayout‎‎

تُستدعى عندما حدوث أي تغيير في تخطيط النص Text.

‎‎pressRetentionOffset‎‎

عند تعطيل واجهة التمرير (scroll view)، تُحدِّد هذه الخاصيّة مدى المسافة التي يمكن أن تتحرك بها اللمسة بعيدًا عن الزر قبل إلغاء تنشيطه. بمجرد إلغاء تنشيط الزر، حاول تحريك لمستك للخلف وسترى أن الزر قد نُشِّطَ مرة أخرى! حركه للخلف وللأمام عدة مرات أثناء تعطيل عرض التمرير. تأكد من تمرير ثابتٍ لتقليل تخصيصات الذاكرة.

النوع مطلوب
كائن Rect، عدد number لا

‎‎selectable‎‎

يتيح للمستخدم تحديد النص لاستخدام وظيفة النسخ واللصق الأصيلتين. القيمة الافتراضية false.

النوع مطلوب
قيمة منطقيّة لا

‎‎selectionColor‎‎

لون إبراز (highlight color) النص.

النوع مطلوب المنصة
لون لا Android

‎‎style‎‎

تنسيق النص.

النوع مطلوب
خاصيات تنسيق النص Text Style, خاصيات تنسيق الواجهة View Style Props لا

‎‎suppressHighlighting‎‎

عندما تكون قيمتها القيمةَ ‎‎true‎‎، لا يُجرى أي تغيير مرئي عند الضغط على النص. افتراضيًا، يُبرِز شكلٌ بيضاوي رمادي النصَّ عند الضغط لأسفل. القيمة الافتراضية false.

النوع مطلوب المنصة
قيمة منطقيّة لا iOS

‎‎testID‎‎

يُستخدَم لتحديد موقع هذا العرض في الاختبارات الشاملة (end-to-end tests).

النوع مطلوب
سلسلة نصيّة لا

‎‎textBreakStrategy‎‎

تضبط استراتيجية فاصل النص (text break) على المستوى 23 من واجهة برمجة تطبيقات Android أو أحدث، القيم المحتملة هي: ‎‎highQuality‎‎، ‎‎simple‎‎ (القيمة الافتراضية)، ‎‎balanced‎‎.

النوع مطلوب المنصة
‎‎('simple', 'highQuality', 'balanced')‎‎ لا Android

تعريفات النوع

TextLayout

الكائن TextLayout هو جزء من رد النداء TextLayoutEvent (مشروح تاليًا) ويحوي بيانات القياس لسطر النص Text.

إليك مثال:

{
    capHeight: 10.496,
    ascender: 14.624,
    descender: 4,
    width: 28.224,
    height: 18.624,
    xHeight: 6.048,
    x: 0,
    y: 0
}

الخاصيات:

الاسم النوع مطلوب الوصف
ascender عدد لا ارتفاع السطر الصاعد / المرتفع (line ascender height) بعد تغيير تخطيط النص.
capHeight عدد لا ارتفاع الحرف الكبير عن خط الأساس (baseline).
descender عدد لا ارتفاع النازل / المنخفض (line ascender height) بعد تغيير تخطيط النص.
height عدد لا ارتفاع السطر بعد تغيير تخطيط النص.
width عدد لا عرض السطر بعد تغيير تخطيط النص.
x عدد لا إحداثيات X للسطر ضمن مكون النص Text.
xHeight عدد لا المسافية بين الخط الأساس ومتوسط السطر (حجم الجزء الأساسي corpus size).
y عدد لا إحداثيات Y للسطر ضمن مكون النص Text.

TextLayoutEvent

يُعاد الكائن TextLayoutEvent من دالة رد نداء نتيجة حدوثٍ تغيير في تخطيط المكون، وتحوي مفتاحًا يدعى lines قيمته مصفوفة من كائنات TextLayout مقابلة لكل سطر جرى تصييره.

إليك مثال:

{
  lines: [
    TextLayout,
    TextLayout
    // ...
  ];
  target: 1127;
}

الخاصيات:

الاسم النوع مطلوب الوصف
lines مصفوفة من كائنات TextLayout لا يوفر معلومات عن تخطيط النص TextLayout لكل سطر جرى تصييره.
target عدد لا مُعرِّف العقدة للعنصر.

مصادر