Aralıklar

Yazma yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Yazma işleminde metni nasıl kullanacağınızı öğrenin.

Aralıklar, metni karakter veya paragraf düzeyinde biçimlendirmek için kullanabileceğiniz güçlü işaretleme nesneleridir. Metin nesnelerine aralıklar ekleyerek metni çeşitli şekillerde değiştirebilirsiniz. Örneğin, renk ekleyebilir, metni tıklanabilir hale getirebilir, metin boyutunu ölçeklendirebilir ve metni özelleştirilmiş bir şekilde çizebilirsiniz. Ayrıca aralıklar TextPaint özelliklerini değiştirebilir, Canvas üzerinde çizim yapabilir ve metin düzenini değiştirebilir.

Android, çeşitli yaygın metin stil verme kalıplarını kapsayan birkaç tür aralık sağlar. Özel stil uygulamak için kendi aralıklarınızı da oluşturabilirsiniz.

Kapsam oluşturma ve uygulama

Bir kapsam oluşturmak için aşağıdaki tabloda listelenen sınıflardan birini kullanabilirsiniz. Sınıflar, metnin kendisinin değiştirilebilir olup olmamasına, metin işaretlemenin değiştirilebilir olup olmamasına ve aralık verilerini içeren temel veri yapısına göre farklılık gösterir.

Sınıf Değiştirilebilir metin Değiştirilebilir işaretleme Veri yapısı
SpannedString Hayır Hayır Doğrusal dizi
SpannableString Hayır Evet Doğrusal dizi
SpannableStringBuilder Evet Evet Aralık ağacı

Üç sınıf da Spanned arayüzünü genişletir. SpannableString ve SpannableStringBuilder, Spannable arayüzünü de genişletir.

Hangisini kullanacağınıza nasıl karar vereceğiniz aşağıda açıklanmıştır:

  • Oluşturduktan sonra metni veya işaretlemeyi değiştirmiyorsanız SpannedString kullanın.
  • Tek bir metin nesnesine az sayıda aralık eklemeniz gerekiyorsa ve metnin kendisi salt okunursa SpannableString kullanın.
  • Oluşturduktan sonra metni değiştirmeniz ve metne aralıklar eklemeniz gerekiyorsa SpannableStringBuilder simgesini kullanın.
  • Metnin kendisi salt okunur olsa da olmasa da bir metin nesnesine çok sayıda aralık eklemeniz gerekiyorsa SpannableStringBuilder kullanın.

Bir aralık uygulamak için setSpan(Object _what_, int _start_, int _end_, int _flags_) işlevini bir Spannable nesnesinde çağırın. what parametresi, metne uyguladığınız aralığı ifade eder. start ve end parametreleri ise aralığı uyguladığınız metin bölümünü belirtir.

Bir aralığın sınırları içine metin eklerseniz aralık, eklenen metni içerecek şekilde otomatik olarak genişler. Metin, aralık sınırlarına (yani başlangıç veya bitiş dizinlerine) yerleştirildiğinde, flags parametresi, aralığın yerleştirilen metni içerecek şekilde genişleyip genişlemeyeceğini belirler. Eklenen metni dahil etmek için Spannable.SPAN_EXCLUSIVE_INCLUSIVE işaretini, eklenen metni hariç tutmak için Spannable.SPAN_EXCLUSIVE_EXCLUSIVE işaretini kullanın.

Aşağıdaki örnekte, bir ForegroundColorSpan öğesinin bir dizeye nasıl ekleneceği gösterilmektedir:

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
);
Kısmen kırmızı olan gri bir metni gösteren resim.
1.şekil ForegroundColorSpan ile biçimlendirilmiş metin.

Aralık Spannable.SPAN_EXCLUSIVE_INCLUSIVE kullanılarak ayarlandığından, aralık sınırlarına eklenen metni içerecek şekilde genişler. Bu durum aşağıdaki örnekte gösterilmiştir:

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)");
SPAN_EXCLUSIVE_INCLUSIVE kullanıldığında aralığın nasıl daha fazla metin içerdiğini gösteren bir resim.
Şekil 2. Spannable.SPAN_EXCLUSIVE_INCLUSIVE kullanılırken kapsam, ek metinleri de içerecek şekilde genişler.

Aynı metne birden fazla aralık ekleyebilirsiniz. Aşağıdaki örnekte, kalın ve kırmızı renkli metnin nasıl oluşturulacağı gösterilmektedir:

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
);
Birden fazla aralığı olan bir metni gösteren resim: `ForegroundColorSpan(Color.RED)` ve `StyleSpan(BOLD)`
3.şekil Birden fazla aralığı olan metin: ForegroundColorSpan(Color.RED) ve StyleSpan(BOLD).

