משאב מחרוזות מספק מחרוזות טקסט לאפליקציה עם עיצוב ועיצוב טקסט אופציונליים. יש שלושה סוגי משאבים שיכולים לספק את האפליקציה באמצעות מחרוזות:
- String
- משאב XML שמספק מחרוזת יחידה.
- מערך מחרוזות
- משאב XML שמספק מערך של מחרוזות.
- מחרוזות כמות (Plurals)
- משאב XML שנושא מחרוזות שונות לצורך רבים.
כל המחרוזות יכולות להחיל חלק מתגי העיצוב והארגומנטים של העיצוב. עבור מידע על עיצוב ועיצוב מחרוזות, עיינו בקטע עיצוב ועיצוב.
מחרוזת
מחרוזת יחידה שאפשר ל��פנות אליה מהאפליקציה או מקובצי משאבים אחרים (כמו כפריסת XML).
הערה: מחרוזת היא משאב פשוט שיש הפניה אליו
באמצעות הערך שצוין במאפיין name
(לא השם של קובץ ה-XML). אפשר
לשלב משאבי מחרוזות עם משאבים פשוטים אחרים בקובץ XML יחיד,
תחת רכיב <resources>
אחד.
- מיקום הקובץ:
-
שם הקובץ שרירותי. המאפיין
name
של הרכיב<string>
משמש למזהה המשאב של הממשק. - סוג נתונים של משאב מקומפל:
- מצביע המשאב אל
String
. - הפניה למשאבים:
-
ב-Java:
R.string.string_name
ב-XML:@string/string_name
- תחביר:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- רכיבים:
- דוגמא:
- קובץ XML נשמר ב-
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
קובץ ה-XML של הפריסה מחיל מחרוזת על תצוגה מפורטת:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
קוד האפליקציה הזה מאחזר מחרוזת:
אפשר להשתמש ב-
getString(int)
אוgetText(int)
כדי לאחזר מחרוזת. כל עיצוב של טקסט עשיר שהוחל על המחרוזתgetText(int)
שומר.
res/values/filename.xml
בצבע מערך מחרוזות
מערך של מחרוזות שאפשר להפנות אליהן מהאפליקציה.
הערה: מערך מחרוזת הוא משאב פשוט שיש אליו הפניה
באמצעות הערך שצוין במאפיין name
(לא השם של קובץ ה-XML). בתור
לדוגמה, אפשר לשלב משאבים של מערך מחרוזות עם משאבים פשוטים אחרים בקובץ XML אחד,
תחת רכיב <resources>
אחד.
- מיקום הקובץ:
-
שם הקובץ שרירותי. המאפיין
name
של הרכיב<string-array>
משמש למזהה המשאב של הממשק. - סוג נתונים של משאב מקומפל:
- מצביע משאב למערך של
String
. - הפניה למשאבים:
-
ב-Java:
R.array.string_array_name
ב-XML:@[package:]array/string_array_name
- תחביר:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- רכיבים:
- דוגמא:
- קובץ XML נשמר ב-
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="planets_array"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> <item>Mars</item> </string-array> </resources>
קוד האפליקציה הזה מאחזר מערך מחרוזת:
Kotlin
val array: Array<String> =
resources
.getStringArray
(R.array.planets_array)Java
Resources res =
getResources()
; String[] planets = res.getStringArray
(R.array.planets_array);
res/values/filename.xml
בצבע מחרוזות כמות (רבים)
לשפות שונות יש כללים שונים להתאמה של דקדוק עם כמות. באנגלית,
לדוגמה, הכמות 1 היא מקרה מיוחד. אנחנו כותבים "ספר אחד", אבל עבור כל כמות אחרת
לכתוב "n Books". ההבחנה בין יחיד לרבים נפוצה מאוד, אך
יוצרים הבחנות עדינות יותר. הקבוצה המלאה שנתמכת ב-Android היא zero
,
one
, two
, few
, many
וגם other
.
הכללים שקובעים באיזה מקרה להשתמש עבור שפה וכמות מסוימים יכולים להיות מורכבים מאוד,
אז Android מספק לך שיטות כמו
getQuantityString()
כדי לבחור
מקור המידע המתאים.
למרות שנקראו בעבר 'מחרוזות כמות', (וזה עדיין נקרא ב-API), כמות
צריך להשתמש במחרוזות רק עבור צורת רבים. זאת טעות במחרוזות כמות
להטמיע משהו כמו "תיבת הדואר הנכנס" של Gmail לעומת 'תיבת דואר נכנס (12)' כשיהיו הודעות שלא נקראו,
לדוגמה. אולי כדאי להשתמש במחרוזות כמות במקום בהצהרת if
,
אבל חשוב לציין שחלק מהשפות (כמו סינית) לא הופכות את הדקדוק
שונים, כך שתמיד תקבלו את המחרוזת other
.
בחירת המחרוזת לשימוש מתבצעת אך ורק על סמך הצורך הדקדוקי.
באנגלית, המערכת מתעלמת ממחרוזת של zero
גם אם הכמות היא 0, כי 0
שאינו שונה מבחינה דקדוקית מ-2, או מכל מספר אחר מלבד 1 ("אפס ספרים", "ספר אחד",
'שני ספרים', וכן הלאה). לעומת זאת, בקוריאנית רק המחרוזת other
שהיו בשימוש אי פעם.
אל תטעה את זה, כי, למשל, two
נשמע כאילו הוא יכול לחול רק על
הכמות 2: שפה יכולה לדרוש שגם 2, 12, 102 (וכן הלאה) יטופלו כמו אחת
כמויות שונות, אבל באופן שונה מכמויות אחרות. הסתמכו על המתרגם לשמוע את ההבדלים
השפה שלהם ממש מתעקשת.
אם ההודעה לא מכילה את מספר הכמות, סביר להניח שהיא לא מועמדת טובה רבים. לדוגמה, בליטאית משתמשים בצורת יחיד גם לספר 1 וגם למספר 101, כך ש"ספר אחד" תואם לערך מתורגמים ל-"1 knyga" ו-"101 Books" מתורגם ל-"101 knyga". בינתיים, 'ספר' הוא 'knyga' ו'ספרים רבים' הוא 'daug knygיוו'. אם הודעה בצורת רבים באנגלית מכילה את המילה 'ספר' (יחיד) ו'ספרים רבים' (רבים) ללא את המספר האמיתי, אפשר לתרגם אותו ל-"knyga" (abook)/"daug knygử" (ספרים רבים), אבל לפי כללי ליטא, יוצג השם knyga (ספר יחיד), כשהמספר הוא 101.
בדרך כלל ניתן להימנע ממחרוזות כמות על ידי שימוש בנוסחאות ניטרליות, כגון "ספרים: 1". כך החיים שלכם ושל המתרגמים חיים לקלים יותר, אם זה סגנון שמתאים לאפליקציה שלכם.
ב-API 24 ואילך אפשר להשתמש ביחידה הארגונית MessageFormat
במכשיר רב יותר-עוצמה
במקום זאת.
הערה: אוסף צורת רבים הוא משאב פשוט
מפנים באמצעות הערך שצוין במאפיין name
(לא שם ה-XML
). לכן, ניתן לשלב משאבים בצורת רבים עם משאבים פשוטים אחרים
קובץ XML, ברכיב <resources>
אחד.
- מיקום הקובץ:
-
שם הקובץ שרירותי. המאפיין
name
של הרכיב<plurals>
משמש למזהה המשאב של הממשק. - הפניה למשאבים:
-
ב-Java:
R.plurals.plural_name
- תחביר:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="plural_name"> <item quantity=["zero" | "one" | "two" | "few" | "many" | "other"] >text_string</item> </plurals> </resources>
- רכיבים:
- דוגמא:
- קובץ XML נשמר ב-
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <!-- As a developer, you should always supply "one" and "other" strings. Your translators will know which strings are actually needed for their language. Always include %d in "one" because translators will need to use %d for languages where "one" doesn't mean 1 (as explained above). --> <item quantity="one">%d song found.</item> <item quantity="other">%d songs found.</item> </plurals> </resources>
קובץ ה-XML נשמר ב-
res/values-pl/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <item quantity="one">Znaleziono %d piosenkę.</item> <item quantity="few">Znaleziono %d piosenki.</item> <item quantity="other">Znaleziono %d piosenek.</item> </plurals> </resources>
שימוש:
Kotlin
val count = getNumberOfSongsAvailable() val songsFound = resources.
getQuantityString
(R.plurals.numberOfSongsAvailable, count, count)Java
int count = getNumberOfSongsAvailable(); Resources res =
getResources()
; String songsFound = res.getQuantityString
(R.plurals.numberOfSongsAvailable, count, count);כשמשתמשים בשיטה
getQuantityString()
, צריך להעביר אתcount
פעמיים אם המחרוזת כוללת פורמט מחרוזות עם מספר. לדוגמה, עבור ��מחרוזת.%d songs found
, הפרמטרcount
הראשון בוחר את מחרוזת הרבים המתאימה הפרמטרcount
השני נוסף ל-placeholder של%d
. אם רבים המחרוזות לא כוללות את פורמט המחרוזת. אין צורך להעביר את הפרמטר השלישי אלgetQuantityString
.
res/values/filename.xml
בצבע פורמט וסגנון
הנה כמה דברים חשובים שכדאי לדעת כדי להבין איך לעצב ולעצב את משאבי המחרוזת.
טיפול בתווים מיוחדים
כאשר מחרוזת מכילה תווים שיש להם שימוש מיוחד ב-XML, צריך לסמן בתו בריחה (escape) את בהתאם לכללי ה-escape הרגילים של XML/HTML. אם צריך לסמן תו בתו בריחה (escape) שיש לו משמעות מיוחדת ב-Android, עליך להשתמש לפניו לוכסן הפוך.
כברירת מחדל, מערכת Android תכווץ רצפים של תווי רווח לבן לרווח יחיד. כדי למנוע מצב כזה, צריך להקיף את החלק הרלוונטי במחרוזת במירכאות כפולות. במקרה הזה כל תווי הרווח הלבן (כולל שורות חדשות) יישמרו בתוך האזור המצוטט. אפשר להשתמש במירכאות כפולות כדי להשתמש גם במירכאות רגילות ללא תו בריחה (escape).
תו | טפסים מילוט |
---|---|
@ | \@ |
? | \? |
שורה חדשה | \n |
מקש Tab | \t |
תו U+XXXX Unicode | \uXXXX |
גרש בודד (' ) |
אחד מהפרטים הבאים:
|
מירכאות כפולות (" ) |
\"
חשוב לשים לב שהמופע של המחרוזת במירכאות בודדות לא פועל. |
כיווץ רווחים לבנים ופעולת בריחה מ-Android מתרחשת אחרי
קובץ המשאב ינותח כ-XML. המשמעות היא
<string>      </string>
(רווח, רווח פיסוק, רווח Unicode Em) כולם כיווץ לרווח אחד
(" "
), כי כל הרווחים הם רווחים מ-Unicode אחרי ניתוח הקובץ כ-XML.
כדי לשמור את הרווחים האלה כפי שהם, אפשר לצטט אותם.
(<string>"      "</string>
)
אפשר גם להשתמש ב-Android Escape
(<string> \u0032 \u8200 \u8195</string>
).
הערה: מבחינת מנתח XML, אין הבדל בין
<string>"Test this"</string>
והקבוצה
<string>"Test this"</string>
בכלל. שני הטפסים
לא יציג מירכאות, אלא יפעיל ציטוט ששומר על רווחים לבנים ב-Android (שלא יכלול
בפועל במקרה הזה).
עיצוב מחרוזות
אם צריך לעצב את המחרוזות, אפשר לעשות את זה באמצעות הצבת הארגומנטים של פורמט במשאב המחרוזת, כפי שאפשר לראות במשאב לדוגמה הבא.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
בדוגמה הזו, מחרוזת הפורמט כוללת שני ארגומנטים: %1$s
הוא מחרוזת ו-%2$d
הוא מספר עשרוני. אחר כך מעצבים את המחרוזת בפורמט getString(int, Object...)
. לדוגמה:
Kotlin
var text = getString(R.string.welcome_messages, username, mailCount)
Java
String text = getString(R.string.welcome_messages, username, mailCount);
עיצוב עם תגי עיצוב של HTML
אפשר להוסיף עיצוב למחרוזות באמצעות תגי עיצוב של HTML. לדוגמה:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
רכיבי ה-HTML הבאים נתמכים:
- מודגש: <b>
- נטוי: <i>, <cite>, <dfn>, <em>
- טקסט גדול יותר ב-25%: <large>
- טקסט קטן ב-20%: <small>
- הגדרה של מאפייני גופנים: <font Face=”font_family“ color=”hex_color”> . דוגמאות של
משפחות הגופנים האפשריות כוללות את
monospace
,serif
וגםsans_serif
. - הגדרה של משפחת גופנים ברוחב אחיד: <tt>
- קו חוצה: <s>, <strike>, <del>
- קו תחתון: <u>
- כתב עילי: <sup>
- כתב תחתי: <sub>
- נקודות: <ul>, <li>
- מעברי שורה: <br>
- חטיבה: <div>
- סגנון CSS: <span style=”color|background_color|text-decoration”>
- פסקאות: <p dir=”rtl | ltr” style=”...”>
אם לא משתמשים בעיצוב, אפשר להגדיר את הטקסט ב-TextView ישירות באמצעות התקשרות
setText(java.lang.CharSequence)
עם זאת, במקרים מסוימים ייתכן
רוצים ליצור משאב טקסט מסוגנן שמשמש גם כמחרוזת עיצוב. בדרך כלל,
לא פועלת כי format(String, Object...)
ו-
getString(int, Object...)
השיטות מסירות את כל הסגנון
מהמחרוזת. דרך לעקוף את הבעיה היא לכתוב את תגי ה-HTML עם תווי בריחה (escape)
ישויות, שאפשר לשחזר באמצעות fromHtml(String)
,
אחרי קביעת הפורמט. לדוגמה:
- שומרים את משאב הטקסט המעוצב כמחרוזת HTML עם בריחה (escape):
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
במחרוזת המעוצבת הזו, נוסף רכיב
<b>
. שי��ו לב שהסוגריים הפותחים הם סימון HTML בתו בריחה (escape), באמצעות הסימון<
. - מזינים את המחרוזת בפורמט הרגיל, אבל גם קוראים לפונקציה
fromHtml(String)
��די להמיר את טקסט ה-HTML לטקסט מסוגנן:Kotlin
val text: String = getString(R.string.welcome_messages, username, mailCount) val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)
Java
String text = getString(R.string.welcome_messages, username, mailCount); Spanned styledText = Html.fromHtml(text, FROM_HTML_MODE_LEGACY);
השיטה fromHtml(String)
מעצבת את כל ישויות ה-HTML, לכן חשוב להקפיד
לסמן בתו בריחה (escape) כל תו HTML אפשרי במחרוזות שבהן משתמשים בטקסט המעוצב, באמצעות
htmlEncode(String)
. לדוגמה, אם אתם מעצבים מחרוזת שמכילה תווים כמו
'<' או '&', צריך לסמן אותם בתו בריחה (escape) לפני הפורמט. כך, כשהמחרוזת המעוצבת
מועבר דרך fromHtml(String)
, הדמויות יוצאים כפי שהן
במקור. לדוגמה:
Kotlin
val escapedUsername: String = TextUtils.htmlEncode
(username)
val text: String = getString(R.string.welcome_messages, escapedUsername, mailCount)
val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)
Java
String escapedUsername = TextUtils.htmlEncode
(username);
String text = getString(R.string.welcome_messages, escapedUsername, mailCount);
Spanned styledText = Html.fromHtml(text);
עיצוב עם מפתחות spannable
Spannable
הוא אובייקט טקסט שאפשר לעצב באמצעותו
מאפייני משפחת גופנים, כגון צבע ומשקל הגופן. אתם משתמשים
SpannableStringBuilder
לפיתוח
את הטקסט ואז להחיל את הסגנונות שהוגדרו בandroid.text.style
את החבילה לטקסט.
אפשר להגדיר חלק גדול מהעבודה בשיטות העזרה הבאות של יצירת טקסט שניתן להזזה:
Kotlin
/** * Returns a CharSequence that concatenates the specified array of CharSequence * objects and then applies a list of zero or more tags to the entire range. * * @param content an array of character sequences to apply a style to * @param tags the styled span objects to apply to the content * such as android.text.style.StyleSpan */ private fun apply(content: Array<out CharSequence>, vararg tags: Any): CharSequence { return SpannableStringBuilder().apply { openTags(tags) content.forEach { charSequence -> append(charSequence) } closeTags(tags) } } /** * Iterates over an array of tags and applies them to the beginning of the specified * Spannable object so that future text appended to the text will have the styling * applied to it. Do not call this method directly. */ private fun Spannable.openTags(tags: Array<out Any>) { tags.forEach { tag -> setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK) } } /** * "Closes" the specified tags on a Spannable by updating the spans to be * endpoint-exclusive so that future text appended to the end will not take * on the same styling. Do not call this method directly. */ private fun Spannable.closeTags(tags: Array<out Any>) { tags.forEach { tag -> if (length > 0) { setSpan(tag, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } else { removeSpan(tag) } } }
Java
/** * Returns a CharSequence that concatenates the specified array of CharSequence * objects and then applies a list of zero or more tags to the entire range. * * @param content an array of character sequences to apply a style to * @param tags the styled span objects to apply to the content * such as android.text.style.StyleSpan * */ private static CharSequence applyStyles(CharSequence[] content, Object[] tags) { SpannableStringBuilder text = new SpannableStringBuilder(); openTags(text, tags); for (CharSequence item : content) { text.append(item); } closeTags(text, tags); return text; } /** * Iterates over an array of tags and applies them to the beginning of the specified * Spannable object so that future text appended to the text will have the styling * applied to it. Do not call this method directly. */ private static void openTags(Spannable text, Object[] tags) { for (Object tag : tags) { text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK); } } /** * "Closes" the specified tags on a Spannable by updating the spans to be * endpoint-exclusive so that future text appended to the end will not take * on the same styling. Do not call this method directly. */ private static void closeTags(Spannable text, Object[] tags) { int len = text.length(); for (Object tag : tags) { if (len > 0) { text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { text.removeSpan(tag); } } }
bold
, italic
וגם color
הבאים
השיטות האלה כוללות את השיטות המסייעות שצוינו למעלה ומדגימות דוגמאות ספציפיות ליישום
סגנונות שהוגדרו בחבילה android.text.style
. שלך
יכולים ליצור שיטות דומות לעיצוב טקסט מסוגים אחרים.
Kotlin
/** * Returns a CharSequence that applies boldface to the concatenation * of the specified CharSequence objects. */ fun bold(vararg content: CharSequence): CharSequence = apply(content, StyleSpan(Typeface.BOLD)) /** * Returns a CharSequence that applies italics to the concatenation * of the specified CharSequence objects. */ fun italic(vararg content: CharSequence): CharSequence = apply(content, StyleSpan(Typeface.ITALIC)) /** * Returns a CharSequence that applies a foreground color to the * concatenation of the specified CharSequence objects. */ fun color(color: Int, vararg content: CharSequence): CharSequence = apply(content, ForegroundColorSpan(color))
Java
/** * Returns a CharSequence that applies boldface to the concatenation * of the specified CharSequence objects. */ public static CharSequence bold(CharSequence... content) { return apply(content, new StyleSpan(Typeface.BOLD)); } /** * Returns a CharSequence that applies italics to the concatenation * of the specified CharSequence objects. */ public static CharSequence italic(CharSequence... content) { return apply(content, new StyleSpan(Typeface.ITALIC)); } /** * Returns a CharSequence that applies a foreground color to the * concatenation of the specified CharSequence objects. */ public static CharSequence color(int color, CharSequence... content) { return apply(content, new ForegroundColorSpan(color)); }
הנה דוגמה לשרשור של השיטות האלה יחד כדי להחיל סגנונות שונים על מילים בתוך ביטוי:
Kotlin
// Create an italic "hello, " a red "world", // and bold the entire sequence. val text: CharSequence = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world)))
Java
// Create an italic "hello, " a red "world", // and bold the entire sequence. CharSequence text = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world)));
מודול ה- Core-ktx Kotlin מכיל גם פונקציות תוסף שהופכות את העבודה עם spans ל- יותר קל. אפשר לעיין מידע נוסף על חבילת android.text ב-GitHub.
למידע נוסף על עבודה עם spans, עיינו בקישורים הבאים:
עיצוב עם הערות
אפשר להחיל עיצוב מורכב או מותאם אישית באמצעות המחלקה Annotation
ביחד עם
<annotation>
בקובצי המשאבים מסוג String.xml. תג ההערה מאפשר
לסמן חלקים מהמחרוזת לעיצוב מותאם אישית על ידי הגדרת צמדי מפתח/ערך מותאמים אישית ב-XML
שה-framework ממיר ל-Annotation
מתפרשת על פני טווח. לאחר מכן אפשר לאחזר את הנתונים האלה
הערות ומשתמשים במפתח ובערך כדי להחיל את הסגנון.
כשיוצרים הערות, חשוב להוסיף את <annotation>
תג לכל התרגומים של המחרוזת בכל קובץ string.xml.
החלת משפחת גופנים בהתאמה אישית על המילה 'text' בכל השפות
דוגמה – הוספת משפחת גופנים מותאמת אישית
-
מוסיפים את התג
<annotation>
ומגדירים את צמד המפתח/ערך. במקרה הזה, הפרמטר המפתח הוא font, והערך הוא סוג הגופן שבו רוצים להשתמש: title_emphasis// values/strings.xml <string name="title">Best practices for <annotation font="title_emphasis">text</annotation> on Android</string> // values-es/strings.xml <string name="title"><annotation font="title_emphasis">Texto</annotation> en Android: mejores prácticas</string>
-
טוענים את משאב המחרוזת ומוצאים את ההערות באמצעות המקש font. לאחר מכן יוצרים מותאם אישית ומחליפים את הטווח הקיים.
Kotlin
// get the text as SpannedString so we can get the spans attached to the text val titleText = getText(R.string.title) as SpannedString // get all the annotation spans from the text val annotations = titleText.getSpans(0, titleText.length, Annotation::class.java) // create a copy of the title text as a SpannableString. // the constructor copies both the text and the spans. so we can add and remove spans val spannableString = SpannableString(titleText) // iterate through all the annotation spans for (annotation in annotations) { // look for the span with the key font if (annotation.key == "font") { val fontName = annotation.value // check the value associated to the annotation key if (fontName == "title_emphasis") { // create the typeface val typeface = getFontCompat(R.font.permanent_marker) // set the span at the same indices as the annotation spannableString.setSpan(CustomTypefaceSpan(typeface), titleText.getSpanStart(annotation), titleText.getSpanEnd(annotation), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } } } // now, the spannableString contains both the annotation spans and the CustomTypefaceSpan styledText.text = spannableString
Java
// get the text as SpannedString so we can get the spans attached to the text SpannedString titleText = (SpannedString) getText(R.string.title); // get all the annotation spans from the text Annotation[] annotations = titleText.getSpans(0, titleText.length(), Annotation.class); // create a copy of the title text as a SpannableString. // the constructor copies both the text and the spans. so we can add and remove spans SpannableString spannableString = new SpannableString(titleText); // iterate through all the annotation spans for (Annotation annotation: annotations) { // look for the span with the key font if (annotation.getKey().equals("font")) { String fontName = annotation.getValue(); // check the value associated to the annotation key if (fontName.equals("title_emphasis")) { // create the typeface Typeface typeface = ResourcesCompat.getFont(this, R.font.roboto_mono); // set the span at the same indices as the annotation spannableString.setSpan(new CustomTypefaceSpan(typeface), titleText.getSpanStart(annotation), titleText.getSpanEnd(annotation), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } // now, the spannableString contains both the annotation spans and the CustomTypefaceSpan styledText.text = spannableString;
אם אתם משתמשים באותו טקסט מספר פעמים, צריך ליצור את אובייקט SpannableString פעם אחת ועושה בו שימוש חוזר לפי הצורך, כדי למנוע ביצועים וזיכרון פוטנציאליים בעיות נפוצות.
לדוגמאות נוספות של שימוש בהערות: עיצוב טקסט בינלאומי ב-Android
טווחי הערות ומגרשי טקסט
בגלל שהפרצופים של Annotation
הם גם ParcelableSpans
, ערך המפתח
זוגות מועברים בחבילות ולא מחולקים. כל עוד מקבל החבילה יודע איך לפרש
את ההערות, אפשר להשתמש ברווחים מסוג Annotation
כדי להחיל סגנון מותאם אישית
טקסט של חלוקה לחבילות.
כדי לשמור את העיצוב המותאם אישית כאשר מעבירים את הטקסט לחבילת Intent, צריך קודם להוסיף
Annotation
מכסה את הטקסט. אפשר לעשות זאת במשאבי ה-XML דרך
<הערה> כמו שמוצג בדוגמה שלמעלה, או בקוד על ידי יצירת
Annotation
ומגדירים אותו כטווח, כמו שמוצג בהמשך:
Kotlin
val spannableString = SpannableString("My spantastic text") val annotation = Annotation("font", "title_emphasis") spannableString.setSpan(annotation, 3, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) // start Activity with text with spans val intent = Intent(this, MainActivity::class.java) intent.putExtra(TEXT_EXTRA, spannableString) startActivity(intent)
Java
SpannableString spannableString = new SpannableString("My spantastic text"); Annotation annotation = new Annotation("font", "title_emphasis"); spannableString.setSpan(annotation, 3, 7, 33); // start Activity with text with spans Intent intent = new Intent(this, MainActivity.class); intent.putExtra(TEXT_EXTRA, spannableString); this.startActivity(intent);
מאחזרים את הטקסט מ-Bundle
בתור SpannableString
ואז מנתחים
את ההערות המצורפות, כפי שמוצג בדוגמה שלמעלה.
Kotlin
// read text with Spans val intentCharSequence = intent.getCharSequenceExtra(TEXT_EXTRA) as SpannableString
Java
// read text with Spans SpannableString intentCharSequence = (SpannableString)intent.getCharSequenceExtra(TEXT_EXTRA);
למידע נוסף על עיצוב טקסט, אפשר לעיין בקישורים הבאים: