Cómo establecer mediante programación el atributo de estilo en una vista

107

Obtengo una vista del XML con el siguiente código:

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

Me gustaría establecer un "estilo" para el botón, ¿cómo puedo hacer eso en Java? Ya que quiero usar varios estilos para cada botón que usaré.

Hilas_
fuente

Respuestas:

52

Generalmente, no se pueden cambiar los estilos mediante programación; puede establecer el aspecto de una pantalla, o parte de un diseño, o un botón individual en su diseño XML utilizando temas o estilos . Sin embargo, los temas se pueden aplicar mediante programación .

También existe un elemento StateListDrawableque le permite definir diferentes elementos de diseño para cada estado en el que Buttonpuede estar, ya sea enfocado, seleccionado, presionado, deshabilitado, etc.

Por ejemplo, para que su botón cambie de color cuando se presiona, puede definir un archivo XML llamado res/drawable/my_button.xmldirectorio 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>

A continuación, puede aplicar este selector a un Buttonestableciendo la propiedad android:background="@drawable/my_button".

Christopher Orr
fuente
4
Mi problema es que cargo datos de un servicio web que describen la información de mi botón. Los botones deben tener un estilo diferente según la categoría a la que pertenecen. Por eso me gustaría establecer el estilo de forma dinámica.
Lint_
3
Bueno, no puede cambiar el styleatributo de Android , pero puede establecer programáticamente el fondo de un Buttonme gusta con cualquier otra vista, si eso es suficiente. Además, como Buttonherencia de TextView, puede cambiar las propiedades del texto. Solo mire la documentación de la API para estos elementos ... developer.android.com/reference/android/view/…
Christopher Orr
Estaba pensando en hacer eso, justo antes de comprobar si tenía nuevas respuestas. Muchas gracias.
Lint_
5
¿No es posible crear un estilo para un botón que defina el tamaño del texto, los márgenes, etc., y luego aplicarlo a un botón mediante programación? Seguramente es posible decir si tengo seis botones que quieren tener el mismo estilo.
Bear
¿Qué atributo podemos inflar? ¿Podemos inflar márgenes, relleno?
Android Man
49

En primer lugar, no es necesario utilizar un inflador de diseño para crear un botón simple. Puedes usar:

button = new Button(context);

Si desea diseñar el botón, tiene 2 opciones: la más simple es especificar todos los elementos en el código, como sugieren muchas de las otras respuestas:

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

La otra opción es definir el estilo en XML y aplicarlo al botón. En el caso general, puede utilizar a ContextThemeWrapperpara esto:

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

Para cambiar los atributos relacionados con el texto en un TextView (o sus subclases como Button) hay un método especial:

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

Este último no se puede utilizar para cambiar todos los atributos; por ejemplo, para cambiar el acolchado necesita utilizar un ContextThemeWrapper. Pero para el color, tamaño, etc. del texto, puede usar setTextAppearance.

beetstra
fuente
1
Sólo brillante. ContextThemeWrapper: es lo que estaba buscando durante tanto tiempo.
Ayaz Alifov
Esto funciona fantásticamente. He estado buscando esta solución por un tiempo.
jasonjwwilliams
14

Sí, puede usar por ejemplo en un botón

Button b = new Button(this);
b.setBackgroundResource(R.drawable.selector_test);
Dayerman
fuente
5
Eso establecerá el fondo, pero un estilo puede especificar más que solo un fondo. Muchas vistas (incluido el botón) parecen tener un constructor que toma un ID de estilo como parámetro. Sin embargo, tengo problemas para hacer que eso funcione para mí: el botón aparece como texto sin borde ni nada. Lo que podría hacer en su lugar es crear un diseño con solo un botón (con un estilo especificado), inflar ese diseño, luego configurar el texto del botón y todo eso.
spaaarky21
11

Puedes hacer atributos de estilo así:

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

en lugar de:

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

    />
