Seperti apa bentuk teks Anda?

Teman-teman, semua bagus Jumat. Kami ingin membagikan terjemahan artikel yang disiapkan khusus untuk siswa kursus “Pengembang Android. Kursus Lanjutan . " Selamat membaca.



Cara mendeklarasikan teks secara gaya di Android.


Virginia Poltrack Illustration

TextView dalam aplikasi Android menyediakan beberapa atribut untuk menata teks dan berbagai cara untuk menerapkannya. Atribut ini dapat diatur secara langsung di tata letak, menerapkan gaya ke tampilan atau tema ke tata letak, atau, jika Anda mau, mengatur tampilan teks. Tapi apa yang harus digunakan? Dan apa yang terjadi jika Anda menggabungkannya?


Apa dan kapan menggunakannya?

Artikel ini menjelaskan berbagai pendekatan untuk stylization teks deklaratif (yaitu, ketika Anda menentukan gaya dalam file XML), membahas ruang lingkup dan prioritas masing-masing metode.

tl; dr;


Anda harus membaca seluruh posting, tetapi di sini adalah ringkasannya.

Ingat urutan prioritas berbagai metode penataan - jika Anda mencoba menstilisasi beberapa teks dan tidak melihat hasil yang diharapkan, maka kemungkinan besar perubahan Anda akan ditimpa oleh sesuatu dengan prioritas lebih tinggi dalam hierarki ini:


Hirarki metode penataan teks

Saya akan menyarankan prosedur penataan berikut:

  1. Setel gaya aplikasi apa pun di textViewStyle sebagai gaya default untuk tema Anda.
  2. Pasang set (kecil) TextAppearance yang akan digunakan aplikasi Anda (atau gunakan / wariskan dari gaya MaterialComponent), dan rujuk langsung dari pandangan Anda
  3. Buat style dengan mengatur atribut yang tidak didukung oleh TextAppearance (yang dengan sendirinya akan menentukan salah satu dari TextAppearance Anda).
  4. Lakukan gaya unik apa pun secara langsung di tata letak.

Tunjukkan beberapa gaya


Anda bisa langsung mengatur atribut TextView di tata letak, tetapi pendekatan ini bisa lebih membosankan dan tidak aman. Bayangkan dengan cara ini Anda mencoba memperbarui warna semua TextViews dalam aplikasi. Seperti semua tampilan lainnya, Anda dapat (dan seharusnya!) Menggunakan gaya untuk memastikan konsistensi, penggunaan kembali, dan kemudahan memperbarui. Untuk tujuan ini, saya sarankan membuat gaya untuk teks kapan pun Anda mungkin ingin menerapkan gaya yang sama ke beberapa tampilan. Ini sangat sederhana dan sebagian besar didukung oleh sistem tampilan Android.

Apa yang terjadi di bawah tenda saat Anda mengatur tampilan? Jika Anda pernah menulis tampilan kustom Anda, Anda mungkin melihat panggilan ke konteks.obtainStyledAttributes (AttributeSet, int [], int, int) . Dengan demikian, sistem tampilan di Android beralih ke tampilan atribut yang ditentukan dalam tata letak. Parameter AttributeSet , pada kenyataannya, dapat dianggap sebagai peta parameter XML yang Anda tentukan dalam tata letak Anda. Jika AttributeSet menetapkan gaya, gaya dibaca pertama kali , dan kemudian atribut yang ditentukan secara langsung dalam tampilan diterapkan padanya. Jadi, kita sampai pada aturan prioritas pertama.

Lihat → Gaya

Atribut yang didefinisikan secara langsung dalam tampilan selalu "menang" dan mengesampingkan atribut yang didefinisikan dalam gaya. Perhatikan bahwa kombinasi atribut style dan view diterapkan; mendefinisikan atribut dalam tampilan, yang juga ditentukan dalam gaya, tidak membatalkan seluruh gaya. Perlu juga dicatat bahwa dalam pandangan Anda tidak ada cara nyata untuk menentukan dari mana stilisasi berasal; Ini ditentukan oleh sistem tampilan untuk Anda sekali dalam panggilan yang sama. Anda tidak bisa mendapatkan kedua opsi dan memilih.

Meskipun gaya sangat berguna, mereka memiliki keterbatasan. Salah satunya adalah bahwa Anda hanya dapat menerapkan satu gaya ke tampilan (berbeda dengan sesuatu seperti CSS, di mana Anda dapat menerapkan beberapa kelas). TextView , bagaimanapun, memiliki trik, ia menyediakan atribut TextAppearance , yang bekerja mirip dengan style . Jika Anda TextAppearance teks melalui TextAppearance , biarkan atribut style gratis untuk gaya lain, yang terlihat praktis. Mari kita lihat lebih dekat apa itu TextAppearance dan bagaimana cara kerjanya.

