Question

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

rien trouvé dans la documentation officielle donc j'ai besoin d'informations sur la façon de définir ces attrs et comment les utiliser dans mon code.

Était-ce utile?

La solution

À l'heure actuelle, la meilleure documentation est la source. Vous pouvez jeter un coup d'oeil ici (attrs. xml) .

Vous pouvez définir des attributs dans l'élément <resources> supérieur ou à l'intérieur d'un élément de <declare-styleable>. Si je vais utiliser un attr dans plus d'un endroit où je l'ai mis dans l'élément racine. Notez 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 élément de <declare-styleable> il peut être utilisé en dehors de celui-ci et vous ne pouvez pas créer un autre attribut avec le même nom d'un type différent.

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

  • référence - si elle fait référence à un autre identifiant de ressource (par exemple, "@ couleur / my_color", "@ layout / my_layout")
  • couleur
  • boolean
  • dimension
  • float
  • entier
  • chaîne
  • fraction
  • ENUM - normalement défini implicitement
  • flag - normalement défini implicitement

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

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

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

attributs de flag sont similaires, sauf les valeurs doivent être définies afin qu'ils puissent être peu ORED ensemble:

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

En plus des attributs, il est l'élément <declare-styleable>. Cela vous permet de définir des attributs d'une vue personnalisée peut utiliser. Vous faites cela en spécifiant un élément <attr>, si elle a déjà été défini, vous ne spécifiez pas le format. Si vous souhaitez réutiliser un androïde attr, par exemple, android:. Gravité, alors vous pouvez le faire dans le name, comme suit

Un exemple d'une 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 sur votre vue personnalisée que vous devez faire quelques choses. D'abord, vous devez déclarer un espace de noms pour trouver vos attributs. Pour ce faire, sur l'élément de mise en page de racine. Normalement, il n'y a que xmlns:android="http://schemas.android.com/apk/res/android". Vous devez maintenant ajouter également 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, l'accès à ce point de vue attribut personnalisé vous font normalement dans le constructeur de votre commande comme suit.

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. :)

Autres conseils

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

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.

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

Tout d'abord, s'il n'y a pas de styles, la signature de la méthode de (Context context, AttributeSet attrs) sera utilisé pour instancier la préférence. Dans ce cas, il suffit d'utiliser context.obtainStyledAttributes(attrs, R.styleable.MyCustomView) pour obtenir le TypedArray.

En second lieu, il ne couvre pas comment traiter les ressources plaurals (chaînes de quantité). Ceux-ci ne peuvent pas être traitées en utilisant TypedArray. Voici un extrait de code de mon SeekBarPreference qui définit le résumé de la préférence mise en forme de sa valeur en fonction de la valeur de la préférence. Si le fichier XML pour les jeux de préférence Android: résumé à une chaîne de texte ou une chaîne resouce la valeur de la préférence est formatée dans la chaîne (il devrait avoir% d en elle, pour ramasser la valeur). Si android. Résumé est réglé sur une ressource de plaurals, puis qui 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 simplement donné à titre d'exemple, cependant, si vous voulez sont tentés de régler le résumé sur l'écran de préférence, vous devez appeler notifyChanged() dans la méthode de onDialogClosed de la préférence.

L'approche traditionnelle est pleine de code réutilisable et la gestion des ressources maladroite. Voilà pourquoi j'ai fait le cadre Spyglass . Pour montrer comment cela fonctionne, voici un exemple montrant comment faire une vue personnalisée qui affiche un titre de chaîne.

Étape 1:. Créer 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 fichier de ressources values/attrs.xml:

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

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

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

Maintenant que votre classe a une annotation Spyglass, le cadre Spyglass détectera lors de la compilation et de générer automatiquement la classe CustomView_SpyglassCompanion.

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

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

Voilà. Maintenant, lorsque vous instancier la classe de XML, le compagnon Spyglass interprète les attributs et fait l'appel de méthode nécessaire. Par exemple, si on gonfle la mise en page suivante alors setTitle sera appelée 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 ne se limite pas aux ressources de chaîne a beaucoup de différentes annotations pour le traitement d'autres types de ressources. Il a également des annotations pour définir des valeurs par défaut et pour passer des valeurs d'espace réservé si vos méthodes ont plusieurs paramètres.

Jetez un oeil à la prise en pension Github pour plus d'informations et des exemples.

si vous ne spécifiez pas l'attribut format de l'élément attr, vous pouvez l'utiliser pour référencer une classe de mises en page XML.

  • exemple attrs.xml .
  • Android comprend que studio la classe est référencée à partir de XML
    • i.e..
      • Refactor > Rename fonctionne
      • Find Usages fonctionne
      • et ainsi de suite ...

ne spécifiez pas d'attribut format ... / src / main / res / valeurs / attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="MyCustomView">
        ....
        <attr name="give_me_a_class"/>
        ....
    </declare-styleable>

</resources>

l'utiliser dans un certain fichier de mise en page ... / src / main / res / layout / activity__main_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<SomeLayout
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- make sure to use $ dollar signs for nested classes -->
    <MyCustomView
        app:give_me_a_class="class.type.name.Outer$Nested/>

    <MyCustomView
        app:give_me_a_class="class.type.name.AnotherClass/>

</SomeLayout>

parse la classe dans votre code d'initialisation de vue ... / src / main / java /.../ MyCustomView.kt

class MyCustomView(
        context:Context,
        attrs:AttributeSet)
    :View(context,attrs)
{
    // parse XML attributes
    ....
    private val giveMeAClass:SomeCustomInterface
    init
    {
        context.theme.obtainStyledAttributes(attrs,R.styleable.ColorPreference,0,0).apply()
        {
            try
            {
                // very important to use the class loader from the passed-in context
                giveMeAClass = context::class.java.classLoader!!
                        .loadClass(getString(R.styleable.MyCustomView_give_me_a_class))
                        .newInstance() // instantiate using 0-args constructor
                        .let {it as SomeCustomInterface}
            }
            finally
            {
                recycle()
            }
        }
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top