Thèmes, styles et autres


Presque tous les développeurs savent qu'il existe des thèmes dans Android, mais leur utilisation est généralement limitée à la copie de fichiers XML à partir de Stack Overflow ou d'autres ressources. Il existe des informations sur Internet sur des sujets, mais ce n'est généralement qu'une recette pour savoir comment atteindre un certain résultat. Dans cet article, j'ai essayé de donner un aperçu introductif du mécanisme de stylisation Android.

Table des matières


Présentation
Attributs pour RectView
Style pour RectView
Style par défaut
Attribut de thème de style RectView
Thème du niveau d'activité
Afficher le sujet
Comment appliquer des valeurs d'attribut
Sujets de ressources
Résumé

Présentation


Les styles et les thèmes dans Android sont des mécanismes qui vous permettent de séparer les détails de conception (par exemple, la couleur, la taille de la police, etc.) de la structure de l'interface utilisateur. Pour comprendre comment cela fonctionne, un exemple simple avec une vue personnalisée nous aidera.

Nous aurons besoin d'une vue personnalisée simple qui dessinera un rectangle avec la couleur souhaitée dans les limites de la vue.

class RectView @JvmOverloads constructor( context: Context, attrSet: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrSet, defStyleAttr) { private val paint = Paint().apply { color = Color.BLUE } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) } } 



Attributs pour RectView


Maintenant, je voudrais pouvoir changer la couleur du rectangle de mise en page.
Pour ce faire, nous devons ajouter un nouvel attribut, ajouter attrs.xml au fichier

 <resources> <attr name="rectColor" format="color"/> </resources> 

Maintenant, dans le code, nous pouvons accéder à l'ID de cet attribut via R.attr.rectColor et
dans la disposition de l'écran, nous pouvons utiliser l'attribut app: rectColor.

 <org.berendeev.themes.RectView android:id="@+id/text2" android:layout_width="100dp" app:rectColor="@color/colorPrimary" android:layout_height="100dp"/> 

Mais RectView ne sait pas encore qu'il existe un attribut où vous pouvez prendre la couleur du rectangle.

Apprenons à RectView à comprendre l'attribut rectColor, ajoutons un groupe d'attributs

 <resources> <attr name="rectColor" format="color"/> <declare-styleable name="RectView"> <attr name="rectColor"/> </declare-styleable> </resources> 

En classe R, 2 nouveaux champs ont été générés:
R.styleable.RectView est un tableau d'attributs id, actuellement c'est un tableau d'un élément R.attr.rectColor
R.styleable.RectView_rectColor est l'index id de l'attribut dans le tableau R.styleable.RectView, c'est-à-dire attribut id que nous pouvons obtenir et donc R.styleable.RectView [R.styleable.RectView_rectColor]

Et ajoutez la prise en charge de l'attribut rectColor au code.

 init { val typedArray = context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, 0, 0 ) try { paint.color = typedArray.getColor( R.styleable.RectView_rectColor, Color.BLUE ) } finally { typedArray.recycle() } } 

Code complet
 class RectView @JvmOverloads constructor( context: Context, attrSet: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrSet, defStyleAttr) { private val paint = Paint().apply { color = Color.BLUE } init { val typedArray = context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, 0, 0 ) try { paint.color = typedArray.getColor( R.styleable.RectView_rectColor, Color.BLUE ) } finally { typedArray.recycle() } } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) } } 


Maintenant, nous pouvons changer la couleur du rectangle à partir de la disposition:



Style pour RectView


Maintenant, nous n'avons qu'un seul attribut, mais supposons qu'il y en ait dix - il serait extrêmement gênant pour nous de définir tous ces attributs dans la mise en page pour des éléments similaires à chaque fois.

La décision de tout faire avec style.

 <style name="DefaultRectViewStyle"> <item name="rectColor">@color/colorAccent</item> </style> 

Maintenant, nous pouvons créer tout type de vue avec la même apparence en spécifiant le style.

 <org.berendeev.themes.RectView android:id="@+id/text2" android:layout_width="100dp" style="@style/DefaultRectViewStyle" android:layout_height="100dp"/> 

Style par défaut


Maintenant, nous voulons que toutes les vues aient une sorte de style par défaut. Pour ce faire, nous spécifierons le style par défaut de la méthode obtiennent des styles d'attributs:

 context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, 0, R.style.DefaultRectViewStyle ) 

Ça suffit. Maintenant, tous les RectView que nous ajoutons à la mise en page auront le style par défaut DefaultRectViewStyle.

Attribut de thème de style RectView


