Kavramlar ve Jetpack Compose uygulaması
Dize kaynağı, uygulamanız için isteğe bağlı metin stili ve biçimlendirme içeren metin dizeleri sağlar. Uygulamanıza dizeler sağlayabilecek üç tür kaynak vardır:
- String
- Tek bir dize sağlayan XML kaynağı.
- Dize Dizisi (String Array)
- Dizi dizisi sağlayan XML kaynağı.
- Miktar Dizeleri (Çoğullar)
- Çoğul oluşturma için farklı dizeler içeren XML kaynağı.
Tüm dizeler, bazı stil işaretlemelerini ve biçimlendirme bağımsız değişkenlerini uygulayabilir. Dizeleri stil verme ve biçimlendirme hakkında bilgi edinmek için Biçimlendirme ve Stil Verme bölümüne bakın.
Dize
Uygulamadan veya diğer kaynak dosyalarından (ör. XML düzeni) başvurulabilen tek bir dize.
- Dosya konumu:
res/values/filename.xml
Dosya adı rastgeledir.<string>öğesininname, kaynak kimliği olarak kullanılır.- derlenmiş kaynak veri türü:
- ,
Stringöğesine yönelik kaynak işaretçisi. - kaynak referansı:
-
Java'da:
R.string.string_name
XML'de:@string/string_name - söz dizimi:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- öğeler:
- örnek:
- XML dosyası
res/values/strings.xmlkonumuna kaydedildi:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Bu düzen XML'si, bir Görünüm'e dize uygular:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
Bu uygulama kodu bir dizeyi alır:
Bir dizeyi almak için
getString(int)veyagetText(int)kullanabilirsiniz.getText(int), dizeye uygulanan tüm zengin metin stilini korur.
Dize dizisi
Uygulamadan referans verilebilecek bir dizeler dizisi.
- Dosya konumu:
res/values/filename.xml
Dosya adı rastgeledir.<string-array>öğesininname, kaynak kimliği olarak kullanılır.- derlenmiş kaynak veri türü:
Stringdizisine yönelik kaynak işaretçisi.- kaynak referansı:
-
Java'da:
R.array.string_array_name
XML'de:@[package:]array/string_array_name - söz dizimi:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- öğeler:
- örnek:
- XML dosyası
res/values/strings.xmlkonumuna kaydedildi: Bu uygulama kodu bir dize dizisi alır:<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="planets_array"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> <item>Mars</item> </string-array> </resources>
Kotlin
val array: Array<String> =
resources.getStringArray(R.array.planets_array)Java
Resources res =
getResources(); String[] planets = res.getStringArray(R.array.planets_array);
Miktar dizeleri (çoğullar)
Farklı dillerde, miktarla ilgili dilbilgisi kuralları farklıdır. Örneğin, İngilizcede 1 sayısı özel bir durumdur. "1 kitap" yazıyoruz ancak diğer miktarlar için "n kitap" yazıyoruz. Tekil ve çoğul arasındaki bu ayrım çok yaygındır ancak diğer dillerde daha ince ayrımlar yapılır. Android tarafından desteklenen tam küme zero, one, two, few, many ve other şeklindedir.
Belirli bir dil ve miktar için hangi büyük/küçük harf durumunun kullanılacağına karar verme kuralları çok karmaşık olabilir. Bu nedenle Android, sizin için uygun kaynağı seçebilmeniz amacıyla getQuantityString() gibi yöntemler sunar.
API 24 ve sonraki sürümlerde bunun yerine çok daha güçlü olan ICU MessageFormat sınıfını kullanabilirsiniz.
- Dosya konumu:
res/values/filename.xml
Dosya adı rastgeledir.<plurals>öğesininname, kaynak kimliği olarak kullanılır.- kaynak referansı:
-
Java'da:
R.plurals.plural_name - söz dizimi:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="plural_name"> <item quantity=["zero" | "one" | "two" | "few" | "many" | "other"] >text_string</item> </plurals> </resources>
- öğeler:
- örnek:
- XML dosyası
res/values/strings.xmlkonumuna kaydedildi:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <!-- As a developer, you should always supply "one" and "other" strings. Your translators will know which strings are actually needed for their language. Always include %d in "one" because translators will need to use %d for languages where "one" doesn't mean 1 (as explained above). --> <item quantity="one">%d song found.</item> <item quantity="other">%d songs found.</item> </plurals> </resources>
XML dosyası
res/values-pl/strings.xmlkonumuna kaydedildi:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <item quantity="one">Znaleziono %d piosenkę.</item> <item quantity="few">Znaleziono %d piosenki.</item> <item quantity="other">Znaleziono %d piosenek.</item> </plurals> </resources>
Kullanım:
Kotlin
val count = getNumberOfSongsAvailable() val songsFound = resources.
getQuantityString(R.plurals.numberOfSongsAvailable, count, count)Java
int count = getNumberOfSongsAvailable(); Resources res =
getResources(); String songsFound = res.getQuantityString(R.plurals.numberOfSongsAvailable, count, count);getQuantityString()yöntemini kullanırken dizeniz dize biçimlendirmesi içeriyorsacountöğesini iki kez iletmeniz gerekir. Örneğin,%d songs founddizesi için ilkcountparametresi uygun çoğul dizesini seçer ve ikincicountparametresi%dyer tutucusuna eklenir. Çoğul dizeleriniz dize biçimlendirmesi içermiyorsa üçüncü parametreyigetQuantityString'ye iletmeniz gerekmez.
Biçim ve stil
Dize kaynaklarınızı doğru şekilde biçimlendirme ve stil verme hakkında bilmeniz gereken birkaç önemli nokta aşağıda açıklanmıştır.
Biçimlendirme dizeleri
Dizelerinizi biçimlendirmeniz gerekiyorsa aşağıdaki örnek kaynakta gösterildiği gibi biçim bağımsız değişkenlerinizi dize kaynağına yerleştirerek bunu yapabilirsiniz.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
Bu örnekte, biçim dizesinin iki bağımsız değişkeni vardır: %1$s bir dizedir ve %2$d ondalık sayıdır. Ardından, getString(int, Object...) işlevini çağırarak dizeyi biçimlendirin. Örneğin:
Kotlin
var text = getString(R.string.welcome_messages, username, mailCount)
Java
String text = getString(R.string.welcome_messages, username, mailCount);
HTML biçimlendirmesiyle stil oluşturma
HTML işaretlemesiyle dizelerinize stil ekleyebilirsiniz. Örneğin:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
Biçimlendirme uygulamıyorsanız TextView metnini doğrudan setText(java.lang.CharSequence) numaralı telefonu arayarak da ayarlayabilirsiniz. Ancak bazı durumlarda, biçimlendirilmiş bir metin kaynağı oluşturmak isteyebilirsiniz. Bu kaynak, biçim dizesi olarak da kullanılır.
Normalde bu işe yaramaz çünkü format(String, Object...) ve getString(int, Object...) yöntemleri, dizedeki tüm stil bilgilerini kaldırır. Bu sorunu çözmek için HTML etiketlerini, biçimlendirme yapıldıktan sonra fromHtml(String) ile kurtarılan kaçışlı öğelerle yazabilirsiniz. Örneğin:
- Stil verilmiş metin kaynağınızı HTML'den kaçışlı dize olarak saklayın:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
Bu biçimlendirilmiş dizeye bir
<b>öğesi eklenir. Açma parantezinin<gösterimi kullanılarak HTML'den kaçırıldığına dikkat edin. - Ardından dizeyi her zamanki gibi biçimlendirin ancak HTML metnini stilize edilmiş metne dönüştürmek için
fromHtml(String)işlevini de çağırın:Kotlin
val text: String = getString(R.string.welcome_messages, username, mailCount) val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)
Java
String text = getString(R.string.welcome_messages, username, mailCount); Spanned styledText = Html.fromHtml(text, FROM_HTML_MODE_LEGACY);
fromHtml(String) yöntemi tüm HTML öğelerini biçimlendirdiğinden, biçimlendirilmiş metinle kullandığınız dizelerdeki olası HTML karakterlerinden htmlEncode(String) kullanarak çıkış yaptığınızdan emin olun. Örneğin, "<" veya "&" gibi karakterler içeren bir dizeyi biçimlendiriyorsanız biçimlendirmeden önce bu karakterlerin çıkış karakteri olarak biçimlendirilmesi gerekir. Böylece, biçimlendirilmiş dize fromHtml(String) üzerinden geçirildiğinde karakterler, başlangıçta yazıldıkları şekilde görünür. Örneğin:
Kotlin
val escapedUsername: String = TextUtils.htmlEncode(username)
val text: String = getString(R.string.welcome_messages, escapedUsername, mailCount)
val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)Java
String escapedUsername = TextUtils.htmlEncode(username);
String text = getString(R.string.welcome_messages, escapedUsername, mailCount);
Spanned styledText = Html.fromHtml(text);Spannable'larla stil oluşturma
Spannable, renk ve yazı tipi ağırlığı gibi yazı karakteri özellikleriyle stil verebileceğiniz bir metin nesnesidir. Metninizi oluşturmak için SpannableStringBuilder öğesini kullanır, ardından android.text.style paketinde tanımlanan stilleri metne uygularsınız.
Aşağıdaki yardımcı yöntemleri kullanarak, çoklu biçimlendirme içeren metin oluşturma işleminin büyük bir kısmını ayarlayabilirsiniz:
Kotlin
/** * Returns a CharSequence that concatenates the specified array of CharSequence * objects and then applies a list of zero or more tags to the entire range. * * @param content an array of character sequences to apply a style to * @param tags the styled span objects to apply to the content * such as android.text.style.StyleSpan */ private fun apply(content: Array<out CharSequence>, vararg tags: Any): CharSequence { return SpannableStringBuilder().apply { openTags(tags) content.forEach { charSequence -> append(charSequence) } closeTags(tags) } } /** * Iterates over an array of tags and applies them to the beginning of the specified * Spannable object so that future text appended to the text will have the styling * applied to it. Do not call this method directly. */ private fun Spannable.openTags(tags: Array<out Any>) { tags.forEach { tag -> setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK) } } /** * "Closes" the specified tags on a Spannable by updating the spans to be * endpoint-exclusive so that future text appended to the end will not take * on the same styling. Do not call this method directly. */ private fun Spannable.closeTags(tags: Array<out Any>) { tags.forEach { tag -> if (length > 0) { setSpan(tag, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } else { removeSpan(tag) } } }
Java
/** * Returns a CharSequence that concatenates the specified array of CharSequence * objects and then applies a list of zero or more tags to the entire range. * * @param content an array of character sequences to apply a style to * @param tags the styled span objects to apply to the content * such as android.text.style.StyleSpan * */ private static CharSequence applyStyles(CharSequence[] content, Object[] tags) { SpannableStringBuilder text = new SpannableStringBuilder(); openTags(text, tags); for (CharSequence item : content) { text.append(item); } closeTags(text, tags); return text; } /** * Iterates over an array of tags and applies them to the beginning of the specified * Spannable object so that future text appended to the text will have the styling * applied to it. Do not call this method directly. */ private static void openTags(Spannable text, Object[] tags) { for (Object tag : tags) { text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK); } } /** * "Closes" the specified tags on a Spannable by updating the spans to be * endpoint-exclusive so that future text appended to the end will not take * on the same styling. Do not call this method directly. */ private static void closeTags(Spannable text, Object[] tags) { int len = text.length(); for (Object tag : tags) { if (len > 0) { text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { text.removeSpan(tag); } } }
Aşağıdaki bold, italic ve color yöntemleri, yukarıdaki yardımcı yöntemleri sarmalar ve android.text.style paketinde tanımlanan stilleri uygulama ile ilgili belirli örnekleri gösterir. Diğer metin stillerini uygulamak için benzer yöntemler oluşturabilirsiniz.
Kotlin
/** * Returns a CharSequence that applies boldface to the concatenation * of the specified CharSequence objects. */ fun bold(vararg content: CharSequence): CharSequence = apply(content, StyleSpan(Typeface.BOLD)) /** * Returns a CharSequence that applies italics to the concatenation * of the specified CharSequence objects. */ fun italic(vararg content: CharSequence): CharSequence = apply(content, StyleSpan(Typeface.ITALIC)) /** * Returns a CharSequence that applies a foreground color to the * concatenation of the specified CharSequence objects. */ fun color(color: Int, vararg content: CharSequence): CharSequence = apply(content, ForegroundColorSpan(color))
Java
/** * Returns a CharSequence that applies boldface to the concatenation * of the specified CharSequence objects. */ public static CharSequence bold(CharSequence... content) { return apply(content, new StyleSpan(Typeface.BOLD)); } /** * Returns a CharSequence that applies italics to the concatenation * of the specified CharSequence objects. */ public static CharSequence italic(CharSequence... content) { return apply(content, new StyleSpan(Typeface.ITALIC)); } /** * Returns a CharSequence that applies a foreground color to the * concatenation of the specified CharSequence objects. */ public static CharSequence color(int color, CharSequence... content) { return apply(content, new ForegroundColorSpan(color)); }
Bir ifadenin içindeki kelimelere çeşitli stiller uygulamak için bu yöntemleri nasıl birleştireceğinize dair bir örneği aşağıda bulabilirsiniz:
Kotlin
// Create an italic "hello, " a red "world", // and bold the entire sequence. val text: CharSequence = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world)))
Java
// Create an italic "hello, " a red "world", // and bold the entire sequence. CharSequence text = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world)));
core-ktx Kotlin modülü, aralıklarla çalışmayı daha da kolaylaştıran uzantı işlevleri de içerir. Daha fazla bilgi edinmek için GitHub'daki android.text
paket belgelerine göz atabilirsiniz.
Aralıklarla çalışma hakkında daha fazla bilgi için aşağıdaki bağlantılara bakın:
Ek açıklamalarla stil oluşturma
strings.xml kaynak dosyalarınızdaki <annotation> etiketiyle birlikte Annotation sınıfını kullanarak karmaşık veya özel stil uygulayabilirsiniz.
Açıklama etiketi, dize bölümlerini özel anahtar/değer çiftleri tanımlayarak özel stil için işaretlemenize olanak tanır. Bu çiftler, çerçeve tarafından Annotation aralıklarına dönüştürülür. Daha sonra bu ek açıklamaları alabilir ve stil uygulamak için anahtarı ve değeri kullanabilirsiniz.
Açıklama oluştururken <annotation>
etiketini her strings.xml dosyasındaki dizenin tüm çevirilerine eklediğinizden emin olun.

Tüm dillerde "metin" kelimesine özel bir yazı tipi uygulama
Örnek: Özel yazı tipi ekleme
-
<annotation>etiketini ekleyin ve anahtar/değer çiftini tanımlayın. Bu durumda anahtar font, değer ise kullanmak istediğimiz yazı tipi türü olan title_emphasis'tir.// 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>
-
Dize kaynağını yükleyin ve font anahtarıyla ek açıklamaları bulun. Ardından özel bir kapsam oluşturun ve mevcut kapsamı değiştirin.
Kotlin
// 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. // the constructor copies both the text and the spans. 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 to the annotation key if (fontName == "title_emphasis") { // create the typeface val typeface = getFontCompat(R.font.permanent_marker) // set the span at 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
Java
// get the text as SpannedString so we can get the spans attached to the text SpannedString titleText = (SpannedString) getText(R.string.title); // get all the annotation spans from the text Annotation[] annotations = titleText.getSpans(0, titleText.length(), Annotation.class); // create a copy of the title text as a SpannableString. // the constructor copies both the text and the spans. so we can add and remove spans SpannableString spannableString = new SpannableString(titleText); // iterate through all the annotation spans for (Annotation annotation: annotations) { // look for the span with the key font if (annotation.getKey().equals("font")) { String fontName = annotation.getValue(); // check the value associated to the annotation key if (fontName.equals("title_emphasis")) { // create the typeface Typeface typeface = ResourcesCompat.getFont(this, R.font.roboto_mono); // set the span at the same indices as the annotation spannableString.setSpan(new 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;
Aynı metni birden fazla kez kullanıyorsanız olası performans ve bellek sorunlarını önlemek için SpannableString nesnesini bir kez oluşturup gerektiğinde yeniden kullanmanız gerekir.
Açıklama kullanımına ilişkin daha fazla örnek için Android'de uluslararasılaştırılmış metni biçimlendirme başlıklı makaleyi inceleyin.
Not aralıkları ve metin ayrıştırma
Annotation aralıkları da ParcelableSpans olduğundan anahtar/değer çiftleri ayrıştırılır ve ayrıştırılmaz. Paketin alıcısı ek açıklamaları yorumlamayı bildiği sürece, Annotation aralıklarını kullanarak paketlenmiş metne özel stil uygulayabilirsiniz.
Metni bir Intent Bundle'a iletirken özel stilinizi korumak için öncelikle metninize Annotation aralıkları eklemeniz gerekir. Bu işlemi, yukarıdaki örnekte gösterildiği gibi <annotation> etiketi aracılığıyla XML kaynaklarında veya aşağıdaki örnekte gösterildiği gibi yeni bir Annotation oluşturup bunu bir aralık olarak ayarlayarak kodda yapabilirsiniz:
Kotlin
val spannableString = SpannableString("My spantastic text") val annotation = Annotation("font", "title_emphasis") spannableString.setSpan(annotation, 3, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) // start Activity with text with spans val intent = Intent(this, MainActivity::class.java) intent.putExtra(TEXT_EXTRA, spannableString) startActivity(intent)
Java
SpannableString spannableString = new SpannableString("My spantastic text"); Annotation annotation = new Annotation("font", "title_emphasis"); spannableString.setSpan(annotation, 3, 7, 33); // start Activity with text with spans Intent intent = new Intent(this, MainActivity.class); intent.putExtra(TEXT_EXTRA, spannableString); this.startActivity(intent);
Bundle içindeki metni SpannableString olarak alın ve ardından, yukarıdaki örnekte gösterildiği gibi ekli ek açıklamaları ayrıştırın.
Kotlin
// read text with Spans val intentCharSequence = intent.getCharSequenceExtra(TEXT_EXTRA) as SpannableString
Java
// read text with Spans SpannableString intentCharSequence = (SpannableString)intent.getCharSequenceExtra(TEXT_EXTRA);
Metin stili hakkında daha fazla bilgi için aşağıdaki bağlantılara bakın: