Devo implementare i miei attributi come in com.android.R.attr
Non ho trovato nulla nella documentazione ufficiale, quindi ho bisogno di informazioni su come definire questi attr e su come usarli dal mio codice.
Devo implementare i miei attributi come in com.android.R.attr
Non ho trovato nulla nella documentazione ufficiale, quindi ho bisogno di informazioni su come definire questi attr e su come usarli dal mio codice.
Risposte:
Attualmente la migliore documentazione è la fonte. Puoi dare un'occhiata qui (attrs.xml) .
È possibile definire gli attributi nell'elemento superiore <resources>
o all'interno di un <declare-styleable>
elemento. Se userò un attr in più di un posto, lo inserirò nell'elemento root. Nota, tutti gli attributi condividono lo stesso spazio dei nomi globale. Ciò significa che anche se si crea un nuovo attributo all'interno di a<declare-styleable>
elemento, può essere utilizzato al di fuori di esso e non è possibile creare un altro attributo con lo stesso nome di un tipo diverso.
Un <attr>
elemento ha due attributi xml name
e format
. name
ti permette di chiamarlo qualcosa e questo è il modo in cui finisci per riferirti ad esso nel codice, ad es R.attr.my_attribute
. L' format
attributo può avere valori diversi a seconda del 'tipo' di attributo desiderato.
È possibile impostare il formato a più tipi utilizzando |
, ad esempio, format="reference|color"
.
enum
gli attributi possono essere definiti come segue:
<attr name="my_enum_attr">
<enum name="value1" value="1" />
<enum name="value2" value="2" />
</attr>
flag
gli attributi sono simili, ad eccezione dei valori che devono essere definiti in modo che possano essere bit bited insieme:
<attr name="my_flag_attr">
<flag name="fuzzy" value="0x01" />
<flag name="cold" value="0x02" />
</attr>
Oltre agli attributi c'è l' <declare-styleable>
elemento. Ciò consente di definire gli attributi che una vista personalizzata può utilizzare. Puoi farlo specificando un <attr>
elemento, se è stato precedentemente definito non specifichi format
. Se desideri riutilizzare un attr android, ad esempio android: gravità, puoi farlo nel name
, come segue.
Un esempio di una vista personalizzata <declare-styleable>
:
<declare-styleable name="MyCustomView">
<attr name="my_custom_attribute" />
<attr name="android:gravity" />
</declare-styleable>
Quando si definiscono gli attributi personalizzati in XML nella vista personalizzata, è necessario eseguire alcune operazioni. Per prima cosa devi dichiarare uno spazio dei nomi per trovare i tuoi attributi. Lo fai sull'elemento del layout di root. Normalmente c'è solo xmlns:android="http://schemas.android.com/apk/res/android"
. Ora devi anche aggiungerexmlns:whatever="http://schemas.android.com/apk/res-auto"
.
Esempio:
<?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>
Infine, per accedere a quell'attributo personalizzato, normalmente lo fai nel costruttore della tua vista personalizzata come segue.
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 fine. :)
View
: github.com/commonsguy/cw-advandroid/tree/master/Views/…
xmlns:my="http://schemas.android.com/apk/lib/my.namespace"
- nessuna copia attrs.xml. Nota il percorso URI dello spazio dei nomi deve essere / apk / * lib * non / apk / res.
apk/lib
trucco non ha funzionato per me su attributi personalizzati con formato di riferimento da un progetto di libreria. Quello che ha funzionato è stato usare apk/res-auto
, come suggerito in stackoverflow.com/a/13420366/22904 appena sotto e anche in stackoverflow.com/a/10217752
enum
e flag
: il primo ci consente di scegliere un solo valore, il secondo ci consente di combinarne diversi. Ho scritto una risposta più lunga in una domanda simile qui , e dopo aver trovato questa domanda ho pensato di collegarmi a quello.
a.recycle()
è molto importante qui per liberare memoria
La risposta di Qberticus è buona, ma manca un dettaglio utile. Se li stai implementando in una libreria sostituisci:
xmlns:whatever="http://schemas.android.com/apk/res/org.example.mypackage"
con:
xmlns:whatever="http://schemas.android.com/apk/res-auto"
In caso contrario, l'applicazione che utilizza la libreria avrà errori di runtime.
La risposta sopra copre tutto nei minimi dettagli, a parte un paio di cose.
Innanzitutto, se non ci sono stili, (Context context, AttributeSet attrs)
verrà utilizzata la firma del metodo per creare un'istanza della preferenza. In questo caso basta usare context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)
per ottenere TypedArray.
In secondo luogo, non tratta il modo in cui gestire le risorse plaurali (stringhe di quantità). Non è possibile gestirli utilizzando TypedArray. Ecco uno snippet di codice dal mio SeekBarPreference che imposta il riepilogo della preferenza formattandone il valore in base al valore della preferenza. Se l'xml per la preferenza imposta android: il riepilogo su una stringa di testo o su una stringa, il valore della preferenza viene formattato nella stringa (dovrebbe contenere% d al suo interno, per raccogliere il valore). Se android: il riepilogo è impostato su una risorsa plaurals, viene utilizzato per formattare il risultato.
// 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);
}
notifyChanged()
il onDialogClosed
metodo della preferenza .L'approccio tradizionale è pieno di codice boilerplate e gestione delle risorse maldestra. Ecco perché ho realizzato il framework Spyglass . Per dimostrare come funziona, ecco un esempio che mostra come creare una vista personalizzata che mostri un titolo String.
Passaggio 1: creare una classe di visualizzazione personalizzata.
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);
}
}
Passaggio 2: definire un attributo stringa nel values/attrs.xml
file di risorse:
<resources>
<declare-styleable name="CustomView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
Passaggio 3: applicare l' @StringHandler
annotazione al setTitle
metodo per indicare al framework Spyglass di instradare il valore dell'attributo a questo metodo quando la vista è gonfiata.
@HandlesString(attributeId = R.styleable.CustomView_title)
public void setTitle(String title) {
titleView.setText(title);
}
Ora che la tua classe ha un'annotazione Spyglass, il framework Spyglass la rileverà in fase di compilazione e genererà automaticamente la CustomView_SpyglassCompanion
classe.
Passaggio 4: utilizzare la classe generata nel init
metodo della vista personalizzata :
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();
}
Questo è tutto. Ora, quando si crea un'istanza della classe da XML, il compagno Spyglass interpreta gli attributi e fa chiamare il metodo richiesto. Ad esempio, se si gonfia il seguente layout, setTitle
verrà chiamato "Hello, World!"
come argomento.
<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>
Il framework non è limitato alle risorse di stringa ha molte annotazioni diverse per la gestione di altri tipi di risorse. Ha anche annotazioni per la definizione di valori predefiniti e per il passaggio di valori segnaposto se i metodi hanno più parametri.
Dai un'occhiata al repository Github per ulteriori informazioni ed esempi.
android:title="@{"Hello, world!"}"
.
se si omette l' format
attributo attr
dall'elemento, è possibile utilizzarlo per fare riferimento a una classe dai layout XML.
Refactor > Rename
lavoriFind Usages
lavorinon specificare un format
attributo in ... / src / main / res / valori / attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
....
<attr name="give_me_a_class"/>
....
</declare-styleable>
</resources>
usalo in alcuni file di layout ... / 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>
analizzare la classe nel codice di inizializzazione della vista ... / 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()
}
}
}