ช่วงคือออบเจ็กต์มาร์กอัปที่มีประสิทธิภาพซึ่งคุณใช้จัดรูปแบบข้อความได้ในระดับอักขระหรือย่อหน้า คุณสามารถเปลี่ยนข้อความได้หลายวิธีเมื่อแนบช่วงกับออบเจ็กต์ข้อความ ซึ่งรวมถึงการเพิ่มสี การทำให้ข้อความคลิกได้ การปรับขนาดข้อความ และการวาดข้อความในลักษณะที่กำหนดเอง ระยะห่างยังเปลี่ยนแปลงคุณสมบัติของ TextPaint
วาดใน Canvas
และเปลี่ยนเลย์เอาต์ข้อความได้ด้วย
Android มีช่วงหลายประเภทที่ครอบคลุมรูปแบบการจัดรูปแบบข้อความทั่วไปที่หลากหลาย นอกจากนี้ คุณยังสร้างช่วงของคุณเองเพื่อใช้การจัดรูปแบบที่กำหนดเองได้ด้วย
สร้างและใช้ช่วง
หากต้องการสร้างช่วง ให้ใช้คลาสใดคลาสหนึ่งที่อยู่ในตารางต่อไปนี้ โดยคลาสจะแตกต่างกันไปตามลักษณะของข้อความเอง ลักษณะของมาร์กอัปข้อความ และโครงสร้างข้อมูลที่สําคัญซึ่งมีข้อมูลช่วง
ชั้น | ข้อความที่เปลี่ยนแปลงได้ | มาร์กอัปที่เปลี่ยนแปลงได้ | โครงสร้างข้อมูล |
---|---|---|---|
SpannedString |
ไม่ | ไม่ | อาร์เรย์เชิงเส้น |
SpannableString |
ไม่ | ใช่ | อาร์เรย์เชิงเส้น |
SpannableStringBuilder |
ใช่ | ใช่ | แผนผังช่วงเวลา |
คลาสทั้ง 3 คลาสขยายอินเทอร์เฟซ Spanned
SpannableString
และ SpannableStringBuilder
ยังขยายอินเทอร์เฟซ Spannable
ด้วย
วิธีเลือกว่าจะใช้รูปแบบใด
- หากคุณไม่ได้แก้ไขข้อความหรือมาร์กอัปหลังจากสร้าง ให้ใช้
SpannedString
- หากต้องการแนบช่วงสั้นๆ ไปยังออบเจ็กต์ข้อความรายการเดียวและข้อความนั้นเป็นแบบอ่านอย่างเดียว ให้ใช้
SpannableString
- หากต้องการแก้ไขข้อความหลังจากสร้างและต้องการแนบช่วงกับข้อความ ให้ใช้
SpannableStringBuilder
- หากต้องการแนบช่วงจำนวนมากกับออบเจ็กต์ข้อความ ไม่ว่าจะมีสิทธิ์อ่านอย่างเดียวหรือไม่ก็ตาม ให้ใช้
SpannableStringBuilder
หากต้องการใช้ช่วง ให้เรียกใช้ setSpan(Object _what_, int _start_, int _end_, int
_flags_)
ในออบเจ็กต์ Spannable
พารามิเตอร์ what หมายถึงช่วงที่คุณใช้กับข้อความ ส่วนพารามิเตอร์ start และ end ระบุส่วนของข้อความที่คุณใช้ช่วงนั้น
หากคุณแทรกข้อความภายในขอบเขตของช่วง ระบบจะขยายช่วงให้รวมข้อความที่แทรกไว้โดยอัตโนมัติ เมื่อแทรกข้อความที่ขอบเขตของช่วง นั่นคือที่ดัชนีเริ่มต้นหรือสิ้นสุด พารามิเตอร์Flag จะกำหนดว่าช่วงจะขยายเพื่อรวมข้อความที่แทรกหรือไม่ ใช้เครื่องหมาย Spannable.SPAN_EXCLUSIVE_INCLUSIVE
เพื่อรวมข้อความที่แทรก และSpannable.SPAN_EXCLUSIVE_EXCLUSIVE
เพื่อยกเว้นข้อความที่แทรก
ตัวอย่างต่อไปนี้แสดงวิธีแนบ ForegroundColorSpan
กับสตริง
Kotlin
val spannable = SpannableStringBuilder("Text is spantastic!") spannable.setSpan( ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE )
Java
SpannableStringBuilder spannable = new SpannableStringBuilder("Text is spantastic!"); spannable.setSpan( new ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE );

