Atribut dengan nama yang sama di attrs.xml untuk tampilan khusus

180

Saya sedang menulis beberapa tampilan khusus yang berbagi beberapa atribut dengan nama yang sama. Di <declare-styleable>bagian masing-masing di attrs.xmlsaya ingin menggunakan nama yang sama untuk atribut:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView1">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>
</resources>

Saya mendapatkan pesan kesalahan yang mengatakan itu myattr1dan myattr2sudah ditentukan. Saya menemukan bahwa saya harus menghilangkan formatatribut untuk myattr1dan myattr2dalam MyView2, tetapi jika saya melakukannya, saya mendapatkan kesalahan berikut di konsol:

[2010-12-13 23:53:11 - MyProject] ERROR: In <declare-styleable> MyView2, unable to find attribute 

Apakah ada cara saya bisa mencapai ini, mungkin semacam namespacing (hanya menebak)?

Venator85
sumber

Jawaban:

401

Solusi: Cukup ekstrak atribut umum dari kedua tampilan dan menambahkannya langsung sebagai anak-anak dari <resources>simpul:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="myattr1" format="string" />
    <attr name="myattr2" format="dimension" />

    <declare-styleable name="MyView1">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>
</resources>
Venator85
sumber
11
apa yang terjadi ketika myattr1string MyView1dan integer MyView2?
foxx1337
4
Saya rasa tidak, misalnya kita dapat memiliki atribut 'orientasi' dan untuk beberapa pandangan itu adalah 'horisontal' / 'vertikal' dan untuk 'lanskap' / 'potret' / 'persegi' lainnya. Dari sudut pandang saya itu adalah bug (atau setidaknya perilaku tidak konsisten) di Android (perlu diingat bahwa: 1. atribut yang dapat diubah selalu dimulai dengan awalan = tampilan nama dan 2. jika Anda membuat proyek perpustakaan terpisah untuk pandangan seperti itu semuanya akan berfungsi dengan baik )
se.solovyev
4
Ketika saya mengikuti jawaban ini saya mendapatkan ERROR: In <declare-styleable> com_app_view_widget, unable to find attribute customAttr Untuk semua tampilan yang saya coba nyatakan. Ada ide?
Dapp
45
@Google: Desain jelek
Glenn Bech
6
@ foxx1337 Cukup gunakan <attr name="myattr1" format="string|integer" />. Bekerja untukku.
Mygod
58

Saya memposting jawaban ini karena solusi yang diposting di atas tidak berhasil untuk saya di Android Studio. Saya perlu membagikan atribut khusus saya di antara tampilan kustom saya, jadi saya mencoba solusi di atas di Android Studio tetapi tidak berhasil. Jadi saya bereksperimen dan mencari cara untuk melakukannya. Semoga ini bisa membantu seseorang mencari masalah yang sama.

  <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <!-- parent styleable -->
     <declare-styleable name="MyView">
         <attr name="myattr1" format="string" />
         <attr name="myattr2" format="dimension" />
     </declare-styleable>

     <!-- inheriting parent styleable -->
     <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
    <declare-styleable name="MyView1" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myBackgroundColor" format="color"/>
    </declare-styleable>


    <!-- inheriting parent styleable -->
    <!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
    <declare-styleable name="MyView2" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myfont" format="string"/>
        ...
    </declare-styleable>
</resources>

Ini bekerja untuk saya sepenuhnya. Kita perlu membuat Parent menjadi gaya dan kemudian kita perlu mewarisi orang tua yang gaya. Sebagai contoh, seperti yang telah saya lakukan di atas: Nama gaya induk MyView dan mewarisi ini ke gaya lainnya seperti MyView1 dan MyView2.

Priya Singhal
sumber
1
Ini berhasil untuk saya. Saya tidak dapat menemukan cara untuk referensi atribut yang diekstraksi dalam kode dari jawaban yang diterima.
Nemanja Kovacevic
Hmm .. itu aneh .. solusi yang diterima tampaknya bekerja dengan baik untuk saya (targetSdkVersion 27). Mungkin karena atribut seperti "teks" adalah umum & mungkin ada di beberapa attrs.xml lainnya ..?
Aba
Saya mencoba dengan nama yang kemungkinan besar tidak umum & solusi yang diterima masih bekerja untuk saya.
Aba
Saya setuju dengan komentar pertama! Tidak ada cara untuk referensi attr yang diekstraksi dari typedArray. Oleh karena itu Anda perlu mendefinisikan orang tua yang gaya
reavcn
untuk ini bekerja jangan lupa untuk mengatasi atribut ini di orangtua dan tidak pada anak (untuk kelas MyView2yang tepat: R.styleable.MyView2_myattr1, salah: R.styleable.MyView_myattr1)
vigilancer
28

