2011-12-03 32 views
34

如果您想要設置從代碼創建的Button的樣式,您必須執行如下操作;爲什麼如此複雜的從Android中的代碼設置樣式

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

在attrs.xml,你建立一個參考

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

在styles.xml中,可以定義一個主題

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

在styles.xml鱸被定義爲示例

<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> 

This works,根據我的理解,這是在Android中通過代碼在View上設置樣式的方式。這似乎過於複雜。按鈕的第三個構造函數參數很容易接受樣式ID R.style.XXX

任何人都可以解釋爲什麼需要這種額外的複雜性嗎?

+1

感謝解釋它是如何工作在Android的系統資源,它幫助我回答我的問題(http://stackoverflow.com/questions/11023335/how-to-set-android-button-background -color/11024343#11024343) – Qwertie

回答

64

它與Android中圍繞使用視圖的鼓勵模式有關。這不是你想要做的事情的預期方法。首先我會解釋這個機制是什麼,然後爲你的應用程序提供一種方法。

在實現View子類時,通常會使用接受attr資源的View構造函數的第三個參數,如您所示,可以指定一個主題屬性用作View的默認樣式的引用。如果你有一個特殊的按鈕叫AwesomeButton你可能會實現這樣它的構造:

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 
} 

當Android的LayoutInflater膨脹的觀點,它使用的論據(Context, AttributeSet) 2個參數的構造函數。 R.attr常量被傳遞給3參數版本,然後在調用super時調用Button的3參數構造函數。這意味着Button將會讀取默認樣式信息,以便從主題中指定的AwesomeButton的默認樣式中封裝它。 Android中的某些視圖與其超類的區別僅在於它們使用的默認樣式。 (Button實際上就是其中之一。)

您以您的風格指定android:layout_widthandroid:layout_height,但這可能會有問題。 LayoutParams(以layout_開頭的任何屬性)都是父視圖所特有的,而不是它們出現的視圖。這就是爲什麼你總是將想要的父視圖作爲第二個參數傳遞給LayoutInflater#inflate--它告訴填充者哪個類應該負責解釋LayoutParams。如果你跳過這個,你會經常發現你的LayoutParams不像你期望的那樣行事,並且經常被忽視。按照慣例,我們不會將LayoutParams置於樣式中,即使在某些特殊情況下它也可以工作。

它看起來像你試圖使用一種風格作爲一種模板。是否有理由不使用佈局資源來指定樣式?

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

這是一個很好的答案,現在我的代碼更簡單了。我並不是真的需要「一路走」並創造一個新的主題。我結束了我的android:layout_height =「@ dimen/actionbar_compat_height」。另一種選擇可能是爲layout-xlarge等創建不同的styled_button.xml。感謝您抽出時間。我現在明白了。 –

+0

太棒了,很高興它幫助你清理了一些東西。 – adamp

+0

哇。我很喜歡這個答案,所以我upvoted這個和另一個來自同一個用戶:-) – SJuan76

相關問題