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