Tạo style for Text using spans
Bài đăng này đã không được cập nhật trong 6 năm
Để tạo style text trong Android, chúng ta sẽ sử dụng spans
! Thay đổi màu của một vài ký tự trong text, tạo text nhấp nháy, scale size text hoặc vẽ các điểm bullet với spans
. Spans có thể thay đổi các thuộc tính của TextPaint
, vẽ trên Canvas
, hoặc thậm chí thay đổi cả bố cục văn bản hay là ảnh hưởng đến các yếu tốt như chiều cao của dòng. Spans là đối tượng được đánh dấu có thể thêm vào hoặc tách ra từ text; chúng có thể được apply toàn bộ hoặc 1 phần của văn bản.
Ngay bây giờ chúng ta sẽ bắt đầu tìm hiểu làm thế nào để sử dụng được spans.
Styling text in Android
Android cung cấp một số styling text:
- Single style — Áp dụng cho toàn bộ text được displayed bởi TextView
- Multi style — Có thể áp dụng cho 1 text, ký tự hoặc đoạn văn bản
Single style tạo apply style cho toàn bộ nội dung text trong TextView, sử dụng thuộc tính của XML or styles and themes. Cách này là 1 giải pháp dễ dàng và hoạt động từ XML nhưng không cho phép tạo style cho 1 phần của văn bản. Ví dụ, sử dụng textStyle=”bold”
, toàn bộ text sẽ được in đậm; bạn không thể chỉ định được ký tự cụ thể nào được in đậm.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="32sp"
android:textStyle="bold"/>
Multi style thêm nhiều kiểu style cho text. Ví dụ, có 1 chữ italic và 1 chữ bold. Multi style có thể tạo bằng cách sử dụng HTML tags, spans hoặc custom text drawing trên Canvas.
HTML tags là cách dễ dàng giải quyết các vấn đề đơn giản, như tạo text bold, italic, hoặc hiển thì bullet points (dấu đánh đầu dòng). Để style chứa HTML tags, call Html.fromHtml method. HTML format được convert thành spans. Chú ý, class Html
không hỗ trợ tất cả các HTML tags và css styles như tạo bullet points có các color khác nhau.
val text = "My text <ul><li>bullet one</li><li>bullet two</li></ul>"
myTextView.text = Html.fromHtml(text)
Bạn có thể draw the text on Canvas khi bạn cần style mà không được support bởi platform như tạo text có layout là đường cong.
Spans cho phép bạn tạo multi-style text tùy chỉnh chi tiết . Ví dụ, bạn có thể tạo văn bản với bullet bằng cách sử dụng BulletSpan. Bạn cũng có thể tùy chỉnh khoảng cách giữa text và bullet, hay color của bullet. Bắt đầu với Android P, bạn thậm chí có thể thay đổi radius của bullet point. Bạn cũng có thể tùy chỉnh Spans. Ví dụ:
val spannable = SpannableString("My text \nbullet one\nbullet two")
spannable.setSpan(
BulletPointSpan(gapWidthPx, accentColor),
/* start index */ 9, /* end index */ 18,
Spannable._SPAN_EXCLUSIVE_EXCLUSIVE_)
spannable.setSpan(
BulletPointSpan(gapWidthPx, accentColor),
/* start index */ 20, /* end index */ spannable.length,
Spannable._SPAN_EXCLUSIVE_EXCLUSIVE_)
myTextView._text_ = spannable
Bạn có thể kết hợp giữa single style và multi style. Bạn có thể xem xét style để apply cho TextView như là “base” style. Spans text style được apply cho “on top” của base style và sẽ được override in base style. Ví dụ, khi set thuộc tính textColor=”@color.blue”
cho TextView và applying cho ForegroundColorSpan(Color.PINK)
cho 4 ký tự đầu của text, 4 characters đầu tiên sẽ sử dụng pink color được set bởi spans.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/blue"/>
val spannable = SpannableString(“Text styling”)
spannable.setSpan(ForegroundColorSpan(Color.PINK),0, 4,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
myTextView.text = spannable
Applying Spans
Khi sử dụng spans bạn cũng có thể làm việc với class : SpannedString, SpannableString hoặc SpannableStringBuilder. Sự khác nhau giữa chúng nằm trong text, các object có thể thay đổi hoặc không thay đổi, và cấu trúc bên trong chúng sử dụng SpannedString
và SpannableString
sử dụng mảng arrays để giữ các records được add vào các spans trong khi SpannableStringBuilder
sử dụng interval tree
Dưới đây là cách bạn có thể quyết định khi sử dụng 1 trong các class trên:
- Chỉreading and not setting text cũng như spans? ->
SpannedString
- Setting the text and the spans? ->
SpannableStringBuilder
- Setting a small number of spans (<~10)? ->
SpannableString
- Setting a larger number of spans (>~10) ->
SpannableStringBuilder
Ví dụ, nếu bạn đang làm việc với text không thay đổi, nhưng bạn muốn attach spans, bạn có thể sử dụng SpannableString
.
Apply span call [setSpan(Object what, int start, int end, int flags)](https://developer.android.com/reference/android/text/Spannable.html#setSpan%28java.lang.Object,%20int,%20int,%20int%29)
của Spannable
object. what
Object là object sẽ được apply từ start đến end trong text. flag
là đánh dấu khoảng có nên mở rộng để text có thể chèn vào điểm start hoặc end hoặc không.
Ví dụ set color ForegroundColorSpan
:
val spannable = SpannableStringBuilder(“Text is spantastic!”)
spannable.setSpan(
ForegroundColorSpan(Color.RED),
8, 12,
Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
Bởi vì spans sử dụng SPAN_EXCLUSIVE_INCLUSIVE flag, khi insert text vào end cùa span, nó sẽ mở rộng bao gồm cả text mới:
val spannable = SpannableStringBuilder(“Text is spantastic!”)
spannable.setSpan(
ForegroundColorSpan(Color.RED),
/* start index */ 8, **/* end index */ 12**,
Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
spannable.insert(12, “(& fon)”)
Nếu span được set với Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
flag, khi insert text tại vị trí end sẽ không thay đổi span.
Multiple spans có thể được tạo và attached như đoạn text. Ví dụ, text có thể vừa được set bold và red color:
val spannable = SpannableString(“Text is spantastic!”)
spannable.setSpan(
ForegroundColorSpan(Color.RED),
8, 12,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(
StyleSpan(BOLD),
8, spannable.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
Basic text styling with HTML tags
Một số HTML tags thường dùng
- Bold:
<b>
,<em>
- Italic:
<i>
,<cite>
,<dfn>
- 25% increase in text size
<big>
- 20% decrease in text size
<small>
- Setting font properties:
<font face=”font_family“ color=”hex_color”>
. Examples of the possible font families includemonospace
,serif
andsans_serif
. - Setting a monospace font family:
<tt>
- Strikethrough:
<s>
,<strike>
,<del>
- Underline:
<u>
- Superscript:
<sup>
- Subscript:
<sub>
- Bullet points:
<ul>
,<li>
- Line breaks:
<br>
- Division:
<div>
- CSS style:
<span style=”color|background_color|text-decoration”>
- Paragraphs:
<p dir=”rtl | ltr” style=”…”>
Ví dụ, để set word “text” bold, text trong file strings.xml :
// values/strings.xml
<string name=”title”>Best practices for <b>text</b> on Android</string>
// values-es/strings.xml
<string name=”title”><b>Texto</b> en Android: mejores prácticas</string>
Trong code:
textView.setText(R.string.title)
Complex text styling with Annotation
Nếu style vượt quá platform HTML tags support, hoặc bạn muốn custom styles, giống như custom bullet point styling hoặc thậm chí tạo style mới, thì chúng ta cần 1 giải pháp khác. Đánh dấu các từ được tạo styled và làm việc với class android.text.Annotation và tương thích với <annotation>
tag trong resource files strings.xml.
Annotation tag cho phép chúng ta define custom <key, value>
pairs trong xml. Khi get string resource SpannedString
,pairs tự động converted bởi Android framework đếnAnnotation
spans, tương ứng với annotation key và value. Chúng ta có thể phân tích list annotations attached cho text add đúng span cho text.
Để chắc chán bạn add <annotation>
tag cho tất cả resource string.xml file.
Apply custom typeface to the word “text”, trong tất cả ngôn ngữ. Apply CustomTypefaceSpan
đến word “text”. Đây là những gì cần làm:
- Add
<annotation>
tag and define<key, value>
pair. Trong trường hợp này, key là_font_
, and value là type cùa font chúng ta 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>
- Lấy string từ resources, với annotations key
_font_
và value tương ứng. Sau đó tạo custom span và set nó cho text ở vị trí trong các annotation.
// 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
// 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 with the annotation key
if (fontName == "title_emphasis") {
// create the typeface
val typeface = getFontCompat(R.font.permanent_marker)
// set the span to 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
Bạn có thể tham khảo code ở đây.
All rights reserved