Główna działalność aplikacji na Androida, którą obecnie tworzę, jest dość duża. Dzieje się tak głównie dlatego, że zawiera TabWidget
3 zakładki. Każda zakładka ma sporo elementów. Aktywność musi kontrolować wszystkie te komponenty jednocześnie. Myślę więc, że możesz sobie wyobrazić, że to działanie ma około 20 pól (pole dla prawie każdego komponentu). Zawiera również dużo logiki (słuchacze kliknięć, logika wypełniania list itp.).
To, co zwykle robię w frameworkach opartych na komponentach, to dzielenie wszystkiego na niestandardowe komponenty. Każdy komponent niestandardowy miałby wtedy wyraźną odpowiedzialność. Zawierałby własny zestaw komponentów i całą inną logikę związaną z tym komponentem.
Próbowałem wymyślić, jak można to zrobić, i znalazłem w dokumentacji Androida coś, co nazywają „Kontrolą złożoną”. (Zobacz http://developer.android.com/guide/topics/ui/custom-components.html#compound i przewiń do sekcji „Compound Controls”). Chciałbym utworzyć taki komponent na podstawie pliku XML definiującego zobacz strukturę.
W dokumentacji jest napisane:
Należy zauważyć, że podobnie jak w przypadku działania, można użyć podejścia deklaratywnego (opartego na języku XML) do tworzenia zawartych składników lub zagnieżdżać je programowo na podstawie kodu.
Cóż, to dobra wiadomość! Podejście oparte na XML jest dokładnie tym, czego chcę! Ale nie mówi, jak to zrobić, z wyjątkiem tego, że jest to „jak w przypadku działania” ... Ale to, co robię w działaniu, to wywołanie setContentView(...)
zawyżenia widoków z XML. Ta metoda nie jest dostępna, jeśli na przykład masz podklasę LinearLayout
.
Więc próbowałem ręcznie zawyżyć XML w ten sposób:
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);
}
}
To działa, z wyjątkiem faktu, że ładowany plik XML został LinearLayout
zadeklarowany jako element główny. Skutkuje to nadymaniem LinearLayout
bycia dzieckiem, MyCompoundComponent
którego już jest LinearLayout
!! Więc teraz mamy zbędny LinearLayout pomiędzy MyCompoundComponent
i widoki, których faktycznie potrzebuje.
Czy ktoś może mi zapewnić lepszy sposób rozwiązania tego problemu, unikając LinearLayout
tworzenia zbędnej instancji?
źródło
Odpowiedzi:
Użyj tagu scalającego jako katalogu głównego XML
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Your Layout --> </merge>
Sprawdź ten artykuł.
źródło
Myślę, że sposób, w jaki powinieneś to zrobić, polega na użyciu nazwy klasy jako elementu głównego XML:
<com.example.views.MyView xmlns:.... android:orientation="vertical" etc.> <TextView android:id="@+id/text" ... /> </com.example.views.MyView>
A potem niech twoja klasa zostanie wyprowadzona z dowolnego układu, którego chcesz użyć. Zauważ, że jeśli używasz tej metody, nie używasz tutaj inflatora układu.
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); } }
Następnie możesz normalnie używać swojego widoku w układach XML. Jeśli chcesz zrobić widok programowo, musisz sam go zawyżyć:
MyView v = (MyView)inflater.inflate(R.layout.my_view, parent, false);
Niestety nie pozwala ci to zrobić,
v = new MyView(context)
ponieważ wydaje się, że nie ma sposobu na obejście problemu zagnieżdżonych układów, więc nie jest to tak naprawdę pełne rozwiązanie. Możesz dodać taką metodę,MyView
aby była trochę ładniejsza:public static MyView create(Context context) { return (MyView)LayoutInflater.fromContext(context).inflate(R.layout.my_view, null, false); }
Zastrzeżenie: może mówię kompletne bzdury.
źródło
<com.example.views.MyView />
a twojesetData
ionFinishInflate
wywołania zaczynają rzucać NPE, a nie masz pojęcia, dlaczego.