Почему так сложно установить стиль из кода в 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> 

Это работает, и это, по моему мнению, способ установить стиль в режиме просмотра с кода на Android. Это кажется слишком сложным. Третий конструктор кнопки Argument мог легко принять идентификатор стиля R.style.XXX

Может ли кто-нибудь объяснить, зачем нужна эта дополнительная сложность?

Solutions Collecting From Web of "Почему так сложно установить стиль из кода в Android?"

Это связано с поощрением шаблонов в Android вокруг использования Views. Это не предполагаемый подход к тому, как он выглядит, как вы пытаетесь сделать. Сначала я объясню, для чего этот механизм, а затем предложим подход для вашего приложения.

Третий аргумент конструктора View, который принимает ресурс attr, обычно используется при реализации подклассов вида и, как вы показали, позволяет указать атрибут темы для использования в качестве ссылки на стиль по умолчанию в представлении. Если у вас была специальная кнопка 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 } 

Когда LayoutInflater Android раздувает представления, он использует конструктор с двумя аргументами с аргументами (Context, AttributeSet) . Константа R.attr передается в 3-аргументную версию, а затем до 3-аргументного конструктора Button супервызове. Это означает, что Button будет считывать информацию о стилизации по умолчанию для вещей, которые она инкапсулирует из AwesomeButton умолчанию AwesomeButton как указано в вашей теме. Некоторые представления в Android отличаются от их суперкласса только в стиле по умолчанию, который они используют. ( Button на самом деле одна из них.)

Вы указываете android:layout_width и android: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); 

Рез / макет / styled_button.xml:

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