Como definir programaticamente o atributo de estilo em uma visualização

107

Estou obtendo uma visão do XML com o código abaixo:

Button view = (Button) LayoutInflater.from(this).inflate(R.layout.section_button, null);

Gostaria de definir um "estilo" para o botão, como posso fazer isso em java desde que deseje usar vários estilos para cada botão que irei usar.

Lint_
fonte

Respostas:

52

Geralmente, você não pode alterar estilos de forma programática; você pode definir a aparência de uma tela, ou parte de um layout, ou botão individual em seu layout XML usando temas ou estilos . Os temas podem, no entanto, ser aplicados de forma programática .

Também existe um StateListDrawableque permite definir drawables diferentes para cada estado em que você Buttonpode estar, seja ele focado, selecionado, pressionado, desabilitado e assim por diante.

Por exemplo, para fazer com que seu botão mude de cor quando for pressionado, você pode definir um arquivo XML chamado res/drawable/my_button.xmldiretório como este:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item
    android:state_pressed="true"
    android:drawable="@drawable/btn_pressed" />
  <item
    android:state_pressed="false"
    android:drawable="@drawable/btn_normal" />
</selector>

Você pode então aplicar esse seletor a um Buttondefinindo a propriedade android:background="@drawable/my_button".

Christopher Orr
fonte
4
Meu problema é que carrego dados de um serviço da web que descreve as informações do meu botão. Os botões precisam ter estilos diferentes com base na categoria a que pertencem. É por isso que gostaria de definir o estilo de forma dinâmica.
Lint_
3
Bem, você não pode alterar o styleatributo Android , mas pode definir programaticamente o plano de fundo de um Buttoncomo faria com qualquer outra visualização, se isso for suficiente. Além disso, como Buttonherda de TextView, você pode alterar as propriedades do texto. Basta olhar a documentação da API para esses itens ... developer.android.com/reference/android/view/…
Christopher Orr
Eu estava pensando em fazer isso, antes de verificar se tinha novas respostas. Muito obrigado.
Lint_
5
Não é possível criar um estilo para um botão que defina o tamanho do texto, as margens, etc etc, e então aplicar isso a um botão de forma programática. Certamente é possível dizer se eu tenho seis botões que desejam ter o mesmo estilo?
Bear
qual atributo podemos aumentar? podemos aumentar as margens, preenchimento?
Android Man
49

Em primeiro lugar, você não precisa usar um inflador de layout para criar um botão simples. Você pode apenas usar:

button = new Button(context);

Se quiser estilizar o botão, você tem 2 opções: a mais simples é apenas especificar todos os elementos no código, como muitas das outras respostas sugerem:

button.setTextColor(Color.RED);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);

A outra opção é definir o estilo em XML e aplicá-lo ao botão. No caso geral, você pode usar um ContextThemeWrapperpara isso:

ContextThemeWrapper newContext = new ContextThemeWrapper(baseContext, R.style.MyStyle);
button = new Button(newContext);

Para alterar os atributos relacionados ao texto em um TextView (ou suas subclasses como Button), existe um método especial:

button.setTextAppearance(context, R.style.MyTextStyle);

Este último não pode ser usado para alterar todos os atributos; por exemplo, para alterar o preenchimento, você precisa usar a ContextThemeWrapper. Mas para cor de texto, tamanho, etc. você pode usar setTextAppearance.

Beetstra
fonte
1
Simplesmente brilhante. ContextThemeWrapper - é o que eu procurava há muito tempo.
Ayaz Alifov
Isso funciona fantasticamente. Há algum tempo que procuro esta solução.
jasonjwwilliams de
14

Sim, você pode usar, por exemplo, em um botão

Button b = new Button(this);
b.setBackgroundResource(R.drawable.selector_test);
Dayerman
fonte
5
Isso definirá o plano de fundo, mas um estilo pode especificar mais do que apenas um plano de fundo. Muitas visualizações (incluindo o botão) parecem ter um construtor que recebe um ID de estilo como parâmetro. No entanto, estou tendo problemas para fazer isso funcionar para mim - o botão aparece como um texto sem borda nem nada. O que posso fazer em vez disso é criar um layout com apenas um botão (com um estilo especificado), aumentar o layout e definir o texto do botão e outros enfeites.
spaaarky21
11

Você pode criar atributos de estilo como:

