Aralıklar

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

Kapsamlar, web’de metin stilini ayarlamak için kullanabileceğiniz güçlü işaretleme nesneleridir. karakter veya paragraf düzeyinde olarak ayarlayabilirsiniz. Metin nesnelerine aralık ekleyerek metni renk ekleme, metni tıklanabilir hale getirme, metin oluşturma gibi ve metni özelleştirilmiş bir şekilde çizme olanağı sunar. Kapsamlar TextPaint özelliklerini değiştirin, bir üzerine çizim yapın Canvas ve metin düzenini değiştirin.

Android, yaygın olarak kullanılan çeşitli metinleri kapsayan çeşitli aralık türleri sağlar oluşturabilirsiniz. Özel stil uygulamak için kendi aralıklarınızı da oluşturabilirsiniz.

Kapsam oluşturma ve uygulama

Kapsam oluşturmak için aşağıdaki tabloda listelenen sınıflardan birini kullanabilirsiniz. Sınıflar, metnin değiştirilip değiştirilmediğine, işaretlemesi değiştirilebilir ve span verilerini içeren temel veri yapısı.

Sınıf Değişebilir metin Değişebilir 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ıfta da Spanned kullanır. SpannableString ve SpannableStringBuilder, Spannable arayüzü.

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

  • Oluşturma işleminden sonra metni veya işaretlemeyi değiştirmiyorsanız SpannedString
  • Tek bir metin nesnesine az sayıda aralık eklemeniz ve metnin kendisi salt okunur; SpannableString kullanın.
  • Oluşturma işleminden sonra metni değiştirmeniz ve metin için SpannableStringBuilder kullanın.
  • Bir metin nesnesine çok sayıda aralık eklemeniz gerekiyorsa salt okunur olup olmadığını kontrol etmek için SpannableStringBuilder kullanın.

Aralık uygulamak için setSpan(Object _what_, int _start_, int _end_, int _flags_) numaralı telefonu arayın Spannable nesnesinde oturum açın. what parametresi, kullandığınız aralığı belirtir. metne uygulanıp start ve end parametreleri test eder.

Bir kapsamın sınırlarına metin eklerseniz aralık otomatik olarak eklenen metni dahil etmesi gerekir. Kapak yerine metin eklerken sınırlar (yani start veya end dizinlerinde) flags parametresi, aralığın eklenen metni içerecek şekilde genişletilip genişletilmeyeceğini belirler. Tekliflerinizi otomatikleştirmek ve optimize etmek için "the" Spannable.SPAN_EXCLUSIVE_INCLUSIVE eklenen metni dahil etmek için flag'i kullanın ve Spannable.SPAN_EXCLUSIVE_EXCLUSIVE kullanabilirsiniz.

Aşağıdaki örnekte bir ForegroundColorSpan itibarıyla bir dize:

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 metin gösteren resim.
Şekil 1. Metnin stil özellikleri ForegroundColorSpan

Aralık Spannable.SPAN_EXCLUSIVE_INCLUSIVE kullanılarak ayarlandığı için aralık Aşağıdaki gibi aralık sınırlarına eklenen metni içerecek şekilde genişler: şu örneği inceleyin:

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 resim.
Şekil 2. Aralık, aşağıdakileri içerecek şekilde genişler: ek metinlerin kullanılması Spannable.SPAN_EXCLUSIVE_INCLUSIVE

Aynı metne birden çok aralık ekleyebilirsiniz. Aşağıdaki örnekte, kalın ve kırmızı metin oluşturmak için:

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 çok aralık içeren bir metin gösteren resim: "ForegroundColorSpan(Color.RED)" ve "StyleSpan(BOLD)"
Şekil 3. Birden çok aralıklı metin: ForegroundColorSpan(Color.RED) ve StyleSpan(BOLD).

Android aralık türleri

Android, API'de 20'den fazla aralık türü sunar. android.text.style paketinden ekleyin. Android, aralıkları iki temel şekilde kategorilere ayırır:

  • Yayılma, metni nasıl etkiler? Kapsama alanı, metnin görünümünü veya metni etkileyebilir kullanabilirsiniz.
  • Genişleme kapsamı: Bazı aralıklar tek tek karakterlere uygulanabilir, bazıları ise tek tek karakterlere uygulanabilir tüm paragrafa uygulanmalıdır.
ziyaret edin.
Farklı aralık kategorilerini gösteren resim
4. Şekil. Android aralıkları.

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ı kapsamlar, metin görünümünü etkiler: Örneğin, Metnin veya arka plan renginin değiştirilmesi, alt çizgi veya üstü çizili ekleme. Bu kapsamı CharacterStyle sınıfı.

Aşağıdaki kod örneğinde, alt çizgiye UnderlineSpan nasıl uygulanacağı gösterilmektedir metin:

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);
"altlineSpan" kullanarak metnin altını nasıl çizeceğinizi gösteren resim
Şekil 5. Altı çizili metin UnderlineSpan