La valeur par défaut est bonne, mais je voudrais contrôler la mise en page de manière plus flexible. Il est pratique de définir le style d'une vue particulière pour l'ensemble de l'application ou pour une activité distincte.

Pour cela, nous avons besoin d'un nouvel attribut. Nous allons définir sa valeur dans le thème, la valeur sera le style qui détermine l'apparence de RectView.

 <attr name="rectViewStyle" format="reference"/> 

Et apprenez à notre rectView à comprendre cet attribut de thème. En passant le troisième paramètre R.attr.rectViewStyle à la méthode getStyledAttributes.

 context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, R.attr.rectViewStyle, R.style.DefaultRectViewStyle ) 

Maintenant, si un élément avec le nom rectViewStyle et une valeur de type style est spécifié dans la rubrique, ce style s'appliquera à tous les RectView avec ce thème.

Thème du niveau d'activité


Nous définissons la valeur de l'attribut rectViewStyle dans notre rubrique.

 <resources> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="rectViewStyle">@style/LocalRectViewStyle</item> </style> </resources> 

Spécifiez la rubrique dans le manifeste d'application.

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.berendeev.themes"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> 

Toutes les activités seront définies sur le thème AppTheme par défaut. Nous avons défini la conception RectView pour l'ensemble de l'application.

Le sujet peut également être défini pour une activité spécifique dans le manifeste.

 <activity android:name=".MainActivity" android:theme="@style/MyTheme"> 

Il est important ici que le thème que nous définirons au niveau de l'application ou de l'activité soit hérité du thème standard. Par exemple, Theme.AppCompat. Sinon, nous obtenons un crash lors de l'exécution.
java.lang.IllegalStateException: vous devez utiliser un thème Theme.AppCompat (ou descendant) avec cette activité.

Afficher le sujet


Au niveau de la vue, nous ne réinstallons pas le thème, mais nous remplaçons les valeurs d'attribut requises, nous n'avons donc pas besoin d'hériter du thème standard. Un parent peut être vide ou, par exemple, nous pouvons hériter d'une des superpositions ThemeOverlay.AppCompat.

Ici, nous définissons le thème MyOverlay pour le groupe LinearLayout et tous ses descendants dans la hiérarchie.

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:theme="@style/MyOverlay"> <org.berendeev.themes.RectView android:layout_width="100dp" android:layout_height="100dp"/> </LinearLayout> 

Dans le sujet, on peut se passer d'un parent, car nous modifions simplement le thème de l'activité.

 <style name="MyOverlay"> <item name="rectViewStyle">@style/LocalRectViewStyle</item> </style> 

Comment appliquer des valeurs d'attribut



Si pour la vue, nous définissons les valeurs d'attribut à la fois dans la mise en page et dans le style et dans le thème, l'ordre de choix de la valeur sera le suivant. La priorité la plus élevée est la valeur spécifiée dans la mise en page, c'est-à-dire si la valeur est définie dans la mise en page, le style et le thème seront ignorés, puis le style continuera, puis le thème et en dernier lieu le style par défaut.

Sujets de ressources


Les valeurs de rubrique peuvent être utilisées dans les ressources. Par exemple, en dessinable, nous pouvons définir une couleur qui dépendra de la couleur définie dans le thème.

 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="?attr/colorPrimary"/> </shape> 

Maintenant, la couleur du rectangle dépend de la valeur de l'attribut colorPrimary dans le thème. L'attribut peut être quelconque. Par exemple, nous pouvons définir notre attribut dans les ressources et définir sa valeur dans le sujet.

Une telle astuce peut être utilisée dans toutes les ressources, par exemple, dans le sélecteur ou dans le dessin vectoriel. Cela rend la conception plus structurée et flexible. Nous pouvons rapidement changer le thème de toutes les activités.

Résumé


  • Le thème et le style au niveau des ressources sont identiques, mais sont utilisés différemment.
  • Un thème peut contenir d'autres thèmes, uniquement des significations ou des styles pour la vue.
  • Le style est indiqué dans la mise en page au niveau de la vue. LayoutInflater calcule les valeurs de style et les transmet en tant qu'AttributeSet au constructeur View.
  • Les thèmes sont un mécanisme qui vous permet de définir l'apparence globale de l'activité entière.
  • Les valeurs de rubrique peuvent être modifiées pour l'élément (et les descendants) dans la hiérarchie des vues.
  • Les valeurs de thème peuvent être utilisées non seulement dans View, mais également dans les ressources.

PS: Si l'article est intéressant, j'écrirai un article plus avancé ou un article avec beaucoup d'exemples réels.

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


All Articles