ForegroundColorSpan
เนื่องจากมีการตั้งค่าช่วงโดยใช้ Spannable.SPAN_EXCLUSIVE_INCLUSIVE
ช่วงจึงขยายเพื่อรวมข้อความที่แทรกไว้ที่ขอบเขตของช่วง ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
val spannable = SpannableStringBuilder("Text is spantastic!") spannable.setSpan( ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE ) spannable.insert(12, "(& fon)")
Java
SpannableStringBuilder spannable = new SpannableStringBuilder("Text is spantastic!"); spannable.setSpan( new ForegroundColorSpan(Color.RED), 8, // start 12, // end Spannable.SPAN_EXCLUSIVE_INCLUSIVE ); spannable.insert(12, "(& fon)");

Spannable.SPAN_EXCLUSIVE_INCLUSIVE
คุณแนบช่วงหลายรายการลงในข้อความเดียวกันได้ ตัวอย่างต่อไปนี้แสดงวิธีสร้างข้อความตัวหนาสีแดง
Kotlin
val spannable = SpannableString("Text is spantastic!") spannable.setSpan(ForegroundColorSpan(Color.RED), 8, 12, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) spannable.setSpan( StyleSpan(Typeface.BOLD), 8, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE )
Java
SpannableString spannable = new SpannableString("Text is spantastic!"); spannable.setSpan( new ForegroundColorSpan(Color.RED), 8, 12, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ); spannable.setSpan( new StyleSpan(Typeface.BOLD), 8, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );

ForegroundColorSpan(Color.RED)
และ
StyleSpan(BOLD)
ประเภทช่วงของ Android
Android มีประเภทช่วงมากกว่า 20 ประเภทในแพ็กเกจ android.text.style Android จะจัดหมวดหมู่ช่วงออกเป็น 2 วิธีหลัก ดังนี้
- วิธีที่ช่วงมีผลต่อข้อความ: ช่วงอาจส่งผลต่อลักษณะที่ปรากฏของข้อความหรือเมตริกข้อความ
- ขอบเขตของช่วง: ช่วงบางช่วงใช้กับอักขระแต่ละตัวได้ ขณะที่บางช่วงต้องใช้กับทั้งย่อหน้า

ส่วนต่อไปนี้จะอธิบายหมวดหมู่เหล่านี้โดยละเอียด
ช่วงที่มีผลต่อลักษณะที่ปรากฏของข้อความ
ช่วงที่มีผลในระดับอักขระจะส่งผลต่อลักษณะที่ปรากฏของข้อความ เช่น การเปลี่ยนสีข้อความหรือพื้นหลัง และการเพิ่มขีดเส้นใต้หรือขีดทับ ช่วงเหล่านี้จะขยายคลาส CharacterStyle
ตัวอย่างโค้ดต่อไปนี้แสดงวิธีใช้ UnderlineSpan
เพื่อขีดเส้นใต้ข้อความ
Kotlin
val string = SpannableString("Text with underline span") string.setSpan(UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
Java
SpannableString string = new SpannableString("Text with underline span"); string.setSpan(new UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

UnderlineSpan
ส่วนที่มีผลต่อลักษณะที่ปรากฏของข้อความเท่านั้นจะทริกเกอร์ให้ระบบวาดข้อความอีกครั้งโดยไม่ทริกเกอร์ให้ระบบคํานวณเลย์เอาต์อีกครั้ง ช่วงเหล่านี้จะติดตั้งใช้งาน
UpdateAppearance
และขยายการทำงาน
CharacterStyle
CharacterStyle
ซับคลาสจะกำหนดวิธีวาดข้อความโดยให้สิทธิ์เข้าถึงเพื่ออัปเดต TextPaint
ช่วงที่มีผลต่อเมตริกข้อความ
ส่วนอื่นๆ ที่ใช้ในระดับอักขระจะส่งผลต่อเมตริกข้อความ เช่น ความสูงของบรรทัดและขนาดข้อความ ช่วงเหล่านี้จะขยายคลาส
MetricAffectingSpan
ตัวอย่างโค้ดต่อไปนี้สร้าง RelativeSizeSpan
ที่
เพิ่มขนาดข้อความ 50%
Kotlin
val string = SpannableString("Text with relative size span") string.setSpan(RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
Java
SpannableString string = new SpannableString("Text with relative size span"); string.setSpan(new RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

RelativeSizeSpan
การใช้ช่วงที่มีผลต่อเมตริกข้อความทําให้ออบเจ็กต์ที่สังเกตการณ์วัดข้อความอีกครั้งเพื่อเลย์เอาต์และการเรนเดอร์ที่ถูกต้อง เช่น การเปลี่ยนขนาดข้อความอาจทําให้คําปรากฏในบรรทัดอื่น การใช้ช่วงก่อนหน้าจะทริกเกอร์การวัดใหม่ การคํานวณเลย์เอาต์ข้อความใหม่ และการวาดข้อความใหม่
ช่วงที่ส่งผลต่อเมตริกข้อความจะขยายคลาส MetricAffectingSpan
ซึ่งเป็นคลาสนามธรรมที่ช่วยให้คลาสย่อยกําหนดวิธีที่ช่วงส่งผลต่อวิธีการวัดข้อความได้ด้วยการให้สิทธิ์เข้าถึง TextPaint
เนื่องจาก MetricAffectingSpan
ขยายจาก CharacterStyle
ซับคลาสจึงส่งผลต่อลักษณะที่ปรากฏของข้อความที่ระดับอักขระ
ช่วงที่มีผลต่อย่อหน้า
ระยะห่างยังส่งผลต่อข้อความในระดับย่อหน้าได้ด้วย เช่น การเปลี่ยนการจัดแนวหรือระยะขอบของบล็อกข้อความ ช่วงที่มีผลกับทั้งย่อหน้า ใช้ ParagraphStyle
หากต้องการใช้ช่วงเหล่านี้ ให้แนบช่วงนั้นกับทั้งย่อหน้า ยกเว้นอักขระขึ้นบรรทัดใหม่ตอนท้าย หากคุณพยายามใช้ช่วงย่อหน้ากับสิ่งอื่นที่ไม่ใช่ทั้งย่อหน้า Android จะไม่ใช้ช่วงเลย
รูปที่ 8 แสดงวิธีที่ Android แยกย่อหน้าในข้อความ

\n
)
ตัวอย่างโค้ดต่อไปนี้ใช้ QuoteSpan
กับย่อหน้า โปรดทราบว่าหากคุณแนบช่วงไว้ที่ตำแหน่งอื่นนอกเหนือจากตอนต้นหรือตอนท้ายของย่อหน้า Android จะไม่ใช้สไตล์นั้นเลย
Kotlin
spannable.setSpan(QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
Java
spannable.setSpan(new QuoteSpan(color), 8, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

QuoteSpan
ใช้กับย่อหน้า
สร้างช่วงที่กำหนดเอง
หากต้องการฟังก์ชันการทำงานมากกว่าที่มีให้ในแท็บ Android ที่มีอยู่ คุณสามารถใช้แท็บที่กําหนดเองได้ เมื่อใช้ช่วงของคุณเอง ให้ตัดสินใจว่าช่วงจะส่งผลต่อข้อความที่ระดับอักขระหรือระดับย่อหน้า และส่งผลต่อเลย์เอาต์หรือลักษณะที่ปรากฏของข้อความหรือไม่ ซึ่งจะช่วยให้คุณระบุคลาสพื้นฐานที่ขยายได้และอินเทอร์เฟซที่อาจต้องใช้ ใช้ตารางต่อไปนี้เป็นข้อมูลอ้างอิง
สถานการณ์ | คลาสหรืออินเทอร์เฟซ |
---|---|
ช่วงที่เลือกจะส่งผลต่อข้อความที่ระดับอักขระ | CharacterStyle |
ระยะมีผลต่อลักษณะของข้อความ | UpdateAppearance |
ระยะมีผลต่อเมตริกข้อความ | UpdateLayout |
ช่วงที่เลือกจะมีผลกับข้อความในระดับย่อหน้า | ParagraphStyle |
เช่น หากต้องการใช้ช่วงที่กำหนดเองซึ่งแก้ไขขนาดและสีข้อความ ให้ขยาย RelativeSizeSpan
RelativeSizeSpan
สืบทอดCharacterStyle
และใช้อินเทอร์เฟซ Update
2 รายการผ่านการรับช่วง เนื่องจากคลาสนี้มีคอลแบ็กสําหรับ updateDrawState
และ updateMeasureState
อยู่แล้ว คุณจึงลบล้างคอลแบ็กเหล่านี้เพื่อใช้ลักษณะการทํางานที่กำหนดเองได้ โค้ดต่อไปนี้จะสร้างช่วงที่กำหนดเองที่ขยาย RelativeSizeSpan
และลบล้างการเรียกกลับ updateDrawState
เพื่อกำหนดสีของ TextPaint
Kotlin
class RelativeSizeColorSpan( size: Float, @ColorInt private val color: Int ) : RelativeSizeSpan(size) { override fun updateDrawState(textPaint: TextPaint) { super.updateDrawState(textPaint) textPaint.color = color } }
Java
public class RelativeSizeColorSpan extends RelativeSizeSpan { private int color; public RelativeSizeColorSpan(float spanSize, int spanColor) { super(spanSize); color = spanColor; } @Override public void updateDrawState(TextPaint textPaint) { super.updateDrawState(textPaint); textPaint.setColor(color); } }
ตัวอย่างนี้แสดงวิธีสร้างช่วงที่กำหนดเอง คุณสร้างเอฟเฟกต์เดียวกันได้โดยใช้ RelativeSizeSpan
และ ForegroundColorSpan
กับข้อความ
ทดสอบการใช้งานช่วง
อินเทอร์เฟซ Spanned
ช่วยให้คุณทั้งตั้งค่าช่วงและดึงข้อมูลช่วงจากข้อความได้ เมื่อทดสอบ ให้ใช้การทดสอบ Android JUnit เพื่อยืนยันว่ามีการเพิ่มช่วงที่เหมาะสมในตําแหน่งที่เหมาะสม ตัวอย่างการจัดรูปแบบข้อความ
แอป
มีช่วงที่ใช้มาร์กอัปกับสัญลักษณ์หัวข้อย่อยโดยแนบ BulletPointSpan
กับข้อความ ตัวอย่างโค้ดต่อไปนี้แสดงวิธีทดสอบว่าหัวข้อย่อยปรากฏตามที่คาดไว้หรือไม่
Kotlin
@Test fun textWithBulletPoints() { val result = builder.markdownToSpans("Points\n* one\n+ two") // Check whether the markup tags are removed. assertEquals("Points\none\ntwo", result.toString()) // Get all the spans attached to the SpannedString. val spans = result.getSpans<Any>(0, result.length, Any::class.java) // Check whether the correct number of spans are created. assertEquals(2, spans.size.toLong()) // Check whether the spans are instances of BulletPointSpan. val bulletSpan1 = spans[0] as BulletPointSpan val bulletSpan2 = spans[1] as BulletPointSpan // Check whether the start and end indices are the expected ones. assertEquals(7, result.getSpanStart(bulletSpan1).toLong()) assertEquals(11, result.getSpanEnd(bulletSpan1).toLong()) assertEquals(11, result.getSpanStart(bulletSpan2).toLong()) assertEquals(14, result.getSpanEnd(bulletSpan2).toLong()) }
Java
@Test public void textWithBulletPoints() { SpannedString result = builder.markdownToSpans("Points\n* one\n+ two"); // Check whether the markup tags are removed. assertEquals("Points\none\ntwo", result.toString()); // Get all the spans attached to the SpannedString. Object[] spans = result.getSpans(0, result.length(), Object.class); // Check whether the correct number of spans are created. assertEquals(2, spans.length); // Check whether the spans are instances of BulletPointSpan. BulletPointSpan bulletSpan1 = (BulletPointSpan) spans[0]; BulletPointSpan bulletSpan2 = (BulletPointSpan) spans[1]; // Check whether the start and end indices are the expected ones. assertEquals(7, result.getSpanStart(bulletSpan1)); assertEquals(11, result.getSpanEnd(bulletSpan1)); assertEquals(11, result.getSpanStart(bulletSpan2)); assertEquals(14, result.getSpanEnd(bulletSpan2)); }
ดูตัวอย่างการทดสอบเพิ่มเติมได้ในส่วน MarkdownBuilderTest ใน GitHub
ทดสอบช่วงที่กำหนดเอง
เมื่อทดสอบช่วง ให้ตรวจสอบว่า TextPaint
มีการแก้ไขตามที่คาดไว้ และมีการแสดงเอลิเมนต์ที่ถูกต้องใน Canvas
เช่น ลองใช้การติดตั้งใช้งานช่วงที่กำหนดเองซึ่งเพิ่มเครื่องหมายหัวข้อไว้ที่ด้านหน้าข้อความ มีการกำหนดขนาดและสีของหัวข้อย่อย และมีช่องว่างระหว่างขอบด้านซ้ายของพื้นที่วาดและหัวข้อย่อย
คุณสามารถทดสอบลักษณะการทํางานของคลาสนี้ได้โดยใช้การทดสอบ AndroidJUnit โดยตรวจสอบสิ่งต่อไปนี้
- หากคุณใช้ช่วงอย่างถูกต้อง จุดเริ่มต้นของย่อหน้าขนาดและสีที่ระบุจะปรากฏบนผืนผ้าใบ และจะมีระยะห่างที่เหมาะสมระหว่างระยะขอบด้านซ้ายกับจุดเริ่มต้นของย่อหน้า
- หากไม่ใช้ช่วง ลักษณะการทำงานที่กำหนดเองจะไม่ปรากฏ
คุณดูการใช้งานการทดสอบเหล่านี้ได้ในตัวอย่าง TextStyling ใน GitHub
คุณสามารถทดสอบการโต้ตอบของ Canvas โดยการจําลอง Canvas, ส่งออบเจ็กต์ที่จําลองไปยังเมธอด drawLeadingMargin()
และยืนยันว่ามีการเรียกใช้เมธอดที่ถูกต้องด้วยพารามิเตอร์ที่ถูกต้อง
ดูตัวอย่างการทดสอบช่วงเพิ่มเติมได้ใน BulletPointSpanTest
แนวทางปฏิบัติแนะนำในการใช้ช่วง
การตั้งค่าข้อความใน TextView
นั้นทำได้หลายวิธีโดยขึ้นอยู่กับความต้องการ
แนบหรือเลิกแนบช่วงโดยไม่เปลี่ยนข้อความที่อยู่เบื้องหลัง
TextView.setText()
มี Overload หลายรายการที่จัดการช่วงต่างกัน ตัวอย่างเช่น คุณสามารถตั้งค่าออบเจ็กต์ข้อความ Spannable
ด้วยโค้ดต่อไปนี้
Kotlin
textView.setText(spannableObject)
Java
textView.setText(spannableObject);
เมื่อเรียกใช้ setText()
แบบโอเวอร์โหลดนี้ TextView
จะสร้างสำเนา Spannable
เป็น SpannedString
และเก็บไว้ในหน่วยความจำเป็น CharSequence
ซึ่งหมายความว่าข้อความและช่วงจะเปลี่ยนแปลงไม่ได้ ดังนั้นเมื่อคุณต้องการอัปเดตข้อความหรือช่วง ให้สร้างออบเจ็กต์ Spannable
ใหม่และเรียกใช้ setText()
อีกครั้ง ซึ่งจะทริกเกอร์การวัดและวาดเลย์เอาต์อีกครั้งด้วย
หากต้องการระบุว่าช่วงต้องเปลี่ยนแปลงได้ ให้ใช้ setText(CharSequence text, TextView.BufferType
type)
แทน ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
textView.setText(spannable, BufferType.SPANNABLE) val spannableText = textView.text as Spannable spannableText.setSpan( ForegroundColorSpan(color), 8, spannableText.length, SPAN_INCLUSIVE_INCLUSIVE )
Java
textView.setText(spannable, BufferType.SPANNABLE); Spannable spannableText = (Spannable) textView.getText(); spannableText.setSpan( new ForegroundColorSpan(color), 8, spannableText.getLength(), SPAN_INCLUSIVE_INCLUSIVE);
ในตัวอย่างนี้ พารามิเตอร์ BufferType.SPANNABLE
ทําให้ TextView
สร้าง SpannableString
และตอนนี้ออบเจ็กต์ CharSequence
ที่ TextView
เก็บไว้จะมีมาร์กอัปที่เปลี่ยนแปลงได้และข้อความที่เปลี่ยนแปลงไม่ได้ หากต้องการอัปเดตช่วง ให้ดึงข้อมูลข้อความเป็น Spannable
แล้วอัปเดตช่วงตามต้องการ
เมื่อคุณแนบ เลิกแนบ หรือจัดตำแหน่งใหม่ TextView
จะอัปเดตโดยอัตโนมัติเพื่อแสดงการเปลี่ยนแปลงในข้อความ หากคุณเปลี่ยนแอตทริบิวต์ภายในของช่วงที่มีอยู่ ให้เรียกใช้ invalidate()
เพื่อทำการเปลี่ยนแปลงที่เกี่ยวข้องกับลักษณะที่ปรากฏ หรือเรียกใช้ requestLayout()
เพื่อทำการเปลี่ยนแปลงที่เกี่ยวข้องกับเมตริก
ตั้งค่าข้อความใน TextView หลายครั้ง
ในบางกรณี เช่น เมื่อใช้ RecyclerView.ViewHolder
คุณอาจต้องการใช้ TextView
ซ้ำและตั้งค่าข้อความหลายครั้ง โดยค่าเริ่มต้น TextView
จะสร้างสำเนาออบเจ็กต์ CharSequence
และเก็บไว้ในหน่วยความจำ ไม่ว่าคุณจะตั้งค่า BufferType
หรือไม่ก็ตาม ซึ่งทำให้การอัปเดตTextView
ทั้งหมดเป็นไปอย่างตั้งใจ คุณไม่สามารถอัปเดตออบเจ็กต์CharSequence
ต้นฉบับเพื่ออัปเดตข้อความได้ ซึ่งหมายความว่าทุกครั้งที่คุณตั้งค่าข้อความใหม่ TextView
จะสร้างออบเจ็กต์ใหม่
หากต้องการควบคุมกระบวนการนี้มากขึ้นและหลีกเลี่ยงการสร้างออบเจ็กต์เพิ่มเติม คุณสามารถใช้ Spannable.Factory
ของคุณเองและลบล้าง newSpannable()
แทนที่จะสร้างออบเจ็กต์ข้อความใหม่ คุณสามารถแคสต์และแสดงผล CharSequence
ที่มีอยู่เป็น Spannable
ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
val spannableFactory = object : Spannable.Factory() { override fun newSpannable(source: CharSequence?): Spannable { return source as Spannable } }
Java
Spannable.Factory spannableFactory = new Spannable.Factory(){ @Override public Spannable newSpannable(CharSequence source) { return (Spannable) source; } };
คุณต้องใส่ textView.setText(spannableObject, BufferType.SPANNABLE)
เมื่อตั้งค่าข้อความ มิเช่นนั้น ระบบจะสร้างแหล่งที่มา CharSequence
เป็นอินสแตนซ์ Spanned
และไม่สามารถแคสต์เป็น Spannable
ได้ ซึ่งจะทำให้ newSpannable()
แสดงClassCastException
หลังจากลบล้าง newSpannable()
แล้ว ให้บอก TextView
ให้ใช้ Factory
ใหม่โดยทำดังนี้
Kotlin
textView.setSpannableFactory(spannableFactory)
Java
textView.setSpannableFactory(spannableFactory);
ตั้งค่าออบเจ็กต์ Spannable.Factory
1 ครั้งทันทีหลังจากที่คุณได้รับข้อมูลอ้างอิงสำหรับ TextView
หากคุณใช้ RecyclerView
ให้ตั้งค่าออบเจ็กต์ Factory
เมื่อคุณเพิ่มยอดดูเป็นครั้งแรก วิธีนี้จะช่วยหลีกเลี่ยงการสร้างออบเจ็กต์เพิ่มเติมเมื่อ RecyclerView
ของคุณเชื่อมโยงรายการใหม่กับ ViewHolder
เปลี่ยนแอตทริบิวต์ของช่วงภายใน
หากต้องการเปลี่ยนเฉพาะแอตทริบิวต์ภายในของช่วงที่มีการเปลี่ยนแปลงได้ เช่น สีหัวข้อในช่วงหัวข้อที่กำหนดเอง คุณสามารถหลีกเลี่ยงค่าใช้จ่ายเพิ่มเติมจากการเรียกใช้ setText()
หลายครั้งได้โดยเก็บการอ้างอิงไปยังช่วงไว้เมื่อสร้าง
เมื่อต้องการแก้ไขช่วง คุณสามารถแก้ไขการอ้างอิงแล้วเรียกใช้ invalidate()
หรือ requestLayout()
ใน TextView
โดยขึ้นอยู่กับประเภทแอตทริบิวต์ที่คุณเปลี่ยนแปลง
ในตัวอย่างโค้ดต่อไปนี้ การใช้หัวข้อย่อยที่กำหนดเองจะมีสีเริ่มต้นเป็นสีแดงซึ่งจะเปลี่ยนเป็นสีเทาเมื่อมีการแตะปุ่ม
Kotlin
class MainActivity : AppCompatActivity() { // Keeping the span as a field. val bulletSpan = BulletPointSpan(color = Color.RED) override fun onCreate(savedInstanceState: Bundle?) { ... val spannable = SpannableString("Text is spantastic") // Setting the span to the bulletSpan field. spannable.setSpan( bulletSpan, 0, 4, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) styledText.setText(spannable) button.setOnClickListener { // Change the color of the mutable span. bulletSpan.color = Color.GRAY // Color doesn't change until invalidate is called. styledText.invalidate() } } }
Java
public class MainActivity extends AppCompatActivity { private BulletPointSpan bulletSpan = new BulletPointSpan(Color.RED); @Override protected void onCreate(Bundle savedInstanceState) { ... SpannableString spannable = new SpannableString("Text is spantastic"); // Setting the span to the bulletSpan field. spannable.setSpan(bulletSpan, 0, 4, Spanned.SPAN_INCLUSIVE_INCLUSIVE); styledText.setText(spannable); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Change the color of the mutable span. bulletSpan.setColor(Color.GRAY); // Color doesn't change until invalidate is called. styledText.invalidate(); } }); } }
ใช้ฟังก์ชันส่วนขยาย KTX ของ Android
นอกจากนี้ Android KTX ยังมีฟังก์ชันส่วนขยายที่ทําให้ใช้งานช่วงได้ง่ายขึ้น ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบของแพ็กเกจ androidx.core.text