Definiowanie własnych atrybutów

Muszę zaimplementować własne atrybuty jak w com.android.R.attr

Nie znalazłem nic w oficjalnej dokumentacji, więc potrzebuję informacji o tym, jak definiować te attry i jak ich używać z mojego kodu.

Author: Suragch, 2010-08-09

4 answers

Obecnie najlepszą dokumentacją jest źródło. Możesz spojrzeć na to tutaj (attrs.xml) .

Atrybuty można definiować w górnym elemencie <resources> lub wewnątrz elementu <declare-styleable>. Jeśli mam używać attr w więcej niż jednym miejscu, umieszczam go w elemencie głównym. Uwaga: wszystkie atrybuty mają tę samą globalną przestrzeń nazw. Oznacza to, że nawet jeśli utworzysz nowy atrybut wewnątrz <declare-styleable> elementu, może on być użyty poza nim i nie możesz utworzyć innego atrybutu z ta sama nazwa innego typu.

Element <attr> posiada dwa atrybuty xml name i format. name pozwala na nazywanie tego czymś i tak kończy się odniesienie do niego w kodzie, np. R.attr.my_attribute. Atrybut format może mieć różne wartości w zależności od "typu" atrybutu, który chcesz.

  • reference-jeśli odwołuje się do innego identyfikatora zasobu (np. " @ color / my_color", "@layout / my_layout")
  • kolor
  • boolean
  • wymiar
  • float
  • liczba całkowita
  • string
  • ułamek
  • enum-normalnie domyślnie zdefiniowane
  • flaga-normalnie niejawnie zdefiniowana

Możesz ustawić format na wiele typów za pomocą |, np. format="reference|color".

enum atrybuty można zdefiniować w następujący sposób:

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

flag atrybuty są podobne z wyjątkiem wartości, które muszą być zdefiniowane tak, aby można je bitować razem:

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

Oprócz atrybutów istnieje element <declare-styleable>. Umożliwia to definiowanie atrybutów, których może używać widok niestandardowy. Można to zrobić przez podanie elementu <attr>, jeśli był on wcześniej zdefiniowany, nie należy podawać format. Jeśli chcesz ponownie użyć Android attr, na przykład android: gravity, możesz to zrobić w name, w następujący sposób.

Przykład niestandardowego widoku <declare-styleable>:
<declare-styleable name="MyCustomView">
  <attr name="my_custom_attribute" />
  <attr name="android:gravity" />
</declare-styleable>

Podczas definiowania własnych atrybutów w XML na Twoim widok niestandardowy musisz zrobić kilka rzeczy. Najpierw musisz zadeklarować przestrzeń nazw, aby znaleźć swoje atrybuty. Robisz to w głównym elemencie układu. Zwykle jest tylko xmlns:android="http://schemas.android.com/apk/res/android". Musisz teraz również dodać xmlns:whatever="http://schemas.android.com/apk/res-auto".

Przykład:

<?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>

Wreszcie, aby uzyskać dostęp do tego niestandardowego atrybutu, zwykle robisz to w konstruktorze niestandardowego widoku w następujący sposób.

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

Koniec. :)

 872
Author: Rich Schuler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-27 23:13:17

Odpowiedź Qberticusa jest dobra, ale brakuje jednego użytecznego szczegółu. Jeśli implementujesz je w bibliotece zastąp:

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

Z:

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

W przeciwnym razie aplikacja korzystająca z biblioteki będzie miała błędy uruchomieniowe.

 81
Author: Neil Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-16 16:18:08

Powyższa odpowiedź obejmuje wszystko w najdrobniejszych szczegółach, poza kilkoma rzeczami.

Po pierwsze, jeśli nie ma stylów, to do utworzenia instancji preferencji zostanie użyta sygnatura metody (Context context, AttributeSet attrs). W tym przypadku wystarczy użyć context.obtainStyledAttributes(attrs, R.styleable.MyCustomView), aby uzyskać TypedArray.

Po drugie nie obejmuje on sposobu radzenia sobie z zasobami plaurals (ciągi ilościowe). Nie można sobie z tym poradzić za pomocą TypedArray. Oto fragment kodu z My SeekBarPreference, który ustawia podsumowanie formatowania preferencji jego wartość zgodnie z wartością preferencji. Jeśli XML dla preferencji ustawia android: summary na łańcuch tekstowy lub łańcuch resouce wartość preferencji jest sformatowana do łańcucha (powinien mieć w nim %d, aby podnieść wartość). Jeśli Android: summary jest ustawiony na zasób plaurals, to jest on używany do formatowania wyniku.

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

  • jest to po prostu podane jako przykład, jednak jeśli chcesz, aby ustawić podsumowanie na ekranie preferencji, to musisz wywołanie notifyChanged() w preferowanej metodzie onDialogClosed.
 14
Author: Steve Waring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-08 13:32:48

Tradycyjne podejście jest pełne kodu boilerplate i niezdarnej obsługi zasobów. Dlatego zrobiłem Framework Spyglass. Aby zademonstrować, jak to działa, oto przykład pokazujący, jak utworzyć niestandardowy widok, który wyświetla tytuł ciągu znaków.

Krok 1: Utwórz własną klasę widoku.

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

Krok 2: Zdefiniuj atrybut string w pliku zasobuvalues/attrs.xml:

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

Krok 3: Zastosuj adnotację @StringHandler do metody setTitle, aby przekazać Framework Spyglass do skieruj wartość atrybutu do tej metody, gdy widok jest napompowany.

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

Teraz, gdy twoja klasa ma adnotację Spyglass, Framework Spyglass wykryje ją podczas kompilacji i automatycznie wygeneruje klasę CustomView_SpyglassCompanion.

Krok 4: Użyj Wygenerowanej klasy w niestandardowym widoku init metoda:

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

To jest to. Teraz, gdy tworzysz instancję klasy z XML, Spyglass companion interpretuje atrybuty i wykonuje wymagane wywołanie metody. Na przykład, jeśli napompuj następujący układ, a setTitle zostanie wywołany z "Hello, World!" jako argumentem.

<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>

Framework nie jest ograniczony do zasobów łańcuchowych ma wiele różnych adnotacji do obsługi innych typów zasobów. Posiada również adnotacje do definiowania wartości domyślnych i przekazywania wartości zastępczych, jeśli twoje metody mają wiele parametrów.

Spójrz na repozytorium Github, aby uzyskać więcej informacji i przykładów.

 2
Author: Helios,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-05 22:25:03