Penampilan teks


Tidak ada yang ajaib di TextAppearance (misalnya, mode rahasia untuk menerapkan beberapa gaya yang seharusnya tidak Anda ketahui !!!!), TextView menyelamatkan Anda dari pekerjaan yang tidak perlu. Mari kita lihat pada konstruktor TextView untuk memahami apa yang terjadi.

 TypedArray a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes); TypedArray appearance = null; int ap = a.getResourceId(com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1); a.recycle(); if (ap != -1) { appearance = theme.obtainStyledAttributes(ap, com.android.internal.R.styleable.TextAppearance); } if (appearance != null) { readTextAppearance(context, appearance, attributes, false); appearance.recycle(); } // a little later a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes); readTextAppearance(context, a, attributes, true); 

Jadi apa yang terjadi di sini? Pada dasarnya, TextView pertama terlihat untuk melihat apakah Anda menentukan android:textAppearance , jika demikian, itu memuat gaya ini dan menerapkan semua properti yang terdaftar di sana. Kemudian, ia memuat semua atribut dari tampilan (yang ia ingat, termasuk gaya) dan menerapkannya. Jadi kita sampai pada aturan prioritas kedua:

Lihat → Gaya → Tampilan Teks

Karena penampilan teks diperiksa terlebih dahulu, atribut apa pun yang didefinisikan secara langsung dalam tampilan atau gaya akan menimpanya.

Dengan TextAppearance , ada TextAppearance lain yang perlu diingat: mendukung subset atribut gaya yang ditawarkan TextView . Untuk lebih memahami apa yang saya maksud, mari kembali ke baris ini:

obtainStyledAttributes(ap, android.R.styleable.TextAppearance);

Kami melihat versi receiveStyledAttributes dengan 4 argumen, versi 2-argumen ini sedikit berbeda dari itu. Dia melihat style yang diberikan (seperti yang didefinisikan oleh id parameter pertama) dan memfilternya hanya sesuai dengan atribut dalam style yang muncul pada parameter kedua, array attrs . Android.R.styleable.TextAppearance yang sangat bergaya mendefinisikan ruang lingkup TextAppearance . Melihat definisi ini, kita melihat bahwa TextAppearance mendukung banyak, tetapi tidak semua, atribut yang didukung TextView .

 <attr name="textColor" /> <attr name="textSize" /> <attr name="textStyle" /> <attr name="typeface" /> <attr name="fontFamily" /> <attr name="textColorHighlight" /> <attr name="textColorHint" /> <attr name="textColorLink" /> <attr name="textAllCaps" format="boolean" /> <attr name="shadowColor" format="color" /> <attr name="shadowDx" format="float" /> <attr name="shadowDy" format="float" /> <attr name="shadowRadius" format="float" /> <attr name="elegantTextHeight" format="boolean" /> <attr name="letterSpacing" format="float" /> <attr name="fontFeatureSettings" format="string" /> 

Atribut Styling Didukung oleh TextAppearance

Berikut adalah beberapa atribut TextView yang tidak termasuk dalam TextAppearance : lineHeight[Multiplier|Extra] , lines , breakStrategy dan hyphenationFrequency . TextAppearance berfungsi pada level karakter, bukan level paragraf, sehingga atribut yang memengaruhi seluruh tata letak tidak didukung.

Oleh karena itu, TextAppearance sangat berguna, memungkinkan kita untuk mendefinisikan gaya yang berorientasi pada atribut gaya teks, dan membiarkan style dalam tampilan gratis untuk keperluan lain. Namun, ini memiliki cakupan terbatas dan berada di bagian bawah rantai prioritas, jadi jangan lupa tentang batasannya.

Default yang wajar


