ti-enxame.com

Por que é tão complexo definir o estilo do código em Android

Se você deseja definir o estilo de um botão criado a partir do código, deve fazer algo assim;

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

em attrs.xml, você configura uma referência

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

Em styles.xml, você define um tema

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

Isso se aplica em styles.xml é definido como por exemplo

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

Isso funciona, e é, de acordo com meu entendimento, a maneira de definir um estilo em um código do modo de exibição no Android. Isso parece excessivamente complexo. O terceiro construtor do botão Argument poderia facilmente aceitar um ID de estilo R.style.XXX

Alguém pode explicar por que essa complexidade extra é necessária?

35
Glenn Bech

Tem a ver com os padrões incentivados dentro do Android em torno do uso do Views. Esta não é a abordagem pretendida para o que parece que você está tentando fazer. Primeiro, explicarei o que esse mecanismo é para e, em seguida, sugira uma abordagem para o seu aplicativo.

O terceiro argumento para os construtores View que usam um recurso attr é geralmente usado ao implementar subclasses View e, como você mostrou, permite especificar um atributo de tema para ser usado como referência ao estilo padrão da View. Se você tivesse um tipo especial de botão chamado AwesomeButton, poderá implementar seus construtores como este:

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
}

Quando LayoutInflater do Android infla visualizações, ele usa o construtor de 2 argumentos com os argumentos (Context, AttributeSet). A constante R.attr é passada para a versão de 3 argumentos e depois para o construtor de 3 argumentos de Button na chamada super. Isso significa que Button lerá as informações de estilo padrão para as coisas que ele encapsula do estilo padrão de AwesomeButton, conforme especificado no seu tema. Algumas visualizações dentro de Android diferem de suas superclasses apenas no estilo padrão que elas usam. (Button é realmente uma delas.)

Você especifica Android:layout_width e Android:layout_height no seu estilo, mas isso pode ser problemático. LayoutParams (qualquer atributo que comece com layout_) são específicos para a exibição principal, não a exibição em que aparecem. É por isso que você sempre passa a visualização pai pretendida como o segundo parâmetro para LayoutInflater#inflate - informa ao inflator qual classe deve ser responsável por interpretar o LayoutParams. Se você pular isso, muitas vezes descobrirá que seus LayoutParams não se comportam conforme o esperado e são frequentemente ignorados. Por convenção, não colocamos LayoutParams em estilos, embora em alguns casos especiais isso funcione.

Parece que você está tentando usar um estilo como uma espécie de modelo. Existe um motivo para não usar um recurso de layout para isso e especificar o estilo lá?

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"
        [...] />
65
adamp