Saat Priya Singhal menjawab, Android Studio membutuhkan nama atribut umum untuk didefinisikan dalam nama gaya mereka sendiri. Mereka tidak bisa menjadi akarnya lagi.

Namun, ada beberapa hal lain yang perlu diperhatikan (itulah sebabnya saya juga menambahkan jawaban):

  • Gaya umum tidak perlu dinamai hal yang sama dengan tampilan. (Berkat jawaban ini untuk menunjukkan hal itu.)
  • Anda tidak perlu menggunakan warisan dengan orang tua.

Contoh

Inilah yang saya lakukan dalam proyek terbaru yang memiliki dua tampilan kustom yang sama-sama memiliki atribut yang sama. Selama tampilan khusus masih memiliki nama untuk atribut dan tidak termasuk format, saya masih dapat mengaksesnya seperti biasa dari kode.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- common attributes to all custom text based views -->

    <declare-styleable name="TextAttributes">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <!-- custom text views -->

    <declare-styleable name="View1">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Contoh efisien

Bahkan, saya bahkan tidak perlu meletakkan atribut di bawah nama kustom. Selama saya mendefinisikannya (memberi mereka a format) untuk setidaknya satu tampilan kustom, saya dapat menggunakannya di mana saja (tanpa format). Jadi ini juga berfungsi (dan terlihat lebih bersih):

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="View1">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Namun, untuk proyek besar, ini bisa menjadi berantakan dan mendefinisikan mereka di atas dalam satu lokasi mungkin lebih baik (seperti yang disarankan di sini ).

Suragch
sumber
Apa yang salah dengan warisan? Saya memiliki hierarki tampilan ubahsuaian yang terkait dengan styleable tidak mencerminkan hubungan ini, yang hanya dapat disimpulkan dalam definisi gaya terkait dengan memberi nama konvensi dan item spesifik yang ditentukan di dalamnya (memperhatikan bahwa beberapa milik salah satu yang dapat ditata dan beberapa lainnya). Saya lebih suka membuatnya eksplisit dengan parentatribut tetapi belum melihat banyak posting menyarankan penggunaannya.
samis
@samis, saya belum mengerjakan ini untuk sementara waktu, tapi saya tidak tahu ada yang salah dengan menggunakan parent. Saya pikir saya hanya mengatakan itu tidak diperlukan.
Suragch
Tidak perlu, saya hanya membuat subclass lain melilit atribut tambahan yang saya tidak ingin dimasukkan ke dalam kelas dasar. Saya hanya menggunakan komentar dan konvensi penamaan untuk menunjukkan pemisahan.
samis
8

Terima kasih Lewis saya punya masalah yang sama, dan solusi warisan Anda memberi saya petunjuk untuk melakukannya seperti di bawah ini dan berfungsi dengan baik. Saya baru saja menyatakan atribut umum di atas dan menulis ulang di badan deklarasi gaya lagi tanpa format. Saya harap ini membantu seseorang

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- common attributes -->
     <attr name="myattr1" format="string" />
     <attr name="myattr2" format="dimension" />

 <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
<declare-styleable name="MyView1" >
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myBackgroundColor" format="color"/>
</declare-styleable>

<!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
<declare-styleable name="MyView2" parent="MyView">
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myfont" format="string"/>
    ...
</declare-styleable>

Hanieh Variani
sumber
1

Hanya dalam kasus seseorang masih terjebak dengan masalah ini setelah mencoba solusi yang tersedia. Saya terjebak dengan menambahkan subtitleatributstring format.

Solusi saya adalah menghapus format.

sebelum:

<attr name="subtitle" format="string"/>

setelah:

<attr name="subtitle"/>

Ahmad Muzakki
sumber