Question Définition d'attr personnalisés


Je dois mettre en œuvre mes propres attributs comme dans com.android.R.attr

Je n'ai rien trouvé dans la documentation officielle et j'ai donc besoin d'informations sur la manière de définir ces attributs et de les utiliser à partir de mon code.


410
2017-08-09 15:08


origine


Réponses:


Actuellement, la meilleure documentation est la source. Vous pouvez y jeter un coup d'oeil ici (attrs.xml).

Vous pouvez définir des attributs dans la partie supérieure <resources> élément ou à l'intérieur d'un <declare-styleable> élément. Si je vais utiliser un attr dans plus d'un endroit, je le mets dans l'élément racine. Notez que tous les attributs partagent le même espace de noms global. Cela signifie que même si vous créez un nouvel attribut à l'intérieur d'un <declare-styleable> Il peut être utilisé en dehors de l'élément et vous ne pouvez pas créer un autre attribut avec le même nom d'un type différent.

Un <attr> l'élément a deux attributs xml name et format. name vous permet d'appeler cela quelque chose et c'est comment vous finissez par vous y référer dans le code, par exemple, R.attr.my_attribute. le format L'attribut peut avoir des valeurs différentes selon le «type» d'attribut que vous voulez.

  • reference - si elle fait référence à un autre identifiant de ressource (par exemple, "@ color / my_color", "@ layout / my_layout")
  • Couleur
  • booléen
  • dimension
  • flotte
  • entier
  • chaîne
  • fraction
  • enum - normalement implicitement défini
  • flag - normalement implicitement défini

Vous pouvez définir le format sur plusieurs types en utilisant |, par exemple., format="reference|color".

enum Les attributs peuvent être définis comme suit:

<attr name="my_enum_attr">
  <enum name="value1" value="1" />
  <enum name="value2" value="2" />
</attr>

flag les attributs sont similaires, sauf que les valeurs doivent être définies de manière à pouvoir être assemblées par bit:

<attr name="my_flag_attr">
  <flag name="fuzzy" value="0x01" />
  <flag name="cold" value="0x02" />
</attr>

En plus des attributs, il y a le <declare-styleable> élément. Cela vous permet de définir les attributs qu'une vue personnalisée peut utiliser. Vous faites cela en spécifiant un <attr> élément, s'il a été précédemment défini, vous ne spécifiez pas le format. Si vous souhaitez réutiliser un attr Android, par exemple, Android: la gravité, alors vous pouvez le faire dans le name, comme suit.

Un exemple de vue personnalisée <declare-styleable>:

<declare-styleable name="MyCustomView">
  <attr name="my_custom_attribute" />
  <attr name="android:gravity" />
</declare-styleable>

Lorsque vous définissez vos attributs personnalisés en XML dans votre vue personnalisée, vous devez effectuer certaines opérations. Vous devez d'abord déclarer un espace de noms pour trouver vos attributs. Vous faites cela sur l'élément de mise en page racine. Normalement il y a seulement xmlns:android="http://schemas.android.com/apk/res/android". Vous devez maintenant ajouter aussi xmlns:whatever="http://schemas.android.com/apk/res-auto".

Exemple:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:whatever="http://schemas.android.com/apk/res-auto"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

    <org.example.mypackage.MyCustomView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      whatever:my_custom_attribute="Hello, world!" />
</LinearLayout>

Enfin, pour accéder à cet attribut personnalisé, procédez comme suit dans le constructeur de votre vue personnalisée.

public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);

  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle, 0);

  String str = a.getString(R.styleable.MyCustomView_my_custom_attribute);

  //do something with str

  a.recycle();
}

La fin. :)


863
2017-08-09 16:11



La réponse de Qberticus est bonne, mais il manque un détail utile. Si vous les implémentez dans une bibliothèque, remplacez:

xmlns:whatever="http://schemas.android.com/apk/res/org.example.mypackage"

avec:

xmlns:whatever="http://schemas.android.com/apk/res-auto"

Sinon, l'application qui utilise la bibliothèque aura des erreurs d'exécution.


81
2017-11-16 16:18



La réponse ci-dessus couvre tout en détail, à part quelques choses.

Premièrement, s'il n'y a pas de styles, alors (Context context, AttributeSet attrs) la signature de la méthode sera utilisée pour instancier la préférence. Dans ce cas, utilisez simplement context.obtainStyledAttributes(attrs, R.styleable.MyCustomView) pour obtenir le TypedArray.

