Android - Menulis komponen khusus (gabungan)

132

Aplikasi Android yang saya kembangkan saat ini memiliki aktivitas utama yang telah berkembang cukup besar. Ini terutama karena mengandung TabWidget3 tab. Setiap tab memiliki beberapa komponen. Kegiatan harus mengendalikan semua komponen itu sekaligus. Jadi saya pikir Anda dapat membayangkan bahwa Kegiatan ini memiliki 20 bidang (bidang untuk hampir setiap komponen). Juga mengandung banyak logika (klik pendengar, logika untuk mengisi daftar, dll).

Apa yang biasanya saya lakukan dalam kerangka kerja berbasis komponen adalah untuk membagi semuanya menjadi komponen kustom. Setiap komponen khusus akan memiliki tanggung jawab yang jelas. Ini akan berisi kumpulan komponennya sendiri dan semua logika lain yang terkait dengan komponen itu.

Saya mencoba mencari tahu bagaimana hal ini dapat dilakukan, dan saya menemukan sesuatu dalam dokumentasi Android yang mereka suka menyebutnya "Kontrol Senyawa". (Lihat http://developer.android.com/guide/topics/ui/custom-components.html#compound dan gulir ke bagian "Kontrol Senyawa") Saya ingin membuat komponen seperti itu berdasarkan file XML yang mendefinisikan struktur tampilan.

Dalam dokumentasi itu tertulis:

Perhatikan bahwa seperti halnya dengan suatu Kegiatan, Anda dapat menggunakan pendekatan deklaratif (berbasis XML) untuk membuat komponen yang terkandung, atau Anda dapat membuat sarang secara terprogram dari kode Anda.

Nah, itu kabar baik! Pendekatan berbasis XML persis seperti yang saya inginkan! Tapi itu tidak mengatakan bagaimana melakukannya, kecuali bahwa itu "seperti dengan Aktivitas" ... Tapi apa yang saya lakukan dalam suatu Aktivitas adalah panggilan setContentView(...)untuk mengembang pandangan dari XML. Metode itu tidak tersedia jika Anda misalnya subkelas LinearLayout.

Jadi saya mencoba mengembang XML secara manual seperti ini:

public class MyCompoundComponent extends LinearLayout {

    public MyCompoundComponent(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_layout, this);
    }
}

Ini berfungsi, kecuali fakta bahwa XML yang saya muat telah LinearLayoutmendeklarasikan sebagai elemen root. Ini menghasilkan peningkatan LinearLayoutmenjadi anak MyCompoundComponentyang sudah menjadi LinearLayout!! Jadi sekarang kita memiliki LinearLayout yang berlebihan di antara MyCompoundComponentdan pandangan yang sebenarnya dibutuhkan.

Bisakah seseorang memberi saya cara yang lebih baik untuk mendekati ini, menghindari LinearLayoutinstantiated yang berlebihan ?

Tom van Zummeren
sumber
14
Saya suka pertanyaan yang saya pelajari. Terima kasih.
Jeremy Logan
5
Baru-baru ini saya menulis entri blog tentang ini: blog.jteam.nl/2009/10/08/exploring-the-world-of-android-part-3
Tom van Zummeren

Jawaban:

101

Gunakan tag gabungan sebagai root XML Anda

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Your Layout -->
</merge>

Lihat artikel ini.

bhatt4982
sumber
10
Terima kasih banyak! Itulah tepatnya yang saya cari. Luar biasa bagaimana pertanyaan yang begitu panjang dapat memiliki jawaban yang begitu singkat. Luar biasa!
Tom van Zummeren
Bagaimana dengan menyertakan tata letak gabungan ini dalam lanskap?
Kostadin
2
@Timmmm hahahaha Saya mengajukan pertanyaan ini jauh sebelum editor visual bahkan ada :)
Tom van Zummeren
0

Saya pikir cara Anda seharusnya melakukannya, adalah menggunakan nama kelas Anda sebagai elemen root XML:

<com.example.views.MyView xmlns:....
       android:orientation="vertical" etc.>
    <TextView android:id="@+id/text" ... />
</com.example.views.MyView>

Dan kemudian minta kelas Anda diturunkan dari tata letak mana pun yang ingin Anda gunakan. Perhatikan bahwa jika Anda menggunakan metode ini, Anda tidak menggunakan inflater tata letak di sini.

public class MyView extends LinearLayout
{
    public ConversationListItem(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    public ConversationListItem(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }


    public void setData(String text)
    {
        mTextView.setText(text);
    }

    private TextView mTextView;

    @Override
    protected void onFinishInflate()
    {
        super.onFinishInflate();

        mTextView = (TextView)findViewById(R.id.text);
    }
}

Dan kemudian Anda dapat menggunakan tampilan Anda dalam tata letak XML seperti biasa. Jika Anda ingin membuat tampilan secara terprogram Anda harus mengembang sendiri:

MyView v = (MyView)inflater.inflate(R.layout.my_view, parent, false);

Sayangnya ini tidak memungkinkan Anda melakukannya v = new MyView(context)karena sepertinya tidak ada cara untuk mengatasi masalah tata letak bersarang, jadi ini bukan solusi yang lengkap. Anda bisa menambahkan metode seperti ini MyViewuntuk membuatnya sedikit lebih bagus:

public static MyView create(Context context)
{
    return (MyView)LayoutInflater.fromContext(context).inflate(R.layout.my_view, null, false);
}

Penafian: Saya mungkin berbicara omong kosong lengkap.

Timmmm
sumber
Terima kasih! Saya pikir jawaban ini juga benar :) Tetapi tiga tahun lalu, ketika saya mengajukan pertanyaan ini, "bergabung" juga berhasil!
Tom van Zummeren
8
Dan kemudian seseorang datang dan mencoba untuk menggunakan tampilan kustom Anda di suatu tempat tata letak hanya dengan <com.example.views.MyView />dan Anda setDatadan onFinishInflatepanggilan mulai melemparkan NPEs, dan Anda tidak tahu mengapa.
Christopher Perry
Kuncinya di sini adalah dengan menggunakan tampilan kustom Anda, lalu di konstruktor, mengembang tata letak yang menggunakan tag gabungan sebagai root. Sekarang Anda dapat menggunakannya dalam XML, atau hanya dengan memperbaruinya. Semua pangkalan dicakup, yang persis apa yang dilakukan pertanyaan / jawaban yang diterima bersama. Apa yang tidak bisa Anda lakukan adalah merujuk pada tata letak secara langsung lagi. Sekarang 'dimiliki' oleh kontrol kustom dan hanya boleh digunakan oleh itu di konstruktor. Tetapi jika Anda menggunakan pendekatan ini, mengapa Anda harus menggunakannya di tempat lain? Kamu tidak akan
Mark A. Donohoe