Festlegen eigener attrs
-
27-09-2019 - |
Frage
Ich brauche meine eigenen Attribute zu implementieren, wie in com.android.R.attr
Nichts gefunden in der offiziellen Dokumentation, so brauche ich Informationen darüber, wie diese attrs zu definieren und wie sie von meinem Code verwenden.
Lösung
Derzeit ist die beste Dokumentation ist die Quelle. Sie können einen Blick auf sie hier href="https://github.com/android/platform_frameworks_base/blob/master/core/res/res/values/attrs.xml" rel="noreferrer"> .
Sie können Attribute im oberen <resources>
Elemente oder innerhalb eines <declare-styleable>
Elements definieren. Wenn ich ein attr in mehr als einem Ort benutzen werde habe ich es in das Root-Element. Beachten Sie, alle Attribute teilen die gleiche globale Namespace. Das bedeutet, dass selbst wenn Sie ein neues Attribut innerhalb eines <declare-styleable>
Elements erstellen kann es verwendet außerhalb davon sein, und Sie können nicht ein weiteres Attribut mit demselben Namen eines anderen Typs erstellen.
Ein <attr>
Element hat zwei XML-Attribute name
und format
. name
können Sie es nennen etwas und das ist, wie Sie im Code darauf zu verweisen am Ende, zum Beispiel R.attr.my_attribute
. Das format
Attribut kann verschiedene Werte haben je nach ‚Typ‘ des Attributs, das Sie möchten.
- Referenz - wenn es verweist auf eine andere Ressource-ID (beispielsweise "@ color / my_color", "@ Layout / my_layout")
- Farbe
- boolean
- Dimension
- float
- integer
- string
- Fraktion
- Enum - normalerweise implizit definiert
- Flagge - normalerweise implizit definiert
Sie können das Format auf mehrere Arten festgelegt durch |
beispielsweise unter Verwendung format="reference|color"
.
enum
Attribute können wie folgt definiert werden:
<attr name="my_enum_attr">
<enum name="value1" value="1" />
<enum name="value2" value="2" />
</attr>
flag
Attribute sind ähnlich, außer die Werte definiert werden müssen, damit sie etwas zusammen ored werden:
<attr name="my_flag_attr">
<flag name="fuzzy" value="0x01" />
<flag name="cold" value="0x02" />
</attr>
Neben Attribute gibt es das <declare-styleable>
Element. Auf diese Weise können Sie Attribute eine benutzerdefinierte Ansicht verwenden können, definieren. Sie tun dies, indem sie ein <attr>
Element spezifiziert, wenn es vorher Sie die format
nicht angeben, definiert wurde. Wenn Sie ein Android-attr, zum Beispiel zur Wiederverwendung, android. Schwerkraft, dann können Sie das in der name
tun, wie folgt
Ein Beispiel für eine benutzerdefinierte Ansicht <declare-styleable>
:
<declare-styleable name="MyCustomView">
<attr name="my_custom_attribute" />
<attr name="android:gravity" />
</declare-styleable>
Wenn Sie Ihre benutzerdefinierte Attribute in XML auf Ihrer benutzerdefinierten Ansicht definieren, müssen Sie ein paar Dinge zu tun. Zuerst müssen Sie einen Namespace deklarieren Ihre Attribute zu finden. Sie tun dies auf dem Root-Layoutelement. Normalerweise gibt es nur xmlns:android="http://schemas.android.com/apk/res/android"
. Sie müssen jetzt auch xmlns:whatever="http://schemas.android.com/apk/res-auto"
hinzufügen.
Beispiel:
<?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>
Schließlich, um den Zugang, dass benutzerdefiniertes Attribut, das Sie normalerweise tun dies im Konstruktor der benutzerdefinierten Ansicht wie folgt.
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();
}
Das Ende. :)
Andere Tipps
Qberticus Antwort ist gut, aber ein nützliches Detail fehlt. Wenn Sie diese in einer Bibliothek implementieren ersetzen:
xmlns:whatever="http://schemas.android.com/apk/res/org.example.mypackage"
mit:
xmlns:whatever="http://schemas.android.com/apk/res-auto"
Ansonsten ist die Anwendung, die die Bibliothek verwendet werden Laufzeitfehler haben.
Die Antwort oben deckt alles im Detail, abgesehen von ein paar Dinge.
Erstens, wenn es keine Stile sind, dann wird die (Context context, AttributeSet attrs)
Methodensignatur verwendet werden, um die Präferenz zu instanziieren. In diesem Fall nur context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)
verwenden, um die TypedArray zu erhalten.
Zweitens ist es nicht behandelt, wie mit plaurals Ressourcen (Anzahl Strings) beschäftigen. Diese können nicht mit der Verwendung von TypedArray behandelt werden. Hier ist ein Code-Schnipsel aus meinem SeekBarPreference, das die Zusammenfassung der Präferenz Formatierung seinen Wert legt entsprechend dem Wert der Präferenz. Wenn die XML für die Vorzugs Sätze android: Zusammenfassung in einer Textzeichenfolge oder eine Zeichenfolge resouce der Wert der Präferenz in den String formatiert ist (es sollte daran haben% d, um den Wert zu holen). Wenn Android. Zusammenfassung zu einer plaurals Ressource festgelegt ist, die verwendet wird, um das Ergebnis zu formatieren
// 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);
}
- Dies ist nur als ein Beispiel gegeben, jedoch, wenn Sie versucht sind, wollen die Zusammenfassung auf dem Einstellungsbildschirm zu setzen, dann müssen Sie
notifyChanged()
in der Präferenz desonDialogClosed
Methode aufzurufen.
Der traditionelle Ansatz ist voll von Standardcode und ungeschickten Umgang mit Ressourcen. Deshalb habe ich die Spyglass Rahmen . Um zu zeigen, wie es funktioniert, hier ist ein Beispiel dafür, wie eine benutzerdefinierte Ansicht zu machen, dass zeigt einen String-Titel.
Schritt 1:. Erstellen Sie eine benutzerdefinierte Ansicht Klasse
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);
}
}
Schritt 2: Definieren Sie ein Zeichenfolge-Attribut in der values/attrs.xml
Ressource-Datei:
<resources>
<declare-styleable name="CustomView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
Schritt 3:. Wenden Sie die @StringHandler
Anmerkung zur setTitle
Methode des Attributwert dieser Methode der Spyglass Rahmen Weg zu sagen, wenn die Ansicht aufgeblasen wird
@HandlesString(attributeId = R.styleable.CustomView_title)
public void setTitle(String title) {
titleView.setText(title);
}
Nun, da Ihre Klasse eine Spyglass Anmerkung hat, erkennt die Spyglass Rahmen es zum Zeitpunkt der Kompilierung und automatisch die CustomView_SpyglassCompanion
Klasse erzeugen.
Schritt 4: Verwenden Sie die generierte Klasse in der init
Methode der benutzerdefinierten Ansicht:
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();
}
Das ist es. Nun, wenn Sie die Klasse von XML-instanziiert, interpretieren die Spyglass Begleiter die Attribute und machen den erforderlichen Methodenaufruf. Zum Beispiel, wenn wir das folgende Layout dann aufblasen setTitle
mit "Hello, World!"
als Argument aufgerufen werden.
<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>
Der Rahmen ist nicht auf String-Ressourcen beschränkt hat viele verschiedene Anmerkungen zum Umgang mit anderen Ressourcentypen. Es hat auch Anmerkungen zur Definition von Standardwerten und für in Platzhalter Werte geben, wenn Ihre Methoden mehrere Parameter haben.
Haben Sie einen Blick auf die Github Repo für weitere Informationen und Beispiele.
Wenn Sie das format
Attribut aus dem attr
Elemente weglassen, können Sie es verwenden, um eine Klasse von XML-Layout zu verweisen.
- Beispiel von attrs.xml .
- Android Studio versteht, dass die Klasse von XML verwiesen wird
- d.
-
Refactor > Rename
funktioniert -
Find Usages
funktioniert - und so weiter ...
-
- d.
nicht angeben, ein format
Attribut in ... / src / main / res / Werte / attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
....
<attr name="give_me_a_class"/>
....
</declare-styleable>
</resources>
verwenden Sie es in einigen Layout-Datei ... / 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>
analysiert, um die Klasse in Ihrer Ansicht Initialisierungscode ... / 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()
}
}
}