Button myButton = new Button(this, null,android.R.attr.buttonBarButtonStyle);

no lugar de:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn"
    style="?android:attr/buttonBarButtonStyle"

    />
Kristy Welsh
fonte
7
Boa resposta considerando que um botão deve ser criado. Seria bom ver como fazer isso para um botão existente.
Quality Catalyst
Veja a resposta de cesards.
Kristy Welsh
10

Se você estiver usando a Biblioteca de suporte, você pode simplesmente usar

TextViewCompat.setTextAppearance(textView, R.style.AppTheme_TextStyle_ButtonDefault_Whatever);

para TextViews e botões. Existem classes semelhantes para o resto das Visualizações :-)

cesards
fonte
qual pacote R você precisa usar para obter este estilo?
htafoya
6

Para quem procura uma resposta material, consulte esta postagem do SO: Botões para colorir no Android com Material Design e AppCompat

Usei uma combinação desta resposta para definir a cor do texto padrão do botão como branco para meu botão: https://stackoverflow.com/a/32238489/3075340

Então esta resposta https://stackoverflow.com/a/34355919/3075340 para definir programaticamente a cor de fundo. O código para isso é:

ViewCompat.setBackgroundTintList(your_colored_button,
 ContextCompat.getColorStateList(getContext(),R.color.your_custom_color));

your_colored_button pode ser apenas um normal Button botão ou AppCompat, se desejar - testei o código acima com os dois tipos de botão e funciona.

EDIT: descobri que os dispositivos pré-pirulito não funcionam com o código acima. Veja esta postagem sobre como adicionar suporte para dispositivos pré-lollipop: https://stackoverflow.com/a/30277424/3075340

Basicamente, faça isso:

Button b = (Button) findViewById(R.id.button);
ColorStateList c = ContextCompat.getColorStateList(mContext, R.color.your_custom_color;
Drawable d = b.getBackground();
if (b instanceof AppCompatButton) {
    // appcompat button replaces tint of its drawable background
    ((AppCompatButton)b).setSupportBackgroundTintList(c);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Lollipop button replaces tint of its drawable background
    // however it is not equal to d.setTintList(c)
    b.setBackgroundTintList(c);
} else {
    // this should only happen if 
    // * manually creating a Button instead of AppCompatButton
    // * LayoutInflater did not translate a Button to AppCompatButton
    d = DrawableCompat.wrap(d);
    DrawableCompat.setTintList(d, c);
    b.setBackgroundDrawable(d);
}
Micro
fonte
6

Dependendo de quais atributos de estilo você gostaria de alterar, você pode usar a biblioteca de Paris:

Button view = (Button) LayoutInflater.from(this).inflate(R.layout.section_button, null);
Paris.style(view).apply(R.style.YourStyle);

Muitos atributos como background, padding, textSize, textColor, etc. são suportados.

Isenção de responsabilidade: eu sou o autor da biblioteca.

Natanael
fonte
5

A resposta de @Dayerman e @h_rules está certa. Para dar um exemplo elaborado com código, na pasta drawable, crie um arquivo xml chamado button_disabled.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" android:padding="10dp">   
 <solid android:color="@color/silver"/>
<corners
   android:bottomRightRadius="20dp"
   android:bottomLeftRadius="20dp"
   android:topLeftRadius="20dp"
   android:topRightRadius="20dp"/>
</shape>

Então, em Java,

((Button) findViewById(R.id.my_button)).setEnabled(false);
((Button) findViewById(R.id.my_button)).setBackgroundResource(R.drawable.button_disabled);

Isso definirá a propriedade do botão como desativada e definirá a cor como prata.

[A cor é definida em color.xml como:

<resources>

    <color name="silver">#C0C0C0</color>

</resources>
biniam
fonte
4
@Pacerier: a pergunta não diz nada disso. É ambíguo se o estilo é XML ou em java. Ele apenas pergunta como definir o estilo de forma programática.
Harvey
3

Em tempo de execução, você sabe qual estilo deseja que seu botão tenha. Portanto, de antemão, em xml na pasta de layout, você pode ter todos os botões prontos para usar com os estilos que você precisa. Portanto, na pasta de layout, você pode ter um arquivo chamado: button_style_1.xml. O conteúdo desse arquivo pode ser semelhante a:

<?xml version="1.0" encoding="utf-8"?>
<Button
    android:id="@+id/styleOneButton"
    style="@style/FirstStyle" />

Se você estiver trabalhando com fragmentos, em onCreateView você infla esse botão, como:

Button firstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);

onde container é o container ViewGroup associado ao método onCreateView que você substitui ao criar seu fragmento.

Precisa de mais dois desses botões? Você os cria assim:

Button secondFirstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);
Button thirdFirstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);