Yalnızca metin görünümünü etkileyen aralıklar, metnin herhangi bir öğe olmadan yeniden çizilmesini düzenin yeniden hesaplanmasını tetikler. Bu aralıklar UpdateAppearance ve uzat CharacterStyle. CharacterStyle alt sınıf, TextPaint.

Metin metriklerini etkileyen aralıklar

Karakter düzeyinde uygulanan diğer aralıklar, satır gibi metin metriklerini etkiler ve metin boyutunu seçin. Bu aralıklar MetricAffectingSpan sınıfını kullanır.

Aşağıdaki kod örneği, RelativeSizeSpan metin boyutunu %50 büyütür:

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);
FocusSizeSpan kullanımını gösteren resim
Şekil 6. Metin, şununla büyütülür: RelativeSizeSpan

Metin metriklerini etkileyen bir aralık uygulandığında, gözlemlenen nesne Doğru düzen ve oluşturma için metni yeniden ölçün. Örneğin, metin boyutu kelimelerin farklı satırlarda görünmesine neden olabilir. Önceki uygulama spanlama, metin düzeninin yeniden hesaplanmasını ve yeniden çizilmesini tetiklemesini metin.

Metin metriklerini etkileyen aralıklar MetricAffectingSpan sınıfını genişletir. alt sınıfların, aralığın metin ölçümünü nasıl etkilediğini tanımlamasına olanak tanıyan soyut sınıf (TextPaint) erişimi sağlayarak. MetricAffectingSpan uzantısından itibaren CharacterSpan, alt sınıflar karakterdeki metnin görünümünü etkiler seviyesinde olmalıdır.

Paragrafları etkileyen aralıklar

Yayılma, paragraf düzeyindeki metni de etkileyebilir, örneğin veya kenar boşluğunu kullanabilirsiniz. Tüm paragrafları etkileyen aralıklar ParagraphStyle uygulayın. Alıcı: kapsamları kullanırsanız, bu aralıkların bitişi hariç paragrafın tamamına eklersiniz yeni satır karakteri ekleyin. Bir paragraf kapsamını Android, aralığı hiç uygulamaz.

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

Şekil 7. Android'de paragraflar yeni satır (\n) karakteri.

Aşağıdaki kod örneği, QuoteSpan öğesini bir paragrafa ekleyebilirsiniz. Lütfen aralığı bir reklamın başlangıcı veya bitişi dışında herhangi bir konuma paragrafı nedeniyle Android, stili hiç uygulamaz.

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
Şekil 8. QuoteSpan bir paragrafa uygulanır.

Özel aralıklar oluşturma

Mevcut Android sürümünde sağlanandan daha fazla işleve 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 etkilediği metnin düzenini veya görünümünü de etkileyip etkilemediğini belirler. Bu, kullanıcıların genişletebileceğiniz temel sınıfları ve ihtiyaç duyabileceğiniz arayüzleri belirleme pek çok yolu vardır. Referans için aşağıdaki tabloyu kullanın:

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

Örneğin, metin boyutunu ve değerini değiştiren özel bir kapsam uygulamanız renk, RelativeSizeSpan öğesini uzat. Devralma yoluyla, RelativeSizeSpan CharacterStyle öğesini genişletir ve iki Update arayüzünü uygular. Bu tarihten itibaren sınıfı zaten updateDrawState ve updateMeasureState için geri çağırmalar sağlıyor. özel davranışınızı uygulamak için bu geri çağırmaları geçersiz kılabilirsiniz. İlgili içeriği oluşturmak için kullanılan aşağıdaki kod, RelativeSizeSpan ve TextPaint renginin rengini ayarlamak için updateDrawState geri çağırmasını geçersiz kılar:

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ığın nasıl oluşturulacağı gösterilmektedir. Tekliflerinizi otomatik olarak metne RelativeSizeSpan ve ForegroundColorSpan uygulayarak etki yaratırsınız.

Aralık kullanımını test et

Spanned arayüzü, hem aralıkları ayarlamanıza hem de metin. Test sırasında bir Android JUnit uygulayın Doğru aralıkların eklendiğini doğrulamak için test'i kullanın doğru konumda. Metin Stili örneği uygulama Metne BulletPointSpan ekleyin. Aşağıdaki kod örneğinde, Google Yapay Zeka'nın madde işaretlerinin beklendiği gibi görünüp görünmediğini belirtin:

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 bkz. GitHub'da MarkdownBuilderTest

Özel aralıkları test etme

Test aralıkları sırasında TextPaint öğesinin beklenen içeriği içerdiğini doğrulayın ve Canvas üzerinde doğru öğelerin görünmesini sağlayın. Örneğin, Örneğin, biraz metin. Madde işaretinde belirtilen boyut ve renk var ve boşluk var madde işareti arasına girin.

Bir AndroidJUnit testi uygulayarak bu sınıfın davranışını test edebilirsiniz. şunları kontrol ediyor:

  • Kapsamı doğru uygularsanız, belirtilen boyutta bir madde işareti ve tuvalde renk görünüyor ve sol ile arasında uygun boşluk var girin.
  • Kapsamı uygulamazsanız özel davranışların hiçbiri görünmez.

