Android - Özel (bileşik) bileşen yazma


132

Şu anda geliştirmekte olduğum Android uygulamasının oldukça büyüyen bir ana etkinliği var. Bunun başlıca nedeni TabWidget, 3 sekmeli bir içermesidir . Her sekmenin epeyce bileşeni vardır. Aktivite, tüm bu bileşenleri aynı anda kontrol etmelidir. Bu yüzden bu Faaliyetin 20 alana (neredeyse her bileşen için bir alan) sahip olduğunu hayal edebileceğinizi düşünüyorum. Ayrıca birçok mantık içerir (tıklama dinleyicileri, listeleri doldurma mantığı, vb.).

Normalde bileşen tabanlı çerçevelerde yaptığım şey, her şeyi özel bileşenlere ayırmaktır. Her özel bileşen daha sonra açık bir sorumluluğa sahip olacaktır. Kendi bileşenlerini ve bu bileşenle ilgili diğer tüm mantığı içerir.

Bunun nasıl yapılabileceğini anlamaya çalıştım ve Android belgelerinde "Bileşik Kontrol" olarak adlandırmak istedikleri bir şey buldum. (Bkz. Http://developer.android.com/guide/topics/ui/custom-components.html#compound ve kaydırarak "Bileşik Kontroller" bölümüne gidin) yapıyı görüntüle.

Belgelerde şöyle diyor:

Bir Activity'de olduğu gibi, içerilen bileşenleri oluşturmak için bildirim temelli (XML tabanlı) yaklaşımı kullanabileceğinizi veya bunları kodunuzdan programlı olarak iç içe yerleştirebileceğinizi unutmayın.

Bu iyi haber! XML tabanlı yaklaşım tam olarak istediğim şey! Ama "bir Aktivite ile olduğu gibi" dışında bunun nasıl yapılacağını söylemiyor ... Ama bir Aktivitede yaptığım şey setContentView(...), görünümleri XML'den şişirme çağrısı . Örneğin alt sınıfınız varsa bu yöntem kullanılamaz LinearLayout.

Bu yüzden XML'i manuel olarak şu şekilde şişirmeye çalıştım:

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);
    }
}

Bu, yüklediğim XML'nin LinearLayoutkök öğe olarak bildirilmesi dışında çalışır . Bu, şişkinliğin kendisi zaten LinearLayoutbir çocuk olan bir çocuk olmasıyla sonuçlanır !! Öyleyse şimdi arasına fazladan bir Doğrusal Yerleşim ve gerçekten ihtiyaç duyduğu görünümler var.MyCompoundComponentLinearLayoutMyCompoundComponent

Biri bana fazladan bir LinearLayoutörneğe sahip olmaktan kaçınarak buna yaklaşmanın daha iyi bir yolunu sağlayabilir mi?


14
Bir şeyler öğrendiğim soruları seviyorum. Teşekkürler.
Jeremy Logan

5
Yakın zamanda bununla
Tom van Zummeren

Yanıtlar:


101

XML kökünüz olarak birleştirme etiketini kullanın

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

Bu makaleye göz atın.


10
Çok teşekkür ederim! Tam olarak aradığım buydu. Bu kadar uzun bir sorunun bu kadar kısa bir cevabı olabilmesi şaşırtıcı. Mükemmel!
Tom van Zummeren

Bu birleştirme düzenini yatayda dahil etmeye ne dersiniz?
Kostadin

2
@Timmmm hahahaha Bu soruyu görsel editör daha var olmadan çok önce sordum :)
Tom van Zummeren

0

Bence bunu yapmanız gereken yol, sınıf adınızı XML kök öğesi olarak kullanmak:

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

Ve sonra sınıfınızı kullanmak istediğiniz düzenden türetin. Bu yöntemi kullanarak eğer o Not yok burada düzen Inflater kullanın.

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);
    }
}

Ve sonra görünümünüzü XML düzenlerinde normal şekilde kullanabilirsiniz. Görünümü programlı yapmak istiyorsanız, kendiniz şişirmeniz gerekir:

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

Maalesef bu, bunu yapmanıza izin vermiyor v = new MyView(context)çünkü iç içe geçmiş düzen sorununun etrafında bir yol yok gibi görünüyor, bu yüzden bu gerçekten tam bir çözüm değil. Bunu MyViewbiraz daha güzel hale getirmek için buna benzer bir yöntem ekleyebilirsiniz :

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

Sorumluluk reddi: Tam saçmalıklardan bahsediyor olabilirim.


Teşekkürler! Bu cevabın da doğru olduğunu düşünüyorum :) Ama üç yıl önce bu soruyu sorduğumda "birleştirme" de hile yaptı!
Tom van Zummeren

8
Ve sonra biri gelir ve özel görünümünüzü bir yerde sadece bir yerde bir düzende kullanmaya çalışır <com.example.views.MyView />ve sizin setDatave onFinishInflatearamalarınız NPE'leri atmaya başlar ve nedenini bilmiyorsunuz.
Christopher Perry

Buradaki hile, özel görünümünüzü kullanmak, ardından yapıcıda, kök olarak bir birleştirme etiketi kullanan bir düzeni şişirmektir. Şimdi bunu XML olarak veya sadece yenileyerek kullanabilirsiniz. Tüm temeller kapsanmıştır, bu da soru / kabul edilen yanıtın birlikte yaptığı şeydir. Ancak yapamayacağınız şey, artık düzene doğrudan başvurmaktır. Artık özel denetime aittir ve yalnızca kurucuda kullanılmalıdır. Ancak bu yaklaşımı kullanıyorsanız, neden başka bir yerde kullanmanız gerekecek? Yapmazsın.
Mark A. Donohoe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.