2011-12-03 10 views
34

Jeśli chcesz ustawić styl przycisku, który tworzysz z kodu, musisz zrobić coś takiego;Dlaczego tak złożony styl z kodu w Androidzie

Button btn = new Button (mActivity, null, R.attr.someattribute); 

w attrs.xml, skonfigurowaniu odniesienie

<attr name="someStyleRef" format="reference"/> 

W styles.xml definiuje motyw

<resources> 
    <style name="Theme.SomeTheme" parent="android:style/Theme.Black"> 
    <item name="someStyleRef">@style/someStyle</item> 
    </style> 
</resources> 

To Lates w styles.xml jest zdefiniowany jak dla przykład

<style name="someStyle"> 
     <item name="android:layout_width">2px</item> 
     <item name="android:layout_height">fill_parent</item> 
     <item name="android:background">@drawable/actionbar_compat_separator</item> 
</style> 

To działa, zgodnie z moim rozumowaniem jest to sposób na ustawienie stylu w widoku z kodu w systemie Android. Wydaje się to zbyt skomplikowane. Trzeci konstruktor przycisku, Argument, mógłby z łatwością zaakceptować identyfikator stylu R.style.XXX

Czy ktoś może wyjaśnić, dlaczego ta dodatkowa złożoność jest potrzebna?

+1

Dzięki za wyjaśnienia, jak to działa w zasobów systemu Android, to pomogło mi odpowiedzieć na moje własne pytanie (http://stackoverflow.com/questions/11023335/how-to-set-android-button-background -color/11024343 # 11024343) – Qwertie

Odpowiedz

64

Ma to związek z zachęcającymi wzorcami w systemie Android, korzystając z widoków. To nie jest zamierzone podejście do tego, jak wygląda próbowanie. Najpierw wyjaśnię, do czego służy ten mechanizm, a następnie zasugeruję podejście do Twojej aplikacji.

Trzeci argument View constructors, który pobiera zasób attr, jest zwykle używany podczas implementacji podklas View i jak już pokazano, pozwala określić atrybut kompozycji, który będzie używany jako odniesienie do domyślnego stylu widoku. Jeśli miał szczególny rodzaj przycisku o nazwie AwesomeButton Was może realizować swoje konstruktorów tak:

public class AwesomeButton extends Button { 
    public AwesomeButton(Context context) { 
     this(context, null); 
    } 

    public AwesomeButton(Context context, AttributeSet attrs) { 
     this(context, attrs, R.attr.awesomeButtonStyle); 
    } 

    public AwesomeButton(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr) { 
     final TypedArray a = context.obtainStyledAttributes(attrs, 
       R.styleable.AwesomeButton, defStyleAttr, 0); 
     // Read AwesomeButton-specific style attributes from a 
     a.recycle(); 
    } 

    // More code 
} 

Kiedy Android LayoutInflater nadmuchuje widoki używa konstruktora 2-argument z argumentów (Context, AttributeSet). Stała R.attr jest przekazywana do wersji 3-argumentowej, a następnie do konstruktora 3-argumentowego Button w wywołaniu super. Oznacza to, że Button odczyta domyślne informacje o stylach dla elementów zawartych w domyślnym stylu AwesomeButton, jak określono w kompozycji. Niektóre widoki w systemie Android różnią się od swojej nadklasy tylko stylem domyślnym, którego używają. (Button jest w rzeczywistości jednym z nich.)

W swoim stylu określasz android:layout_width i android:layout_height, ale może to być problematyczne. LayoutParams (dowolny atrybut rozpoczynający się od layout_) są charakterystyczne dla widoku nadrzędnego, a nie dla widoku, w którym się pojawiają. Dlatego zawsze przekazujesz planowany widok macierzysty jako drugi parametr do LayoutInflater#inflate - informuje on nadawcę, która klasa powinna być odpowiedzialna za interpretację LayoutParams. Jeśli pominiesz to, często okaże się, że Twój LayoutParams nie zachowuje się tak, jak się spodziewasz i często jest ignorowany. Zgodnie z konwencją nie umieszczamy stylów LayoutParams w stylach, chociaż w niektórych szczególnych przypadkach jest to rodzaj pracy.

Wygląda na to, że próbujesz użyć stylu jako szablonu. Czy istnieje powód, aby nie używać do tego zasobu układu i określić styl?

final LayoutInflater inflater = LayoutInflater.from(mActivity); 
Button btn = (Button) inflater.inflate(R.layout.styled_button, parentView, false); 

res/layout/styled_button.XML:

<Button android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="@drawable/my_button_background" 
     [...] /> 
+0

To jest bardzo dobra odpowiedź, a mój kod jest teraz znacznie prostszy. Tak naprawdę nie musiałem iść "na całość" i stworzyć nowy motyw. Skończyło się na zachowaniu mojego androida: layout_height = "@ dimen/actionbar_compat_height". Inną opcją mogłoby być stworzenie różnych styled_button.xml dla layout-xlarge itp. Dzięki za poświęcenie czasu. Teraz rozumiem. –

+0

Wspaniale, cieszę się, że pomogło ci to wyjaśnić. – adamp

+0

Wow. Ta odpowiedź podobała mi się tak bardzo, że przegłosowałem tę i inną od tego samego użytkownika :-) – SJuan76