Bu testlerin uygulanma şeklini TextStyling sample'ı tıklayın.

Tuvalle ilgili bir model oluşturup modellenmiş öğeyi ileterek Canvas etkileşimlerini test edebilirsiniz. nesne drawLeadingMargin() yöntemini kullanarak ve doğru yöntemlerin doğru yöntemle çağrıldığını parametreleridir.

Daha fazla span test örneğini şurada bulabilirsiniz: BulletPointSpanTest.

Aralıkları kullanmayla ilgili en iyi uygulamalar

TextView cihazındaki metni ayarlamanın bellek açısından verimli birkaç yolu vardır. görünür.

Temel metni değiştirmeden bir yayılma metni ekleme veya çıkarma

TextView.setText() içeren öğeler, spanları farklı şekilde işleyen birden çok aşırı yükleme içerir. Örneğin, şunları yapabilirsiniz: aşağıdaki kodla bir Spannable metin nesnesi ayarlayın:

Kotlin

textView.setText(spannableObject)

Java

textView.setText(spannableObject);

Bu aşırı setText() yüklemesi çağrılırken TextView, Spannable, SpannedString olarak hatırlanır ve CharSequence olarak bellekte tutulur. Bu, metninizin ve aralıkların sabit olduğu anlamına gelir. Dolayısıyla, metni veya kapsamları güncelleyin, yeni bir Spannable nesnesi oluşturun ve çağrıyı setText(), bu da aynı zamanda elektriğin yeniden ölçülmesini ve kullanır.

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

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 bir SpannableString oluşturmasına neden olur ve TextView tarafından tutulan CharSequence nesnesi artık değişebilir işaretlemeye sahip ve sabit metindir. Kapsamı güncellemek için metni Spannable olarak alın ve ardından aralıkları gerektiği gibi güncelleyin.

Aralıkları eklediğinizde, ayırdığınızda veya yeniden konumlandırdığınızda TextView otomatik olarak yansıtması için e-posta alır. Dahili bir özelliği değiştirirseniz mevcut bir kapsamın adı, görünümle ilgili değişiklikler yapmak için invalidate() veya Metrikle ilgili değişiklikler yapmak için requestLayout().

TextView'da metni birden çok kez ayarlama

Bazı durumlarda, örneğin RecyclerView.ViewHolder bir TextView metnini yeniden kullanmak ve metni birden çok kez ayarlamak isteyebilirsiniz. Ölçüt varsayılan olarak, BufferType değerini ayarlayıp ayarlamamanızdan bağımsız olarak, TextView CharSequence nesnesinin bir kopyasını oluşturur ve bunu bellekte tutar. Bu da tüm TextView güncelleme bilinçli olarak yapıldı. Orijinali güncelleyemezsiniz Metni güncellemek için CharSequence nesnesi. Bu, her yeni ayar yaptığınızda metnini ayarlarsanız TextView yeni bir nesne oluşturur.

Bu işlem üzerinde daha fazla kontrol sahibi olmak ve ekstra nesneden kaçınmak isterseniz kendi oluşturduğunuz içerikleri Spannable.Factory ve geçersiz kılma newSpannable(). Yeni bir metin nesnesi oluşturmak yerine mevcut metin nesnesini yayınlayabilir ve döndürebilirsiniz Aşağıdaki örnekte gösterildiği gibi, Spannable olarak CharSequence:

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

Aşağıdaki durumlarda textView.setText(spannableObject, BufferType.SPANNABLE) kullanmanız gerekir: metni de belirleyebilirsiniz. Aksi takdirde, CharSequence kaynağı Spanned olarak oluşturulur örneğe dönüştürülemiyor ve Spannable öğesine dönüştürülemiyor. Bu da newSpannable() için ClassCastException.

newSpannable() öğesini geçersiz kıldıktan sonra TextView adlı kullanıcıdan yeni Factory öğesini kullanmasını isteyin:

Kotlin

textView.setSpannableFactory(spannableFactory)

Java

textView.setSpannableFactory(spannableFactory);

Spannable.Factory nesnesini bir kez, referans aldıktan hemen sonra ayarlayın TextView. RecyclerView kullanıyorsanızFactory önce görüntüleme sayınızı artırmanız gerekir. Böylece, RecyclerView, yeni bir öğeyi ViewHolder cihazınıza bağlar.

Dahili span özelliklerini değiştirme

Değişebilir bir aralığın yalnızca dahili bir özelliğini (ör. özel bir madde işareti aralığında madde işareti rengi kullanarak Oluşturulan aralığın referansını koruyarak birden çok kez setText(). Kapsamı değiştirmeniz gerektiğinde referansı değiştirebilir ve ardından Türüne bağlı olarak TextView üzerinde invalidate() veya requestLayout() yeni bir özellik ekleyin.

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

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ı sağlayan uzantı işlevleri de içerir. daha kolay olur. Daha fazla bilgi edinmek için androidx.core.text paketinden yararlanın.