Você pode personalizar esses botões:

secondFirstStyleBtn.setText("My Second");
thirdFirstStyleBtn.setText("My Third");

Em seguida, você adiciona seus botões estilizados e personalizados ao contêiner de layout que também aumentou no método onCreateView:

_stylizedButtonsContainer = (LinearLayout) rootView.findViewById(R.id.stylizedButtonsContainer);

_stylizedButtonsContainer.addView(firstStyleBtn);
_stylizedButtonsContainer.addView(secondFirstStyleBtn);
_stylizedButtonsContainer.addView(thirdFirstStyleBtn);

E é assim que você pode trabalhar dinamicamente com botões estilizados.

Jerry Frost
fonte
0

Fiz uma interface auxiliar para isso usando o padrão de suporte.

public interface StyleHolder<V extends View> {
    void applyStyle(V view);
}

Agora, para cada estilo que você deseja usar pragmaticamente, apenas implemente a interface, por exemplo:

public class ButtonStyleHolder implements StyleHolder<Button> {

    private final Drawable background;
    private final ColorStateList textColor;
    private final int textSize;

    public ButtonStyleHolder(Context context) {
        TypedArray ta = context.obtainStyledAttributes(R.style.button, R.styleable.ButtonStyleHolder);

        Resources resources = context.getResources();

        background = ta.getDrawable(ta.getIndex(R.styleable.ButtonStyleHolder_android_background));

        textColor = ta.getColorStateList(ta.getIndex(R.styleable.ButtonStyleHolder_android_textColor));

        textSize = ta.getDimensionPixelSize(
                ta.getIndex(R.styleable.ButtonStyleHolder_android_textSize),
                resources.getDimensionPixelSize(R.dimen.standard_text_size)
        );

        // Don't forget to recycle!
        ta.recycle();
    }

    @Override
    public void applyStyle(Button btn) {
        btn.setBackground(background);
        btn.setTextColor(textColor);
        btn.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
    }
}

Declare um estilizável em seu attrs.xml, o estilizável para este exemplo é:

<declare-styleable name="ButtonStyleHolder">
    <attr name="android:background" />
    <attr name="android:textSize" />
    <attr name="android:textColor" />
</declare-styleable>

Aqui está o estilo declarado em styles.xml:

<style name="button">
    <item name="android:background">@drawable/button</item>
    <item name="android:textColor">@color/light_text_color</item>
    <item name="android:textSize">@dimen/standard_text_size</item>
</style>

E, finalmente, a implementação do suporte de estilo:

Button btn = new Button(context);    
StyleHolder<Button> styleHolder = new ButtonStyleHolder(context);
styleHolder.applyStyle(btn);

Achei isso muito útil, pois pode ser facilmente reutilizado e mantém o código limpo e detalhado, eu recomendaria usar isso apenas como uma variável local para que possamos permitir que o coletor de lixo faça seu trabalho assim que terminarmos de definir todos os estilos .

Kostyantin2216
fonte
-1

Eu enfrentei o mesmo problema recentemente. aqui está como eu resolvi isso.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <!-- This is the special two colors background START , after this LinearLayout, you can add all view that have it for main background-->
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:weightSum="2"

    android:background="#FFFFFF"
    android:orientation="horizontal"
    >

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#0000FF" />

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#F000F0" />
    </LinearLayout>
    <!-- This is the special two colors background END-->

   <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:text="This Text is centered with a special backgound,
    You can add as much elements as you want as child of this RelativeLayout"
    android:textColor="#FFFFFF"
    android:textSize="20sp" />
</RelativeLayout>
  • Usei um LinearLayout com android: weightSum = "2"
  • Dei aos dois elementos filhos android: layout_weight = "1" (dei a cada um 50% do espaço pai (largura e altura))
  • E, finalmente, dei aos dois elementos filho diferentes cores de fundo para obter o efeito final.

Obrigado !

dev242
fonte