Kristy galés
fuente
7
Se creará una buena respuesta considerando un botón. Sería bueno ver cómo hacer eso para un botón existente.
Quality Catalyst
Vea la respuesta de cesards.
Kristy Welsh
10

Si está utilizando la biblioteca de soporte, simplemente puede usar

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

para TextViews y Buttons. Hay clases similares para el resto de Vistas :-)

cesar
fuente
¿Qué paquete de R necesitas usar para obtener este estilo?
htafoya
6

Para cualquiera que busque una respuesta material, vea esta publicación SO: Botones para colorear en Android con Material Design y AppCompat

Usé una combinación de esta respuesta para establecer el color de texto predeterminado del botón en blanco para mi botón: https://stackoverflow.com/a/32238489/3075340

Entonces esta respuesta https://stackoverflow.com/a/34355919/3075340 para configurar programáticamente el color de fondo. El código para eso es:

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

your_colored_button puede ser solo un regular Button botón o de AppCompat si lo desea; probé el código anterior con ambos tipos de botones y funciona.

EDITAR: Descubrí que los dispositivos anteriores a la piruleta no funcionan con el código anterior. Vea esta publicación sobre cómo agregar soporte para dispositivos pre-lollipop: https://stackoverflow.com/a/30277424/3075340

Básicamente haz esto:

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

Dependiendo de los atributos de estilo que desee cambiar, es posible que pueda utilizar la biblioteca de París:

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

Se admiten muchos atributos como background, padding, textSize, textColor, etc.

Descargo de responsabilidad: soy el autor de la biblioteca.

Natanael
fuente
5

La respuesta de @Dayerman y @h_rules es correcta. Para dar un ejemplo elaborado con código, en la carpeta dibujable, cree un archivo xml llamado 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>

Luego, en Java,

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

Esto establecerá la propiedad del botón en deshabilitada y establecerá el color en plateado.

[El color se define en color.xml como:

<resources>

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

</resources>
biniam
fuente
4
@Pacerier: la pregunta no dice eso en absoluto. Es ambiguo si el estilo es XML o java. Solo pregunta cómo establecer el estilo mediante programación.
Harvey
3

En tiempo de ejecución, sabes qué estilo quieres que tenga tu botón. Entonces, de antemano, en xml en la carpeta de diseño, puede tener todos los botones listos para usar con los estilos que necesita. Entonces, en la carpeta de diseño, es posible que tenga un archivo llamado: button_style_1.xml. El contenido de ese archivo podría verse así:

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

Si está trabajando con fragmentos, entonces en onCreateView infla ese botón, como:

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

donde contenedor es el contenedor de ViewGroup asociado con el método onCreateView que anula al crear su fragmento.

¿Necesitas dos botones más? Los crea así:

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

Puede personalizar esos botones:

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

Luego, agrega sus botones personalizados y estilizados al contenedor de diseño que también infló en el método onCreateView:

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

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

Y así es como puede trabajar dinámicamente con botones estilizados.

Jerry Frost
fuente
0

Hice una interfaz de ayuda para esto usando el patrón de soporte.

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

Ahora, para cada estilo que desee utilizar de forma pragmática, simplemente implemente la interfaz, por ejemplo:

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 un estilo en su attrs.xml, el estilo para este ejemplo es:

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

Aquí está el estilo declarado en 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>

Y finalmente la implementación del estilo titular:

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

Encontré esto muy útil ya que se puede reutilizar fácilmente y mantiene el código limpio y detallado, recomendaría usar esto solo como una variable local para que podamos permitir que el recolector de basura haga su trabajo una vez que hayamos terminado con la configuración de todos los estilos .

Kostyantin2216
fuente
-1

Me enfrenté al mismo problema recientemente. así es como lo resolví.

<?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>
  • Usé un LinearLayout con android: weightSum = "2"
  • Le di a los dos elementos secundarios android: layout_weight = "1" (le di a cada uno el 50% del espacio principal (ancho y alto))
  • Y finalmente, le di a los dos elementos secundarios diferentes colores de fondo para tener el efecto final.

Gracias !

dev242
fuente