Ketika kami melihat bagaimana tampilan Android menyelesaikan atribut ( context.obtainStyledAttributes ), kami sebenarnya menyederhanakannya sedikit. Dia memanggil theme.obtainStyledAttributes (menggunakan Theme Context saat ini 'a). Saat memeriksa tautan , urutan prioritas yang kami teliti sebelumnya ditampilkan, dan 2 tempat lagi diindikasikan untuk mencari penyelesaian atribut: gaya default untuk tampilan dan tema.

Saat menentukan nilai akhir atribut tertentu, empat parameter input ikut bermain:

  1. Nilai atribut apa pun di AtributSet ini.
  2. Sumber daya style yang ditentukan dalam AttributeSet (bernama "style").
  3. Gaya default ditentukan oleh defStyleAttr dan defstyleres
  4. Nilai dasar di utas ini.

Urutan Prioritas Styling dari Dokumentasi Tema

Kami akan kembali ke tema, tapi mari kita lihat gaya default terlebih dahulu. Apa gaya default ini? Untuk menjawab pertanyaan ini, saya pikir akan berguna untuk mengambil jalan keluar kecil dari tema TextView dan melihat Button sederhana. Ketika Anda memasukkan < Button > ke tata letak Anda, tampilannya seperti ini.


Tombol standar

Mengapa Jika Anda melihat kode sumber Button , Anda akan melihat bahwa kode itu agak sedikit:

 public class Button extends TextView { public Button(Context context) { this(context, null); } public Button(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.buttonStyle); } public Button(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public CharSequence getAccessibilityClassName() { return Button.class.getName(); } @Override public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { if (getPointerIcon() == null && isClickable() && isEnabled()) { return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND); } return super.onResolvePointerIcon(event, pointerIndex); } } 

Itu saja! Inilah seluruh kelas (tidak ada komentar). Anda bisa memeriksanya sendiri di sini . Saya akan menunggu Jadi dari mana latar belakang, huruf kapital, riak, dll. Berasal? Anda mungkin telah terjawab, tetapi semuanya akan didefinisikan dalam konstruktor dengan 2 argumen; yang dipanggil saat tata letak diambil dari XML. Ini adalah parameter terakhir yang mendefinisikan defaultStyleAttr di com.android.internal.R.attr.buttonStyle . Ini adalah gaya default, yang pada dasarnya adalah titik referensi tidak langsung, memungkinkan Anda menentukan gaya default. Itu tidak menunjuk langsung ke gaya, tetapi memungkinkan Anda untuk menunjuk ke salah satu yang ditentukan dalam topik Anda yang akan memeriksa ketika menyelesaikan atribut. Dan itulah yang biasanya dilakukan oleh semua tema yang Anda warisi untuk memberikan tampilan dan nuansa widget standar. Misalnya, jika Anda melihat topik Materi, ia mendefinisikan @style/Widget.Material.Light.Button , dan gaya inilah yang menyediakan semua atribut yang theme.obtainStyledAttributes akan theme.obtainStyledAttributes jika Anda tidak menentukan hal lain.

Kembali ke TextView , ini juga menawarkan gaya default: textViewStyle . Ini bisa sangat nyaman jika Anda ingin menerapkan beberapa gaya ke setiap TextView di aplikasi Anda. Misalkan Anda ingin mengatur jarak garis default ke 1.2. Anda dapat melakukan ini dengan style/TextAppearance dan mencoba menerapkannya selama peninjauan kode (atau mungkin bahkan dengan aturan kustom yang elegan di Lint), tetapi Anda harus waspada dan memastikan bahwa Anda merekrut anggota tim baru , hati-hati dengan refactoring, dll.

Pendekatan yang lebih baik adalah menentukan gaya default Anda sendiri untuk semua TextView dalam aplikasi, mengatur perilaku yang diinginkan. Anda dapat melakukan ini dengan mengatur gaya Anda sendiri untuk textViewStyle , yang diwarisi dari platform atau dari MaterialComponents/AppCompat secara default.

 <style name="Theme.MyApp" parent="@style/Theme.MaterialComponents.Light"> ... <item name="android:textViewStyle">@style/Widget.MyApp.TextView</item></style> <style name="Widget.MyApp.TextView" parent="@android:style/Widget.Material.TextView"> <item name="android:textAppearance">@style/TextAppearance.MyApp.Body</item> <item name="android:lineSpacingMultiplier">@dimen/text_line_spacing</item> </style> 

Dengan mengingat hal ini, aturan prioritas kami berupa:

Lihat -> Gaya -> Gaya Default -> TextAppearance

Sebagai bagian dari resolusi atribut sistem tampilan, slot ini diisi setelah gaya (sehingga segala sesuatu dalam gaya dibatalkan oleh gaya yang diterapkan atau melihat atribut secara default), tetapi masih akan menimpa tampilan teks. Gaya default bisa sangat nyaman. Jika Anda pernah memutuskan untuk menulis tampilan kustom Anda sendiri, mereka bisa menjadi cara yang ampuh untuk menerapkan perilaku default, membuatnya mudah untuk dikustomisasi.