Android kapsam türleri

Android, android.text.style paketinde 20'den fazla span türü sunar. Android, aralıkları iki temel şekilde sınıflandırır:

  • Aralığın metni etkileme şekli: Bir aralık, metin görünümünü veya metin metriklerini etkileyebilir.
  • Kapsam: Bazı kapsamlar tek tek karakterlere uygulanabilirken diğerleri tüm paragrafa uygulanmalıdır.
Farklı kapsam kategorilerini gösteren bir resim
Şekil 4. Android aralıklarının kategorileri.

Aşağıdaki bölümlerde bu kategoriler daha ayrıntılı olarak açıklanmaktadır.

Metin görünümünü etkileyen aralıklar

Karakter düzeyinde uygulanan bazı aralıklar, metin veya arka plan rengini değiştirme, altı çizili veya üstü çizili metin ekleme gibi metin görünümünü etkiler. Bu aralıklar, CharacterStyle sınıfını genişletir.

Aşağıdaki kod örneğinde, metnin altını çizmek için UnderlineSpan nasıl uygulanacağı gösterilmektedir:

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` kullanarak metnin altını çizme işleminin nasıl yapılacağını gösteren bir resim
Şekil 5. UnderlineSpan kullanılarak altı çizilmiş metin.

Yalnızca metin görünümünü etkileyen aralıklar, düzenin yeniden hesaplanmasını tetiklemeden metnin yeniden çizilmesini tetikler. Bu aralıklar UpdateAppearance özelliğini uygular ve CharacterStyle özelliğini genişletir. CharacterStyle alt sınıfları, TextPaint güncelleme erişimi sağlayarak metnin nasıl çizileceğini tanımlar.

Metin metriklerini etkileyen aralıklar

Karakter düzeyinde uygulanan diğer aralıklar, satır yüksekliği ve metin boyutu gibi metin metriklerini etkiler. Bu aralıklar, MetricAffectingSpan sınıfını genişletir.

Aşağıdaki kod örneği, metin boyutunu %50 artıran bir RelativeSizeSpan oluşturur:

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 kullanımını gösteren bir resim
6.şekil RelativeSizeSpan kullanılarak büyütülmüş metin.

Metin metriklerini etkileyen bir kapsam uygulandığında, gözlemleyen nesne doğru düzen ve oluşturma için metni yeniden ölçer. Örneğin, metin boyutunu değiştirmek kelimelerin farklı satırlarda görünmesine neden olabilir. Yukarıdaki span'in uygulanması, yeniden ölçümlemeyi, metin düzeninin yeniden hesaplanmasını ve metnin yeniden çizilmesini tetikler.

Metin metriklerini etkileyen aralıklar, MetricAffectingSpan sınıfını genişletir. Bu sınıf, alt sınıfların TextPaint'ye erişim sağlayarak aralığın metin ölçümünü nasıl etkileyeceğini tanımlamasına olanak tanıyan soyut bir sınıftır. MetricAffectingSpan, CharacterStyle öğesini genişlettiği için alt sınıflar, metnin karakter düzeyindeki görünümünü etkiler.

Paragrafları etkileyen aralıklar

Bir aralık, paragraf düzeyinde metni de etkileyebilir. Örneğin, bir metin bloğunun hizalamasını veya kenar boşluğunu değiştirebilir. Paragrafların tamamını etkileyen aralıklar ParagraphStyle ile uygulanır. Bu aralıkları kullanmak için, sonundaki yeni satır karakteri hariç olmak üzere tüm paragrafa eklemeniz gerekir. Bir paragraf aralığını tam bir paragraf dışında bir şeye uygulamaya çalışırsanız Android aralığı hiç uygulamaz.

Şekil 8'de Android'in metindeki paragrafları nasıl ayırdığı gösterilmektedir.

7.şekil Android'de paragraflar yeni satır (\n) karakteriyle sonlanır.

Aşağıdaki kod örneğinde bir paragrafa QuoteSpan uygulanmaktadır. Aralığı bir paragrafın başlangıcı veya sonu dışında herhangi bir konuma eklerseniz Android'in stili hiç uygulamayacağını unutmayın.

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 örneğini gösteren bir resim
8. şekil. Paragrafa uygulanan QuoteSpan

Özel aralıklar oluşturma

Mevcut Android aralıklarında sunulan işlevlerden daha fazlasına ihtiyacınız varsa özel bir aralık uygulayabilirsiniz. Kendi aralığınızı uygularken aralığınızın metni karakter düzeyinde mi yoksa paragraf düzeyinde mi etkileyeceğine ve metnin düzenini mi yoksa görünümünü mü etkileyeceğine karar verin. Bu, hangi temel sınıfları genişletebileceğinizi ve hangi arayüzleri uygulamanız gerekebileceğini belirlemenize yardımcı olur. Referans için aşağıdaki tabloyu kullanın:

Senaryo Sınıf veya arayüz
Kapsamınız, metni karakter düzeyinde etkiler. CharacterStyle
Kapsamınız, metin görünümünü etkiler. UpdateAppearance
Kapsamınız, metin metriklerini etkiler. UpdateLayout
Kapsamınız, metni paragraf düzeyinde etkiler. ParagraphStyle

Örneğin, metin boyutunu ve rengini değiştiren özel bir aralık uygulamanız gerekiyorsa RelativeSizeSpan öğesini genişletin. Devralma yoluyla RelativeSizeSpan genişletir CharacterStyle ve iki Update arayüzünü uygular. Bu sınıf zaten updateDrawState ve updateMeasureState için geri çağırma işlevleri sağladığından, özel davranışınızı uygulamak için bu geri çağırma işlevlerini geçersiz kılabilirsiniz. Aşağıdaki kod, RelativeSizeSpan ile genişleyen ve updateDrawState geri çağırmasını geçersiz kılarak TextPaint rengini ayarlayan özel bir aralık oluşturur:

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);
    }
}

Bu örnekte, özel aralık oluşturma işlemi gösterilmektedir. Metne RelativeSizeSpan ve ForegroundColorSpan uygulayarak aynı efekti elde edebilirsiniz.

Test aralığı kullanımı

Spanned arayüzü, hem aralıkları ayarlamanıza hem de metinden aralıkları almanıza olanak tanır. Test sırasında, doğru aralıkların doğru konumlara eklendiğini doğrulamak için Android JUnit testi uygulayın. Text Styling örnek uygulamasında, metne BulletPointSpan ekleyerek madde işaretlerine biçimlendirme uygulayan bir span bulunur. Aşağıdaki kod örneğinde, madde işaretlerinin beklendiği gibi görünüp görünmediğinin nasıl test edileceği gösterilmektedir:

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));
}

Daha fazla test örneği için GitHub'daki MarkdownBuilderTest'e bakın.

Özel aralıkları test etme

Aralıkları test ederken TextPaint öğesinin beklenen değişiklikleri içerdiğini ve Canvas öğenizde doğru öğelerin göründüğünü doğrulayın. Örneğin, bazı metinlere madde işareti ekleyen özel bir aralık uygulaması düşünün. Madde işaretinin belirli bir boyutu ve rengi vardır. Çizilebilir alanın sol kenar boşluğu ile madde işareti arasında bir boşluk bulunur.

Bu sınıfın davranışını, aşağıdaki noktaları kontrol eden bir AndroidJUnit testi uygulayarak test edebilirsiniz:

  • Kapsamı doğru şekilde uygularsanız tuvalde belirtilen boyut ve renkte bir madde işareti görünür. Sol kenar boşluğu ile madde işareti arasında uygun boşluk bulunur.
  • Kapsamı uygulamazsanız özel davranışların hiçbiri görünmez.

Bu testlerin nasıl uygulandığını GitHub'daki TextStyling örneğinde görebilirsiniz.

Canvas'ı taklit ederek, taklit edilen nesneyi drawLeadingMargin() yöntemine ileterek ve doğru yöntemlerin doğru parametrelerle çağrıldığını doğrulayarak Canvas etkileşimlerini test edebilirsiniz.

Daha fazla kapsam testi örneğini BulletPointSpanTest'te bulabilirsiniz.

Aralıkların kullanımıyla ilgili en iyi uygulamalar

İhtiyaçlarınıza bağlı olarak, TextView içinde metin ayarlamanın belleği verimli kullanan çeşitli yolları vardır.

Temel metni değiştirmeden bir aralığı ekleme veya kaldırma

TextView.setText() Aralıkları farklı şekilde işleyen birden fazla aşırı yükleme içerir. Örneğin, aşağıdaki kodu kullanarak bir Spannable metin nesnesi ayarlayabilirsiniz:

Kotlin

textView.setText(spannableObject)

Java

textView.setText(spannableObject);

Bu setText() aşırı yüklemesi çağrıldığında TextView, Spannable öğenizin SpannedString olarak bir kopyasını oluşturur ve bunu CharSequence olarak bellekte tutar. Bu, metninizin ve aralıklarınızın değişmez olduğu anlamına gelir. Bu nedenle, metni veya aralıkları güncellemeniz gerektiğinde yeni bir Spannable nesnesi oluşturup setText() işlevini tekrar çağırmanız gerekir. Bu işlem, düzenin yeniden ölçülmesini ve yeniden çizilmesini de tetikler.

Aralıkların değiştirilebilir olması gerektiğini belirtmek için aşağıdaki örnekte gösterildiği gibi setText(CharSequence text, TextView.BufferType type) kullanabilirsiniz:

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);

Bu örnekte, BufferType.SPANNABLE parametresi, TextView öğesinin SpannableString oluşturmasına neden olur ve TextView tarafından tutulan CharSequence nesnesi artık değiştirilebilir işaretlemeye ve değiştirilemez metne sahiptir. Arası güncelleyebilmek için metni Spannable olarak alın ve ardından aralıkları gerektiği şekilde güncelleyin.

Aralıkları eklediğinizde, kaldırdığınızda veya yeniden konumlandırdığınızda TextView, metindeki değişikliği yansıtacak şekilde otomatik olarak güncellenir. Mevcut bir aralığın dahili bir özelliğini değiştirirseniz görünümle ilgili değişiklikler yapmak için invalidate(), metrikle ilgili değişiklikler yapmak için requestLayout() işlevini çağırın.

TextView'da metni birden çok kez ayarlama

Bazı durumlarda (ör. RecyclerView.ViewHolder kullanırken) TextView öğesini yeniden kullanmak ve metni birden fazla kez ayarlamak isteyebilirsiniz. Varsayılan olarak, BufferType ayarını yapıp yapmadığınızdan bağımsız olarak TextView, CharSequence nesnesinin bir kopyasını oluşturur ve bellekte tutar. Bu nedenle, tüm TextView güncellemeler kasıtlıdır. Metni güncellemek için orijinal TextView nesneyi güncelleyemezsiniz.CharSequence Bu, her yeni metin ayarladığınızda TextView simgesinin yeni bir nesne oluşturduğu anlamına gelir.

Bu süreç üzerinde daha fazla kontrol sahibi olmak ve ek nesne oluşturmayı önlemek istiyorsanız kendi Spannable.Factory öğenizi uygulayabilir ve newSpannable() öğesini geçersiz kılabilirsiniz. Yeni bir metin nesnesi oluşturmak yerine, aşağıdaki örnekte gösterildiği gibi mevcut CharSequence öğesini Spannable olarak yayınlayıp döndürebilirsiniz:

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;
    }
};

Metni ayarlarken textView.setText(spannableObject, BufferType.SPANNABLE) kullanmanız gerekir. Aksi takdirde, kaynak CharSequence, Spanned örneği olarak oluşturulur ve Spannable'ye yayınlanamaz. Bu da newSpannable()'ün ClassCastException oluşturmasına neden olur.

newSpannable() geçersiz kılındıktan sonra TextView'ye yeni Factory'yi kullanmasını söyleyin:

Kotlin

textView.setSpannableFactory(spannableFactory)

Java

textView.setSpannableFactory(spannableFactory);

Spannable.Factory nesnesini, TextView referansını aldıktan hemen sonra bir kez ayarlayın. RecyclerView kullanıyorsanız görünümlerinizi ilk kez şişirdiğinizde Factory nesnesini ayarlayın. Bu, RecyclerView yeni bir öğeyi ViewHolder öğenize bağladığında fazladan nesne oluşturulmasını önler.

Dahili span özelliklerini değiştirme

Yalnızca değiştirilebilir bir aralığın iç özelliğini (ör. özel madde işaretli aralıktaki madde işareti rengi) değiştirmeniz gerekiyorsa aralığa oluşturulduğu sırada referans vererek setText() işlevini birden çok kez çağırmanın getireceği ek yükten kaçınabilirsiniz. Aralığı değiştirmeniz gerektiğinde referansı değiştirebilir ve ardından değiştirdiğiniz özelliğin türüne bağlı olarak TextView üzerinde invalidate() veya requestLayout() işlevini çağırabilirsiniz.

Aşağıdaki kod örneğinde, özel madde işareti uygulamasının varsayılan rengi kırmızıdır ve bir düğmeye dokunulduğunda griye döner:

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();
            }
        });
    }
}

Android KTX uzantı işlevlerini kullanma

Android KTX, aralıklarla çalışmayı kolaylaştıran uzantı işlevleri de içerir. Daha fazla bilgi edinmek için androidx.core.text paketinin belgelerine bakın.