Saya perlu menerapkan atribut saya sendiri seperti di com.android.R.attr
Tidak menemukan apa pun dalam dokumentasi resmi sehingga saya memerlukan informasi tentang cara mendefinisikan attrs ini dan cara menggunakannya dari kode saya.
Saya perlu menerapkan atribut saya sendiri seperti di com.android.R.attr
Tidak menemukan apa pun dalam dokumentasi resmi sehingga saya memerlukan informasi tentang cara mendefinisikan attrs ini dan cara menggunakannya dari kode saya.
Jawaban:
Saat ini dokumentasi terbaik adalah sumbernya. Anda dapat melihatnya di sini (attrs.xml) .
Anda bisa mendefinisikan atribut di <resources>
elemen atas atau di dalam <declare-styleable>
elemen. Jika saya akan menggunakan attr di lebih dari satu tempat saya letakkan di elemen root. Catatan, semua atribut memiliki namespace global yang sama. Itu berarti bahwa bahkan jika Anda membuat atribut baru di dalam <declare-styleable>
elemen itu dapat digunakan di luarnya dan Anda tidak dapat membuat atribut lain dengan nama yang sama dari tipe yang berbeda.
Suatu <attr>
elemen memiliki dua atribut xml name
dan format
. name
memungkinkan Anda menyebutnya sesuatu dan ini adalah bagaimana Anda akhirnya menyebutnya dalam kode, misalnya R.attr.my_attribute
,. The format
atribut dapat memiliki nilai yang berbeda tergantung pada 'jenis' atribut yang Anda inginkan.
Anda dapat mengatur format ke beberapa jenis dengan menggunakan |
, misalnya format="reference|color"
,.
enum
atribut dapat didefinisikan sebagai berikut:
<attr name="my_enum_attr">
<enum name="value1" value="1" />
<enum name="value2" value="2" />
</attr>
flag
atribut serupa kecuali nilai-nilai perlu didefinisikan sehingga mereka dapat digigit bersama:
<attr name="my_flag_attr">
<flag name="fuzzy" value="0x01" />
<flag name="cold" value="0x02" />
</attr>
Selain atribut ada <declare-styleable>
elemen. Ini memungkinkan Anda untuk mendefinisikan atribut yang bisa digunakan tampilan kustom. Anda melakukan ini dengan menentukan <attr>
elemen, jika sebelumnya ditentukan Anda tidak menentukan format
. Jika Anda ingin menggunakan kembali Android attr, misalnya, Android: Gravity, maka Anda dapat melakukannya diname
, sebagai berikut.
Contoh tampilan khusus <declare-styleable>
:
<declare-styleable name="MyCustomView">
<attr name="my_custom_attribute" />
<attr name="android:gravity" />
</declare-styleable>
Ketika mendefinisikan atribut khusus Anda dalam XML pada tampilan kustom Anda, Anda perlu melakukan beberapa hal. Pertama, Anda harus mendeklarasikan namespace untuk menemukan atribut Anda. Anda melakukan ini pada elemen tata letak root. Biasanya hanya ada xmlns:android="http://schemas.android.com/apk/res/android"
. Anda sekarang juga harus menambahkanxmlns:whatever="http://schemas.android.com/apk/res-auto"
.
Contoh:
<?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>
Terakhir, untuk mengakses atribut khusus yang biasanya Anda lakukan di konstruktor tampilan kustom Anda sebagai berikut.
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();
}
Tamat. :)
View
: github.com/commonsguy/cw-advandroid/tree/master/Views/…
xmlns:my="http://schemas.android.com/apk/lib/my.namespace"
- tanpa menyalin attrs.xml. Perhatikan bahwa jalur URI namespace harus / apk / * lib * not / apk / res.
apk/lib
triknya tidak berfungsi untuk saya pada atribut khusus dengan format referensi dari proyek perpustakaan. Apa yang melakukan pekerjaan adalah untuk digunakan apk/res-auto
, seperti yang disarankan dalam stackoverflow.com/a/13420366/22904 tepat di bawah dan juga di stackoverflow.com/a/10217752
enum
dan flag
: yang pertama memungkinkan kita memilih satu dan hanya satu nilai, yang terakhir memungkinkan kita menggabungkan beberapa. Saya menulis jawaban yang lebih panjang dalam pertanyaan yang sama di sini , dan setelah sekarang menemukan pertanyaan ini saya pikir saya akan terhubung ke itu
a.recycle()
sangat penting di sini untuk membebaskan memori
Jawaban Qberticus baik, tetapi satu detail yang berguna tidak ada. Jika Anda menerapkan ini di perpustakaan ganti:
xmlns:whatever="http://schemas.android.com/apk/res/org.example.mypackage"
dengan:
xmlns:whatever="http://schemas.android.com/apk/res-auto"
Kalau tidak, aplikasi yang menggunakan perpustakaan akan memiliki kesalahan runtime.
Jawaban di atas mencakup semuanya dengan sangat terperinci, terlepas dari beberapa hal.
Pertama, jika tidak ada gaya, maka (Context context, AttributeSet attrs)
tanda tangan metode akan digunakan untuk instantiate preferensi. Dalam hal ini gunakan sajacontext.obtainStyledAttributes(attrs, R.styleable.MyCustomView)
untuk mendapatkan TypedArray.
Kedua tidak mencakup cara menangani sumber daya plaur (string kuantitas). Ini tidak bisa ditangani dengan menggunakan TypedArray. Berikut ini cuplikan kode dari SeekBarPreference saya yang menetapkan ringkasan preferensi yang memformat nilainya sesuai dengan nilai preferensi. Jika xml untuk preferensi menyetel android: ringkasan ke string teks atau string, resouce nilai preferensi diformat ke dalam string (seharusnya memiliki% d di dalamnya, untuk mengambil nilai). Jika android: ringkasan diatur ke sumber daya plaur, maka itu digunakan untuk memformat hasilnya.
// 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()
metode preferensi onDialogClosed
.Pendekatan tradisional penuh dengan kode boilerplate dan penanganan sumber daya yang canggung. Itu sebabnya saya membuat kerangka kerja Spyglass . Untuk mendemonstrasikan cara kerjanya, berikut adalah contoh yang menunjukkan cara membuat tampilan kustom yang menampilkan judul String.
Langkah 1: Buat kelas tampilan kustom.
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);
}
}
Langkah 2: Tentukan atribut string dalam values/attrs.xml
file sumber daya:
<resources>
<declare-styleable name="CustomView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
Langkah 3: Terapkan @StringHandler
anotasi ke setTitle
metode untuk memberi tahu kerangka kerja Spyglass untuk merutekan nilai atribut ke metode ini saat tampilan meningkat.
@HandlesString(attributeId = R.styleable.CustomView_title)
public void setTitle(String title) {
titleView.setText(title);
}
Sekarang kelas Anda memiliki anotasi Spyglass, kerangka kerja Spyglass akan mendeteksinya pada waktu kompilasi dan secara otomatis menghasilkan CustomView_SpyglassCompanion
kelas.
Langkah 4: Gunakan kelas yang dihasilkan dalam metode tampilan kustom init
:
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();
}
Itu dia. Sekarang ketika Anda instantiate kelas dari XML, pendamping Spyglass menafsirkan atribut dan membuat panggilan metode yang diperlukan. Misalnya, jika kita mengembang tata letak berikut maka setTitle
akan dipanggil dengan "Hello, World!"
sebagai argumen.
<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>
Kerangka kerja tidak terbatas pada sumber daya string memiliki banyak anotasi yang berbeda untuk menangani jenis sumber daya lainnya. Ini juga memiliki anotasi untuk menentukan nilai default dan untuk meneruskan nilai placeholder jika metode Anda memiliki beberapa parameter.
Lihat repo Github untuk informasi dan contoh lebih lanjut.
android:title="@{"Hello, world!"}"
.
jika Anda menghilangkan format
atribut dari attr
elemen, Anda bisa menggunakannya untuk referensi kelas dari tata letak XML.
Refactor > Rename
bekerjaFind Usages
bekerjajangan tentukan format
atribut di ... / src / main / res / values / attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
....
<attr name="give_me_a_class"/>
....
</declare-styleable>
</resources>
gunakan di beberapa file 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>
parsing kelas dalam kode inisialisasi tampilan Anda ... / 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()
}
}
}