Jika Anda mewarisi widget dan tidak menentukan gaya default Anda sendiri, maka pastikan untuk menggunakan gaya kelas induk default di konstruktor (jangan hanya lulus 0). Misalnya, jika Anda mewarisi dari AppCompatTextView dan menulis konstruktor Anda sendiri dengan 2 argumen, pastikan untuk melewati android.R.attr.textViewStyle defaultStyleAttr ( seperti di sini ), jika tidak, Anda akan kehilangan perilaku kelas induk.

Tema


Seperti disebutkan sebelumnya, ada cara lain (terakhir, saya berjanji) untuk memberikan informasi gaya. theme.obtainStyledAttributes tempat theme.obtainStyledAttributes akan melihat langsung ke topik itu sendiri. Artinya, jika Anda menambahkan atribut gaya ke tema Anda, misalnya android:textColor , sistem tampilan akan memilihnya sebagai pilihan terakhir. Sebagai aturan, itu adalah ide yang buruk untuk mencampur atribut tema dan atribut gaya, yaitu, apa yang Anda terapkan langsung ke tampilan, sebagai aturan, tidak boleh ditetapkan untuk tema (dan sebaliknya), tetapi ada beberapa pengecualian langka.

Salah satu contohnya adalah ketika Anda mencoba mengubah font di seluruh aplikasi. Anda dapat menggunakan salah satu metode yang dijelaskan di atas, tetapi menyesuaikan secara manual gaya / tampilan teks di mana-mana akan menjadi monoton dan tidak aman, dan gaya default hanya akan bekerja di tingkat widget; subkelas dapat mengesampingkan perilaku ini, misalnya tombol menentukan android:buttonStyle mereka sendiri android:buttonStyle , yang android:textViewStyle Anda android:textViewStyle tidak akan mengambil. Sebagai gantinya, Anda dapat menentukan font di tema Anda:

 <style name="Theme.MyApp" parent="@style/Theme.MaterialComponents.Light"> ... <item name="android:fontFamily">@font/space_mono</item> </style> 

Sekarang setiap tampilan yang mendukung atribut ini akan mengambilnya jika tidak diganti oleh sesuatu dengan prioritas lebih tinggi:

Lihat → Gaya → Gaya Default → Tema → TextAppearance

Sekali lagi, karena ini adalah bagian dari sistem penataan tampilan, itu akan menimpa semua yang disediakan dalam bentuk teks, tetapi akan ditimpa oleh atribut yang lebih spesifik.

Ingat prioritas ini. Dalam contoh kami dengan font untuk seluruh aplikasi, Anda dapat mengharapkan Toolbar mengambil font ini, karena mengandung judul, yang merupakan TextView . Kelas Toolbar itu sendiri, bagaimanapun, mendefinisikan gaya default yang mengandung titleTextAppearance , yang mendefinisikan android:fontFamily , dan menetapkannya langsung di header TextView , menimpa nilai level tema. Gaya tingkat topik bisa berguna, tetapi mudah ditimpa, jadi pastikan itu diterapkan dengan benar.

Bonus: Masalah yang Tidak Terselesaikan


Seluruh artikel ini dikhususkan untuk desain teks deklaratif di tingkat tampilan, yaitu, bagaimana gaya seluruh TextView selama mengisi. Gaya apa pun yang diterapkan setelah mengisi (misalnya, textView.setTextColor(…) ) akan menggantikan gaya deklaratif. TextView juga mendukung gaya yang lebih kecil melalui Span . Saya tidak akan membahas topik ini, karena dijelaskan secara rinci dalam artikel oleh Florina Muntenescu .

Spantastic text styling dengan Spans
Rentang underspanding

Saya akan menyebutkan ini untuk kelengkapan, untuk diingat bahwa gaya dan rentang program akan berada di urutan teratas prioritas:

Rentang → Setter → Tampilan → Gaya → Gaya Default → Tema → TextAppearance

Pilih gaya Anda


Meskipun ada beberapa cara untuk menata teks Anda, memahami perbedaan antara metode dan keterbatasannya membantu Anda menemukan alat yang tepat untuk tugas tertentu atau memahami mengapa satu metode lebih diutamakan daripada yang lain.

Memiliki gaya teks yang bagus!

Kami mengundang semua orang ke webinar gratis dalam kerangka yang akan kami kenali dengan kerangka DI Dagger 2: kami akan mempelajari bagaimana Dagger2 menghasilkan kode, kami akan berurusan dengan penjelasan JSR 330 dan konstruksi Dagger2, kami akan belajar cara menggunakan Dagger2 dalam aplikasi multi-modul dan mempertimbangkan Dagger Android Injector.

Source: https://habr.com/ru/post/id456110/


All Articles