Deuxièmement, il ne couvre pas la manière de traiter les ressources plaurales (chaînes de quantité). Ceux-ci ne peuvent pas être traités avec TypedArray. Voici un extrait de code de ma SeekBarPreference qui définit le résumé de la préférence en formatant sa valeur en fonction de la valeur de la préférence. Si le code XML de la préférence définit Android: résumé à une chaîne de texte ou une chaîne, la valeur de la préférence est mise en forme dans la chaîne (elle doit avoir% d pour prendre la valeur). Si android: summary est défini sur une ressource plaurals, cela est utilisé pour formater le résultat.

// Use your own name space if not using an android resource.
final static private String ANDROID_NS = 
    "http://schemas.android.com/apk/res/android";
private int pluralResource;
private Resources resources;
private String summary;

public SeekBarPreference(Context context, AttributeSet attrs) {
    // ...
    TypedArray attributes = context.obtainStyledAttributes(
        attrs, R.styleable.SeekBarPreference);
    pluralResource =  attrs.getAttributeResourceValue(ANDROID_NS, "summary", 0);
    if (pluralResource !=  0) {
        if (! resources.getResourceTypeName(pluralResource).equals("plurals")) {
            pluralResource = 0;
        }
    }
    if (pluralResource ==  0) {
        summary = attributes.getString(
            R.styleable.SeekBarPreference_android_summary);
    }
    attributes.recycle();
}

@Override
public CharSequence getSummary() {
    int value = getPersistedInt(defaultValue);
    if (pluralResource != 0) {
        return resources.getQuantityString(pluralResource, value, value);
    }
    return (summary == null) ? null : String.format(summary, value);
}

  • Ceci est juste donné à titre d'exemple, cependant, si vous voulez être tenté de définir le résumé sur l'écran des préférences, vous devez alors appeler notifyChanged() dans les préférences onDialogClosed méthode.

14
2017-09-03 15:33



L'approche traditionnelle est pleine de code standard et de gestion des ressources maladroite. Voilà pourquoi j'ai fait le Cadre de Spyglass. Pour montrer comment cela fonctionne, voici un exemple montrant comment créer une vue personnalisée affichant un titre de chaîne.

Étape 1: Créez une classe de vue personnalisée.

public class CustomView extends FrameLayout {
    private TextView titleView;

    public CustomView(Context context) {
        super(context);
        init(null, 0, 0);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0, 0);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs, defStyleAttr, 0);
    }

    @RequiresApi(21)
    public CustomView(
            Context context, 
            AttributeSet attrs,
            int defStyleAttr,
            int defStyleRes) {

        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs, defStyleAttr, defStyleRes);
    }

    public void setTitle(String title) {
        titleView.setText(title);
    }

    private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        inflate(getContext(), R.layout.custom_view, this);

        titleView = findViewById(R.id.title_view);
    }
}

Étape 2: Définir un attribut de chaîne dans le values/attrs.xml fichier de ressources:

<resources>
    <declare-styleable name="CustomView">
        <attr name="title" format="string"/>
    </declare-styleable>
</resources>

Étape 3: Appliquer le @StringHandler annotation à la setTitle méthode pour indiquer au framework Spyglass d'acheminer la valeur d'attribut à cette méthode lorsque la vue est gonflée.

@HandlesString(attributeId = R.styleable.CustomView_title)
public void setTitle(String title) {
    titleView.setText(title);
}

Maintenant que votre classe a une annotation Spyglass, le framework Spyglass le détecte à la compilation et génère automatiquement le CustomView_SpyglassCompanion classe.

Étape 4: utilisez la classe générée dans la vue personnalisée init méthode:

private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    inflate(getContext(), R.layout.custom_view, this);

    titleView = findViewById(R.id.title_view);

    CustomView_SpyglassCompanion
            .builder()
            .withTarget(this)
            .withContext(getContext())
            .withAttributeSet(attrs)
            .withDefaultStyleAttribute(defStyleAttr)
            .withDefaultStyleResource(defStyleRes)
            .build()
            .callTargetMethodsNow();
}

C'est tout. Maintenant, lorsque vous instanciez la classe à partir de XML, le compagnon de Spyglass interprète les attributs et lance l'appel de méthode requis. Par exemple, si nous gonflons la disposition suivante, alors setTitle sera appelé avec "Hello, World!" comme argument.

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:width="match_parent"
    android:height="match_parent">

    <com.example.CustomView
        android:width="match_parent"
        android:height="match_parent"
        app:title="Hello, World!"/>
</FrameLayout>

Le cadre n'est pas limité aux ressources de chaîne a beaucoup d'annotations différentes pour gérer d'autres types de ressources. Il a également des annotations pour définir les valeurs par défaut et pour transmettre des valeurs d'espace réservé si vos méthodes ont plusieurs paramètres.

Jetez un coup d’œil au dépôt Github pour plus d’informations et d’exemples.


2
2017-11-20 12:30