Tài nguyên chuỗi cung cấp chuỗi văn bản cho ứng dụng bằng định dạng và định kiểu văn bản tuỳ chọn. Có 3 loại tài nguyên có thể cung cấp chuỗi cho ứng dụng của bạn:
- Chuỗi
- Tài nguyên XML cung cấp một chuỗi đơn.
- Mảng chuỗi
- Tài nguyên XML cung cấp một mảng chuỗi.
- Chuỗi số lượng (số nhiều)
- Tài nguyên XML chứa các chuỗi khác nhau để số hoá.
Tất cả chuỗi đều có khả năng áp dụng một số đối số định dạng và đánh dấu kiểu. Để biết thông tin về định kiểu và định dạng các chuỗi, vui lòng xem mục Định dạng và định kiểu.
Chuỗi
Một chuỗi đơn có thể được tham chiếu từ ứng dụng hoặc từ các tệp tài nguyên khác (chẳng hạn như bố cục XML).
Lưu ý: Chuỗi là một tài nguyên đơn giản được tham chiếu bằng cách sử dụng giá trị đã cung cấp trong thuộc tính name
(không phải tên của tệp XML). Vì vậy, bạn có thể kết hợp tài nguyên chuỗi với các tài nguyên đơn giản khác trong một tệp XML, bên dưới một phần tử <resources>
.
- vị trí tệp:
res/values/filename.xml
Bạn có thể tuỳ ý đặt tên tệp.name
của phần tử<string>
được dùng làm mã nhận dạng tài nguyên.- loại dữ liệu tài nguyên được biên dịch:
- Con trỏ tài nguyên đến
String
. - mã tham chiếu tài nguyên:
-
Trong Java:
R.string.string_name
Trong XML:@string/string_name
- cú pháp:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- phần tử:
- ví dụ:
- Tệp XML được lưu vào
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Tệp XML bố cục này áp dụng một chuỗi cho một Thành phần hiển thị:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
Mã xử lý ứng dụng này truy xuất một chuỗi:
Bạn có thể sử dụng
getString(int)
hoặcgetText(int)
để truy xuất chuỗi.getText(int)
giữ lại mọi kiểu văn bản đa dạng thức được áp dụng cho chuỗi.
Mảng chuỗi
Một mảng chuỗi có thể được tham chiếu từ ứng dụng.
Lưu ý: Mảng chuỗi là một tài nguyên đơn giản được tham chiếu bằng cách sử dụng giá trị đã cung cấp trong thuộc tính name
(không phải tên của tệp XML). Do đó, bạn có thể kết hợp các tài nguyên mảng chuỗi với các tài nguyên đơn giản khác trong một tệp XML, bên dưới một phần tử <resources>
.
- vị trí tệp:
res/values/filename.xml
Bạn có thể tuỳ ý đặt tên tệp.name
của phần tử<string-array>
được dùng làm mã nhận dạng tài nguyên.- loại dữ liệu tài nguyên được biên dịch:
- Con trỏ tài nguyên đến một mảng
String
. - mã tham chiếu tài nguyên:
-
Trong Java:
R.array.string_array_name
Trong XML:@[package:]array/string_array_name
- cú pháp:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- phần tử:
- ví dụ:
- Tệp XML được lưu vào
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>
Mã xử lý ứng dụng này truy xuất một mảng chuỗi:
Kotlin
val array: Array<String> =
resources
.getStringArray
(R.array.planets_array)Java
Resources res =
getResources()
; String[] planets = res.getStringArray
(R.array.planets_array);
Chuỗi số lượng (số nhiều)
Mỗi ngôn ngữ có những quy tắc riêng đối với thoả thuận ngữ pháp về số lượng. Chẳng hạn như trong tiếng Anh, số lượng 1 là một trường hợp đặc biệt. Chúng tôi viết "1 cuốn sách", nhưng đối với bất kỳ số lượng nào khác, chúng tôi sẽ viết "n cuốn sách". Sự khác biệt giữa số ít và số nhiều này rất phổ biến, nhưng các ngôn ngữ khác cũng giúp phân biệt rõ hơn. Tập hợp đầy đủ do Android hỗ trợ là zero
,
one
, two
, few
, many
và other
.
Quy tắc quyết định trường hợp sử dụng cho một ngôn ngữ và số lượng nhất định có thể rất phức tạp, vì vậy, Android cung cấp cho bạn các phương thức như getQuantityString()
để chọn tài nguyên phù hợp cho bạn.
Mặc dù trước đây được gọi là "chuỗi số lượng" (và vẫn được gọi như vậy trong API), nhưng bạn chỉ nên sử dụng chuỗi số lượng cho số nhiều. Chẳng hạn sẽ là một sai lầm nếu bạn sử dụng chuỗi số lượng để triển khai một số mục như "Hộp thư đến" của Gmail so với "Hộp thư đến (12)" khi có thư chưa đọc. Việc sử dụng chuỗi số lượng thay vì một câu lệnh if
có vẻ thuận tiện, nhưng quan trọng là bạn cần lưu ý một số ngôn ngữ (chẳng hạn như tiếng Trung) không tạo ra khác biệt nào về ngữ pháp. Vì vậy, bạn sẽ luôn nhận chuỗi other
.
Việc lựa chọn chuỗi cần sử dụng chỉ dựa trên sự cần thiết về mặt ngữ pháp.
Trong tiếng Anh, một chuỗi cho zero
sẽ bị bỏ qua ngay cả khi số lượng là 0, vì số 0 không khác về mặt ngữ pháp với số 2 hoặc bất kỳ số nào khác trừ số 1 ("0 cuốn sách", "một cuốn sách", "2 cuốn sách", v.v. ). Ngược lại, trong tiếng Hàn, chỉ chuỗi other
được là sử dụng.
Cũng đừng nhầm lẫn bởi thực tế two
có vẻ như chỉ có thể áp dụng cho số lượng 2: một ngôn ngữ có thể yêu cầu xử lý số 2, 12, 102 (v.v.) như nhau, nhưng khác với các số lượng khác. Hãy bám sát vào người biên dịch để biết ngôn ngữ của họ thực sự nhấn mạnh đến những điểm khác biệt nào.
Nếu thông báo của bạn không chứa số lượng, thì đó có thể không phải là lựa chọn phù hợp cho số nhiều. Chẳng hạn như trong tiếng Lithuania, dạng số ít được sử dụng cho cả 1 và 101, vì vậy "1 cuốn sách" được dịch thành "1 knyga" và "101 cuốn sách" được dịch thành "101 knyga". Trong khi đó, "một cuốn sách" là "knyga" và "nhiều cuốn sách" là "daug knygų". Nếu thông báo ở dạng số nhiều trong tiếng Anh chứa "một cuốn sách" (số ít) và "nhiều cuốn sách" (số nhiều) mà không có số thực, thì thông báo đó có thể được dịch là "knyga" (một cuốn sách)/"daug knygų" (nhiều cuốn sách), nhưng trong quy tắc của Lithuania, nó sẽ hiển thị "knyga" (một cuốn sách duy nhất) khi số đó là 101.
Bạn cũng có thể tránh các chuỗi số lượng bằng cách sử dụng các công thức trung lập về số lượng, chẳng hạn như "Sách: 1". Việc này giúp cuộc sống của bạn và những người biên dịch trở nên dễ chịu hơn nếu đó là phong cách chấp nhận được cho ứng dụng của bạn.
Thay vào đó, trên API cấp 24 trở lên, bạn có thể sử dụng lớp ICU MessageFormat
mạnh mẽ hơn nhiều.
Lưu ý: Bộ sưu tập số nhiều là một tài nguyên đơn giản được tham chiếu bằng cách sử dụng giá trị đã cung cấp trong thuộc tính name
(không phải tên của tệp XML). Do đó, bạn có thể kết hợp tài nguyên số nhiều với các tài nguyên đơn giản khác trong một tệp XML, bên dưới một phần tử <resources>
.
- vị trí tệp:
res/values/filename.xml
Bạn có thể tuỳ ý đặt tên tệp.name
của phần tử<plurals>
được dùng làm mã nhận dạng tài nguyên.- mã tham chiếu tài nguyên:
-
Trong Java:
R.plurals.plural_name
- cú pháp:
-
<?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>
- phần tử:
- ví dụ:
- Tệp XML được lưu vào
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>
Tệp XML được lưu vào
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>
Cách sử dụng:
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);Khi sử dụng phương thức
getQuantityString()
, bạn cần phải truyềncount
hai lần nếu chuỗi của bạn mang định dạng chuỗi có số. Chẳng hạn như đối với chuỗi%d songs found
, tham sốcount
đầu tiên sẽ chọn chuỗi số nhiều phù hợp, và tham sốcount
thứ hai được chèn vào phần giữ chỗ%d
. Nếu các chuỗi số nhiều không chứa định dạng chuỗi thì bạn không cần truyền tham số thứ ba tớigetQuantityString
.
Định dạng và kiểu
Dưới đây là một số điều quan trọng mà bạn nên biết về cách định dạng và định kiểu đúng cách cho tài nguyên chuỗi.
Xử lý các ký tự đặc biệt
Khi một chuỗi chứa các ký tự có cách sử dụng đặc biệt trong XML, bạn phải thoát các ký tự theo quy tắc thoát XML/HTML chuẩn. Nếu cần thoát một ký tự có ý nghĩa đặc biệt trong Android, bạn nên sử dụng dấu gạch chéo ngược phía trước.
Theo mặc định, Android sẽ thu gọn các chuỗi ký tự có khoảng trắng thành một dấu cách. Bạn có thể tránh trường hợp này bằng cách đặt phần liên quan của chuỗi trong dấu ngoặc kép. Trong trường hợp này, mọi ký tự có khoảng trắng (kể cả các dòng mới) sẽ được giữ nguyên trong vùng đã được đóng ngoặc. Dấu ngoặc kép cũng sẽ cho phép bạn sử dụng dấu nháy đơn lẻ thông thường.
Nhân vật | (Các) Biểu mẫu thoát |
---|---|
@ | \@ |
? | \? |
Dòng mới | \n |
Thẻ | \t |
Ký tự Unicode U+XXXX | \uXXXX |
Dấu nháy đơn (' ) |
Bất kỳ trường hợp nào sau đây:
|
Dấu ngoặc kép (" ) |
\"
Lưu ý là bạn không thể bao quanh chuỗi bằng dấu nháy đơn. |
Việc thu gọn khoảng trắng và ký tự thoát trên Android sẽ xảy ra sau khi tệp tài nguyên của bạn được phân tích cú pháp dưới dạng XML. Tức là <string>      </string>
(dấu cách, dấu chấm câu, dấu cách Unicode Em) đều thu gọn thành một dấu cách duy nhất (" "
), vì tất cả đều là dấu cách Unicode sau khi tệp được phân tích cú pháp dưới dạng XML.
Để giữ nguyên các dấu cách đó, bạn có thể trích dẫn các dấu cách đó (<string>"      "</string>
) hoặc sử dụng ký tự thoát của Android (<string> \u0032 \u8200 \u8195</string>
).
Lưu ý: Từ góc nhìn của trình phân tích cú pháp XML, không có sự khác biệt giữa <string>"Test this"</string>
và <string>"Test this"</string>
. Cả hai biểu mẫu đều không cho thấy dấu ngoặc kép nào, nhưng sẽ kích hoạt dấu ngoặc kép giữ nguyên dấu cách của Android (điều này không có tác dụng thực tế trong trường hợp này).
Định dạng chuỗi
Nếu cần định dạng chuỗi, bạn có thể thực hiện bằng cách đặt các đối số định dạng vào tài nguyên chuỗi, như được minh hoạ bằng tài nguyên ví dụ sau.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
Trong ví dụ này, chuỗi định dạng có hai đối số: %1$s
là một chuỗi và %2$d
là một số thập phân. Sau đó, định dạng chuỗi bằng cách gọi getString(int, Object...)
. Ví dụ:
Kotlin
var text = getString(R.string.welcome_messages, username, mailCount)
Java
String text = getString(R.string.welcome_messages, username, mailCount);
Tạo kiểu bằng mã đánh dấu HTML
Bạn có thể thêm kiểu cho chuỗi bằng mã đánh dấu HTML. Ví dụ:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
Các phần tử HTML sau được hỗ trợ:
- In đậm: <b>
- In nghiêng: <i>, <cite>, <dfn>, <em>
- Văn bản lớn hơn 25%: <big>
- Văn bản nhỏ hơn 20%: <small>
- Đặt thuộc tính phông chữ: <font face=”font_family“ color=”hex_color”>. Ví dụ về các bộ phông chữ có thể có:
monospace
,serif
vàsans_serif
. - Đặt một bộ phông chữ đơn cách: <tt>
- Gạch ngang chữ: <s>, <strike>, <del>
- Gạch dưới: <u>
- Chỉ số trên: <sup>
- Chỉ số dưới: <sub>
- Dấu đầu dòng: <ul>, <li>
- Ngắt dòng: <br>
- Phép chia: <div>
- Kiểu CSS: <span style=”color|background_color|text-decoration”>
- Đoạn: <p dir=”rtl | ltr” style=”…”>
Nếu không áp dụng định dạng, bạn có thể trực tiếp thiết lập văn bản TextView bằng cách gọi setText(java.lang.CharSequence)
. Tuy nhiên, trong một số trường hợp, có thể bạn muốn tạo một tài nguyên văn bản được định kiểu cũng được dùng làm chuỗi định dạng. Thường thì cách này không hiệu quả vì các phương thức format(String, Object...)
và getString(int, Object...)
sẽ tách mọi thông tin về kiểu khỏi chuỗi. Giải pháp cho trường hợp này là viết các thẻ HTML chứa các thực thể thoát, sau đó được khôi phục bằng fromHtml(String)
sau khi định dạng. Ví dụ:
- Lưu trữ tài nguyên văn bản đã được tạo kiểu dưới dạng chuỗi thoát HTML:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
Trong chuỗi được định dạng này, phần tử
<b>
sẽ được thêm. Lưu ý dấu ngoặc mở là ký tự thoát HTML, sử dụng ký hiệu<
. - Sau đó định dạng chuỗi như bình thường, nhưng cũng gọi
fromHtml(String)
để chuyển đổi văn bản HTML thành văn bản được tạo kiểu: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);
Vì phương thức fromHtml(String)
định dạng mọi thực thể HTML, hãy nhớ thoát mọi ký tự HTML có thể có trong chuỗi mà bạn sử dụng bằng văn bản đã định dạng, bằng cách sử dụng htmlEncode(String)
. Chẳng hạn như nếu bạn đang định dạng một chuỗi có chứa các ký tự như "<" hoặc "&", thì các chuỗi này phải được thoát trước khi định dạng, để khi chuỗi đã định dạng được truyền qua fromHtml(String)
thì các ký tự sẽ xuất hiện theo cách viết ban đầu. Ví dụ:
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);
Tạo kiểu bằng các spannable
Spannable
là một đối tượng văn bản mà bạn có thể tạo kiểu bằng các thuộc tính kiểu chữ như màu sắc và độ đậm của phông chữ. Bạn sử dụng SpannableStringBuilder
để tạo văn bản rồi sau đó áp dụng các kiểu đã xác định trong gói android.text.style
cho văn bản đó.
Bạn có thể sử dụng các phương thức trợ giúp sau đây để thiết lập phần lớn công việc tạo văn bản có span:
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); } } }
Các phương thức bold
, italic
và color
sau đây bao gồm những phương thức trợ giúp ở trên và minh hoạ các ví dụ cụ thể về cách áp dụng kiểu được xác định trong gói android.text.style
. Bạn có thể tạo các phương thức tương tự để thực hiện các kiểu văn bản khác.
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)); }
Sau đây là ví dụ về cách liên kết các phương thức này với nhau để áp dụng nhiều kiểu cho từng từ trong một cụm từ:
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)));
Mô-đun core-ktx cũng chứa các hàm mở rộng giúp việc sử dụng span thậm chí còn dễ dàng hơn. Bạn có thể xem tài liệu về gói android.text trên GitHub để tìm hiểu thêm.
Để biết thêm thông tin về cách sử dụng span, vui lòng xem các đường liên kết sau:
Tạo kiểu bằng chú thích
Bạn có thể tạo kiểu phức tạp hoặc tuỳ chỉnh bằng cách sử dụng lớp Annotation
cùng với thẻ <annotation>
trong các tệp tài nguyên strings.xml. Thẻ chú thích cho phép bạn đánh dấu các phần của chuỗi để định kiểu tuỳ chỉnh bằng cách xác định các cặp khoá-giá trị tuỳ chỉnh trong XML mà khung đó chuyển đổi thành các span Annotation
. Sau đó, bạn có thể truy xuất các chú thích này và sử dụng khoá và giá trị để áp dụng kiểu.
Khi tạo các chú thích, hãy đảm bảo bạn thêm thẻ <annotation>
vào tất cả các bản dịch của chuỗi trong mọi tệp strings.xml.
Áp dụng một kiểu chữ tuỳ chỉnh cho từ “văn bản” trong tất cả ngôn ngữ
Chẳng hạn như thêm kiểu chữ tuỳ chỉnh
-
Thêm thẻ
<annotation>
và xác định cặp khoá-giá trị. Trong trường hợp này, khoá là phông chữ, và giá trị là loại phông chữ chúng ta muốn sử dụng: 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>
-
Tải tài nguyên chuỗi và tìm các chú thích bằng khoá phông chữ. Sau đó, tạo một span tuỳ chỉnh và thay thế span hiện có.
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;
Nếu đang dùng nhiều lần cùng một văn bản, bạn nên tạo đối tượng SpannableString một lần và sử dụng lại nếu cần để tránh các vấn đề tiềm ẩn về hiệu suất và bộ nhớ.
Để xem thêm ví dụ về cách sử dụng chú thích, vui lòng xem phần Tạo kiểu cho văn bản quốc tế hoá trong Android
Các span chú thích và phân vùng văn bản
Vì các span Annotation
cũng là ParcelableSpans
, các cặp khoá-giá trị sẽ được phân loại lẫn không phân loại. Miễn là người nhận phân vùng biết cách diễn giải các chú thích, bạn có thể sử dụng các span Annotation
để áp dụng kiểu tuỳ chỉnh cho văn bản đã được phân vùng.
Để duy trì kiểu tuỳ chỉnh khi chuyển văn bản đến Gói ý định, trước tiên, bạn cần thêm các span Annotation
vào văn bản. Bạn có thể thực hiện việc này trong các tài nguyên XML thông qua thẻ <annotation>, như minh hoạ trong ví dụ ở trên hoặc trong mã bằng cách tạo một Annotation
mới và thiết lập dưới dạng span như sau:
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);
Truy xuất văn bản từ Bundle
dưới dạng SpannableString
rồi phân tích cú pháp các chú thích đính kèm, như trong ví dụ trên.
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);
Để biết thêm thông tin về kiểu văn bản, vui lòng xem các đường liên kết sau:
- Buổi nói chuyện tại Google I/O 2018 – Các phương pháp hay nhất dành cho văn bản trên Android
- Tìm hiểu về span