SpannableString ay isang klase ng Android SDK mula sa paketeng android.text na nagpapahintulot sa paglalapat ng maramihang estilo sa iba't ibang bahagi ng isang string ng teksto sa TextView. Hindi tulad ng HTML markup, ang SpannableString ay gumagana sa antas ng mga bagay na Span, na namamahala sa visual na pagpapakita ng teksto: kulay, laki, tipo ng letra, salungguhit at mga interactive na elemento. Ayon sa Google Developers, ginagamit ang SpannableString sa mga bahagi ng sistema ng Android para sa pag-format ng mga link. Ito ang pangunahing paraan ng pag-istilo ng teksto nang hindi kumokonekta sa mga third-party na library.
Pangunahin
SpannableString ay isang klase ng Android na nagpapatupad ng interface ng Spannable, na nag-iimbak ng teksto kasama ng isang set ng mga bagay na Span na namamahala sa visual na pagpapakita. Hindi tulad ng ordinaryong String, pinapayagan ng SpannableString ang pag-attach ng mga katangian ng estilo sa mga tiyak na saklaw ng mga karakter: gawing pula ang bahagi ng teksto, palakihin ang font sa pamagat, o magdagdag ng naki-click na link sa loob ng talata.
Ang klase ay nasa paketeng android.text at magagamit mula sa API Level 1. Ang SpannableString ay hindi nababago — pagkatapos gawin, ang istraktura nito ay naayos, at ang pagpapalit ng teksto ay nangangailangan ng paglikha ng bagong bagay. Para sa dinamikong pag-edit, ginagamit ang SpannableStringBuilder, na sumusuporta sa pagpasok at pagtanggal ng mga karakter nang hindi nawawala ang mga estilo.
CharSequence ay ang pangunahing interface para sa data ng teksto, na ipinatupad ng String, StringBuilder at SpannableString. Ang pangunahing pagkakaiba sa pagitan ng SpannableString at String ay ang suporta para sa pag-attach ng mga arbitraryong bagay sa substring. Nakikilala ng TextView ang interface ng Spannable at sa pag-render ay inilalapat ang mga bagay na span sa mga kaukulang bahagi ng teksto. Kung ang ordinaryong String ay ipinasa sa TextView, walang estilo ang ilalapat.
Ang SpannableString ay nag-iimbak ng teksto bilang isang array na char[] at isang hiwalay na array ng mga bagay na span na may metadata tungkol sa simula at wakas na posisyon. Kapag tinawag ang setSpan(what, start, end, flags), ang bagay na what ay nai-save sa listahan kasama ng impormasyon tungkol sa saklaw. Sa pag-render, sunud-sunod na inilalapat ng TextView ang lahat ng span na nasa loob ng ipinapakitang saklaw, na tinatawag ang mga pamamaraang updateDrawState at updateMeasureState.
CharacterStyle ay ang base class para sa mga span na nakakaapekto sa mga indibidwal na karakter anuman ang kanilang posisyon sa mga linya. Kasama rito ang ForegroundColorSpan (kulay ng teksto), RelativeSizeSpan (kamag-anak na laki), StyleSpan (bold at italic), UnderlineSpan (salungguhit) at iba pa. Inilalapat ang Character-span sa bawat karakter sa tinukoy na saklaw nang isa-isa.
ParagraphStyle ay ang interface para sa mga span na nakakaapekto sa buong talata. Ang pinakakilalang kinatawan ay ang AlignmentSpan, na nag-aayos ng buong talata sa kaliwa, gitna o kanan. Dapat saklawin ng Paragraph-span ang buong talata, kung hindi, binabalewala ng Android ang paglalapat nito. Ang paghihigpit na ito ay nauugnay sa katotohanan na ang pagkakahanay o indentation ay may katuturan lamang para sa isang buong bloke ng teksto.
Span flags ay apat na constant na tumutukoy sa pag-uugali ng span kapag naglalagay o nagtatanggal ng teksto sa mga hangganan ng saklaw nito. Pinapanatili ng SPAN_EXCLUSIVE_EXCLUSIVE na aktibo ang span lamang sa loob ng orihinal na mga hangganan, pinalalawak ito ng SPAN_INCLUSIVE_INCLUSIVE kapag nagdaragdag ng teksto sa mga hangganan. Ang SPAN_EXCLUSIVE_INCLUSIVE at SPAN_INCLUSIVE_EXCLUSIVE ay nagbibigay ng pinaghalong pag-uugali para sa simula at wakas ng saklaw.
| Flag | Insert Kaliwa | Insert Kanan |
|---|---|---|
| SPAN_EXCLUSIVE_EXCLUSIVE | hindi kasama | hindi kasama |
| SPAN_INCLUSIVE_INCLUSIVE | kasama | kasama |
| SPAN_EXCLUSIVE_INCLUSIVE | hindi kasama | kasama |
| SPAN_INCLUSIVE_EXCLUSIVE | kasama | hindi kasama |
Ang tamang pagpili ng flag ay kritikal para sa Editable na teksto sa EditText, kung saan ang user ay maaaring magpasok at magtanggal ng mga karakter. Para sa read-only na TextView karaniwang ginagamit ang SPAN_EXCLUSIVE_EXCLUSIVE — ang estilo ay inilalapat lamang sa orihinal na saklaw at hindi lumalawak sa mga pagbabagong programmatic.
Ang Android SDK ay nagbibigay ng higit sa 25 built-in na klase ng span na sumasaklaw sa karamihan ng mga gawain sa pag-istilo ng teksto. Bawat klase ay nagpapatupad ng interface ng CharacterStyle o ParagraphStyle at tumatanggap ng mga parameter sa pamamagitan ng constructor. Lahat ng klase ay nasa paketeng android.text.style at magagamit nang hindi kumokonekta ng mga karagdagang dependency.
ForegroundColorSpan nagtatakda ng kulay ng teksto para sa tinukoy na saklaw, tumatanggap ng kulay sa format na int. Kinulayan ng BackgroundColorSpan ang background sa ilalim ng teksto, kapaki-pakinabang para sa pag-highlight ng mga query sa paghahanap. Itinatakda ng AbsoluteSizeSpan ang eksaktong laki ng font sa mga pixel, RelativeSizeSpan — isang multiplier na may kaugnayan sa base na laki ng teksto sa TextView.
StyleSpan tumatanggap ng mga constant na Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC o BOLD_ITALIC at binabago ang anyo ng mga karakter. Nagdaragdag ang UnderlineSpan ng salungguhit, StrikethroughSpan — strikethrough. Ang SuperscriptSpan at SubscriptSpan ay lumilikha ng superscript at subscript. Pinapayagan ng TypefaceSpan ang pagtatakda ng custom na font sa pamamagitan ng bagay na Typeface para sa isang saklaw ng teksto.
ClickableSpan ay isang abstract class para sa paglikha ng mga naki-click na bahagi ng teksto. Kapag pinindot, tinatawag ang pamamaraang onClick(). Para gumana ang mga click, ang TextView ay dapat may setMovementMethod(LinkMovementMethod.getInstance()). Ang URLSpan ay isang subclass ng ClickableSpan para sa mga hyperlink na may awtomatikong pagbubukas ng browser. Ang ClickableSpan ay madalas na pinagsama sa ForegroundColorSpan upang biswal na i-highlight ang link na may asul na kulay.
val spannable = SpannableString("Open developer.android.com")
spannable.setSpan(
URLSpan("https://developer.android.com"),
9, 31, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
spannable.setSpan(
ForegroundColorSpan(Color.BLUE),
9, 31, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
textView.movementMethod = LinkMovementMethod.getInstance()
Kung wala ang LinkMovementMethod, ang mga click sa URLSpan ay hindi mapoproseso. Ang MovementMethod ay responsable para sa pagharang ng mga touch event at paghahanap ng ClickableSpan sa posisyon ng pagpindot. Ang may kulay na span ay ginagawang nakikita ang link para sa user.
Ang pagtatrabaho sa SpannableString ay nagsisimula sa paglikha ng isang instance mula sa isang string ng teksto at sunud-sunod na paglalapat ng mga span sa pamamagitan ng pamamaraang setSpan(). Ang pamamaraan ay tumatanggap ng apat na parameter: ang bagay na span, posisyon ng simula, posisyon ng wakas, at mga flag. Pagkatapos itakda ang lahat ng span, ang bagay ay ipinapasa sa TextView sa pamamagitan ng setText().
Gagawa tayo ng string kung saan ang unang salita ay magiging pula at mas malaki ang laki. Para dito ginagamit ang ForegroundColorSpan para sa kulay at RelativeSizeSpan para sa scale. Ang parehong span ay inilalapat sa parehong saklaw nang hiwalay sa isa't isa — ang pagkakasunud-sunod ng pagtawag sa setSpan ay hindi mahalaga.
val text = "Header: remaining text"
val spannable = SpannableString(text)
val colorSpan = ForegroundColorSpan(Color.RED)
val sizeSpan = RelativeSizeSpan(1.5f)
spannable.setSpan(colorSpan, 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
spannable.setSpan(sizeSpan, 0, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = spannable
Ang mga karakter mula sa posisyon 0 hanggang 9 ay makakatanggap ng parehong estilo nang sabay. Awtomatikong inilalapat ng TextView ang lahat ng span sa pag-render — walang karagdagang tawag ang kinakailangan. Ang RelativeSizeSpan na may multiplier na 1.5f ay magpapalaki ng laki ng font ng 50% kumpara sa base.
Html.fromHtml() ay lumilikha ng isang bagay na Spanned mula sa isang HTML string, ngunit ang hanay ng mga suportadong tag ay limitado. Ang SpannableString ay nagbibigay ng buong kontrol sa bawat atributo nang walang mga limitasyon ng HTML. Kung kinakailangan i-convert ang HTML sa mga span na may kasunod na pagdaragdag ng mga custom na estilo, maaaring gamitin ang Html.fromHtml() bilang batayan, pagkatapos ay dagdagan ng mga span sa pamamagitan ng setSpan().
val htmlText = Html.fromHtml(
"<b>Important:</b> check the data",
Html.FROM_HTML_MODE_LEGACY
)
val spannable = SpannableString(htmlText)
spannable.setSpan(
ForegroundColorSpan(Color.RED),
0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
Ang resulta — ang tekstong "Mahalaga:" ay magiging bold (mula sa HTML) at pula (mula sa span). Ang ganitong paraan ay maginhawa kapag nagtatrabaho sa nilalaman ng server, kung saan ang bahagi ng pag-format ay itinakda sa pamamagitan ng HTML, at ang bahagi ay idinaragdag nang programmatic sa panig ng kliyente.
Pinapayagan ng SpannableString ang paglalapat ng walang limitasyong bilang ng span sa pareho o magkakapatong na saklaw. Ang pagsasama-sama ng mga span ay isang pangunahing bentahe kumpara sa HTML markup, kung saan ang mga nested tag ay maaaring magkasalungat. Ang mga span ay independyente at inilalapat nang sunud-sunod sa pag-render.
Halimbawa, ang isang bahagi ng teksto ay maaaring gawing sabay-sabay na bold, pula at naki-click. Para dito, tatlong span ang ginawa — StyleSpan, ForegroundColorSpan at ClickableSpan — at bawat isa ay inilalapat sa parehong saklaw. Ang pagkakasunud-sunod ng paglalapat ay hindi nakakaapekto sa resulta, dahil ang bawat span ay responsable para sa sarili nitong katangian ng teksto.
Kung ang mga span ng iba't ibang uri ay bahagyang nagpapatong, bawat isa ay gumagana nang hiwalay sa sarili nitong mga hangganan. ForegroundColorSpan sa saklaw na 0-10 at StyleSpan(BOLD) sa saklaw na 5-15 ay magbibigay ng pulang bold na teksto sa bahaging 5-10 at bold lamang sa 10-15. Walang lumalabas na salungatan, dahil binabago ng bawat span ang sarili nitong atributo sa pag-render.
Ang pamamaraang getSpans(int start, int end, Class type) ay nagbabalik ng array ng mga span na nasa loob ng tinukoy na saklaw. Ito ay kapaki-pakinabang para sa pagsusuri kung aling mga estilo ang nailapat na o para sa pagtanggal ng mga partikular na span. Gamit ang nextSpanTransition() maaaring mag-iterate sa mga hangganan ng pagbabago ng span — ito ang batayan ng paggana ng mga custom na TextView na kailangang malaman kung saan nagbabago ang estilo.
SpannableStringBuilder ay isang klase para sa hakbang-hakbang na pagbuo ng naka-istilong teksto na may kakayahang magpasok, magpalit at magtanggal ng mga fragment. Hindi tulad ng SpannableString, na ginawa mula sa isang handa na string at hindi nababago, pinapayagan ng Builder ang sunud-sunod na pagdaragdag ng mga bahagi ng teksto at pagtatalaga ng mga estilo sa daan. Ito ang perpektong pagpipilian para sa mga pinagsamang mensahe: mga log, chat, headline ng balita na may mga dynamic na label.
Ipinapatupad ng Builder ang mga interface na Spannable at Editable, na ginagawa itong katugma sa EditText. Maaaring i-edit ng user ang teksto, at ang mga estilo ay pinapanatili at tamang lumilipat kapag nagpapasok ng mga bagong karakter. Ang SpannableString, dahil hindi nababago, ay hindi angkop para sa mga editable field.
Ang pamamaraang append() ay nagbabalik ng builder mismo, na nagpapahintulot sa pagbuo ng isang kadena ng mga tawag. Pagkatapos magdagdag ng teksto, inilalapat ang mga span sa pamamagitan ng setSpan(). Ang mga posisyon ay ipinapahiwatig na may kaugnayan sa kasalukuyang haba ng builder. Ang Insert() at replace() ay magagamit din para sa mas tumpak na kontrol sa nilalaman.
val builder = SpannableStringBuilder()
.append("New ")
.append("comment")
val blue = ForegroundColorSpan(Color.BLUE)
val gray = ForegroundColorSpan(Color.GRAY)
builder.setSpan(blue, 0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
builder.setSpan(gray, 6, 17, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = builder
Ang tekstong "Bago " ay may kulay asul, at ang "komento" ay may kulay abo. Kapag nagpapasok ng mga karagdagang karakter sa pagitan nila, hindi maaapektuhan ng span ang bagong teksto dahil sa mga flag na EXCLUSIVE. Awtomatikong itinatama ng Builder ang mga panloob na index kapag nagbago.
Ang paggamit ng maraming bilang ng span ay nakakaapekto sa pagganap ng pag-render ng TextView. Bawat span ay tumatawag sa pamamaraang updateDrawState() o updateMeasureState() sa bawat muling pag-render. Inirerekomenda na limitahan ang bilang ng span bawat TextView sa 50–100 para sa komportableng trabaho sa mga mid-segment na device. Ang mga span na nagbabago ng laki ng teksto (RelativeSizeSpan, AbsoluteSizeSpan) ay nangangailangan ng muling pagkalkula ng layout sa bawat pagbabago, na mas mahal kaysa sa mga span para lamang sa kulay o salungguhit.
TextAppearanceSpan ay nagpapahintulot sa paglalapat ng isang buong hanay ng mga estilo mula sa xml resource na android:textAppearance sa isang operasyong setSpan(). Sa halip na tatlong hiwalay na span (kulay, laki, font) ginagamit ang isang TextAppearanceSpan na may reference sa estilo. Binabawasan nito ang bilang ng mga bagay at pinapasimple ang pagpapanatili — ang pagbabago ng estilo sa resource ay awtomatikong inilalapat sa lahat ng teksto na gumagamit ng span na ito.
Ang paglikha ng bagong instance ng span para sa bawat setSpan() ay nagdudulot ng karagdagang load sa garbage collector. Optimal na gumawa ng constant na bagay ng span kung paulit-ulit na inilalapat. Halimbawa, ang ForegroundColorSpan(Color.RED) ay maaaring i-save sa companion object at muling gamitin. Gayunpaman, ang mga span na may estado (ClickableSpan na may iba't ibang handler) ay dapat gawin nang isa-isa para sa bawat kaso.
Para sa pag-diagnose ng mga problema sa pagganap ng span, gamitin ang Layout Inspector sa Android Studio at GPU profiler. Kung ang TextView na may maraming span ay kapansin-pansing bumagal sa pag-scroll, isaalang-alang ang pagpapalit ng bahagi ng span ng mga static na estilo sa pamamagitan ng TextAppearanceSpan o pagbawas ng bilang ng span sa pamamagitan ng pagsasama-sama ng mga atributo sa custom na pagpapatupad ng UpdateAppearance.
Mga Madalas Itanong
String ay isang hindi nababagong pagkakasunod-sunod ng mga karakter na walang suporta sa estilo. Ang SpannableString ay nag-iimbak ng parehong mga karakter, ngunit karagdagang naglalaman ng isang array ng mga bagay na Span na may impormasyon sa pag-format. Tinutukoy ng TextView ang uri ng ipinasa na CharSequence at inilalapat ang mga span sa mga kaukulang saklaw sa pag-render. Binabalewala ng String ang anumang mga katangian ng estilo at ipinapakita bilang plain text.
Ang pamamaraang removeSpan(Object span) ay nagtatanggal ng isang partikular na span. Para sa kumpletong paglilinis, tawagan ang getSpans(0, length, Object::class.java), na nagbabalik ng array ng lahat ng span, at pagkatapos ay tanggalin ang bawat isa sa pamamagitan ng removeSpan. Bilang kahalili, gumawa ng bagong SpannableString(text.toString()) na walang span. Ang SpannableStringBuilder ay may pamamaraang clear() na nagtatanggal ng parehong teksto at span.
SpannableString ay gumagana sa EditText, ngunit para sa nai-edit na teksto mas mainam ang SpannableStringBuilder na nagpapatupad ng Editable. Ang EditText ay nangangailangan ng Editable interface para sa pagsubaybay sa mga pagbabago. Kung ang SpannableString ay ipinasa sa EditText, ang teksto ay ipapakita na may mga estilo, ngunit sa pag-edit, iko-convert ito ng Android sa Editable, na maaaring mag-reset ng ilang span.
Sa Jetpack Compose, ang mga Android SDK span ay hindi direktang ginagamit. Sa halip, ang Compose ay nagbibigay ng AnnotatedString — sarili nitong katumbas ng SpannableString na may katulad na kakayahan: SpanStyle para sa mga estilo ng indibidwal na karakter at ParagraphStyle para sa mga talata. Ang conversion ng SpannableString sa AnnotatedString ay posible sa pamamagitan ng buildAnnotatedString na may iteration sa mga span.
Gumawa ng klase na nagmamana mula sa CharacterStyle at i-override ang pamamaraang updateDrawState(TextPaint tp). Sa loob ng pamamaraan, baguhin ang mga katangian ng TextPaint: kulay, kapal ng linya, mga epekto. Para sa metric na pagbabago gamitin ang UpdateLayout o MetricAffectingSpan. Ang mga custom na span ay inilalapat sa pamamagitan ng setSpan() tulad ng mga built-in na span.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din