Android: imposta lo stile di visualizzazione a livello di codice


226

Ecco XML:

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/LightStyle"
    android:layout_width="fill_parent"
    android:layout_height="55dip"
    android:clickable="true"
    android:orientation="horizontal" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" />

</RelativeLayout>

Come impostare l' styleattributo a livello di codice?


Vedi qui ['response'] [1], questo ha funzionato per me. [1]: stackoverflow.com/a/5488652/2938493
Artificioo,

Risposte:


211

Tecnicamente puoi applicare gli stili a livello di codice, con comunque visualizzazioni personalizzate:

private MyRelativeLayout extends RelativeLayout {
  public MyRelativeLayout(Context context) {
     super(context, null, R.style.LightStyle);
  }
}

Il costruttore di un argomento è quello utilizzato per creare un'istanza delle visualizzazioni a livello di codice.

Quindi concatena questo costruttore al super che accetta un parametro di stile.

RelativeLayout someLayout = new MyRelativeLayout(new ContextThemeWrapper(this,R.style.RadioButton));

O come ha sottolineato @Dori semplicemente:

RelativeLayout someLayout = new RelativeLayout(new ContextThemeWrapper(activity,R.style.LightStyle));

34
Potresti semplicemente farlo in modo programmatico senza estenderlo poiché il costruttore di 3 arg è comunque pubblico developer.android.com/reference/android/widget/… , android.util.AttributeSet, int)
Dori,

1
@Turbo, sia la documentazione e le eclissi dovrebbe dirvi che: http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). Con LinearLayout è richiesto il livello 11+.
TheOne

2
@Dori Cosa vorresti passare per il AttributeSet?
Blundell,

9
Se è un oggetto TextView, devi utilizzare setTextAppearance (R.style.small_text) per quegli attributi che influiscono sul testo (dimensioni, colore, ecc.)
Maragues

2
Non ho idea del perché l'approccio del 3 ° argomento non funzioni. Ho fatto domanda per Button. L'approccio di @Benjamin Piette funziona bene.
Youngjae,

124

Cosa ha funzionato per me:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • Usa un ContextThemeWrapper

E

  • Usa il costruttore a 3 argomenti (non funzionerà senza questo)

L'uso del metodo funziona, ma ottengo W / ResourceType ﹕ Troppi riferimenti agli attributi, fermati a: 0x01010034. Qualche soluzione?
HaloMediaz,

Non ho mai visto quel problema. Potrebbe trattarsi di un problema specifico del dispositivo o qualcosa correlato a una recente versione di Android?
Benjamin Piette,

11
IMPORTANTE! Questo metodo fa il lavoro, ma imposterà lo stile per ogni visualizzazione bambino così se la creazione di un nuovo layout con la ContextThemeWrapper.
aProperFox,

@aProperFox puoi spiegarmi meglio? Con me funziona aggiungendo solo un pulsante. Ti riferisci a un layout?
Gilian,

1
@Gilian esattamente, se lo usi in una vista composta con uno o più figli, avranno lo stesso stile della vista padre per cui hai impostato lo stile. Questo potrebbe portare a un'eccessiva imbottitura o margine all'interno delle viste interne e può farti impazzire se non ne sei consapevole :)
aProperFox

88

Aggiornamento : al momento di rispondere a questa domanda (metà 2012, livello API 14-15), l'impostazione della vista a livello di codice non era un'opzione (anche se c'erano alcune soluzioni non banali) mentre ciò è stato reso possibile dopo l'API più recente stampa. Vedi la risposta di @ Blundell per i dettagli.

VECCHIA Risposta:

Non puoi ancora impostare lo stile di una vista a livello di codice, ma potresti trovare utile questo thread .


16
Non vero. Vedi la risposta di @ Blundell.
a.bertucci,

31
Per alcune situazioni (ad esempio utilizzando TextView) è possibile utilizzare textView.setTextAppearance(context, R.style.mystyle);. Secondo il documento "Imposta il colore, la dimensione, lo stile, il colore del suggerimento e il colore di evidenziazione del testo dalla risorsa TextAppearance specificata." developer.android.com/reference/android/widget/… , int)
Rogel Garcia,

4
api> 23; textView.setTextAppearance (R.style.mystyle);
alican akyol,

1
Ho pubblicato questa risposta oltre 4 anni fa @HaydenKai. e l'API è cambiata molto da allora, consentendo di applicare gli stili a livello di codice.
Korhan Ozturk,

3
@KorhanOzturk ha concordato, ma su SO con domande come questa che hanno attività, la domanda dovrebbe essere riaperta e una nuova risposta accettata
HaydenKai,

16

Per un nuovo Button / TextView:

Button mMyButton = new Button(new ContextThemeWrapper(this, R.style.button_disabled), null, 0);

Per un'istanza esistente:

mMyButton.setTextAppearance(this, R.style.button_enabled);

Per immagine o layout:

Image mMyImage = new ImageView(new ContextThemeWrapper(context, R.style.article_image), null, 0);

8

Se desideri continuare a utilizzare XML (che la risposta accettata non ti consente di fare) e impostare lo stile dopo la creazione della vista, potresti essere in grado di utilizzare la libreria di Parigi che supporta un sottoinsieme di tutti gli attributi disponibili.

Poiché stai gonfiando la tua vista da XML, dovrai specificare un ID nel layout:

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/my_styleable_relative_layout"
    style="@style/LightStyle"
    ...

Quindi, quando è necessario modificare lo stile a livello di codice, dopo che il layout è stato gonfiato:

// Any way to get the view instance will do
RelativeLayout myView = findViewById(R.id.my_styleable_relative_layout);

// This will apply all the supported attribute values of the style
Paris.style(myView).apply(R.style.LightStyle);

Per di più: l'elenco dei tipi e degli attributi di visualizzazione supportati (include sfondo, riempimento, margine, ecc. E può essere facilmente esteso) e istruzioni di installazione con documentazione aggiuntiva .

Disclaimer: sono l'autore originale di detta biblioteca.


È ancora un approccio raccomandato da utilizzare nel 2019?
IgorGanapolsky,

1
@IgorGanapolsky afaik yes! Non ne conosco nessuno migliore.
Nathanael

Grazie @Nathanael per aver fornito questa soluzione. Anche per esserne il manutentore con l'ultimo attributo line_height. Continua così! Veramente utile.
Guillem Roca,

7

Puoi applicare uno stile alla tua attività facendo:

super.setTheme( R.style.MyAppTheme );

o Android predefinito:

super.setTheme( android.R.style.Theme );

nella tua attività, prima setContentView().


4
@siemian puoi per favore lasciare che FOM si esprima liberamente? Non ha bisogno di modifiche!
Mika,

6

Nessuna delle risposte fornite è corretta.

È possibile impostare lo stile a livello di codice.

La risposta breve è dare un'occhiata a http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435

Risposta lunga. Ecco il mio frammento per impostare lo stile definito personalizzato in modo programmatico per la tua vista:

1) Crea uno stile nel tuo file styles.xml

 <style name="MyStyle">
    <item name="customTextColor">#39445B</item>
    <item name="customDividerColor">#8D5AA8</item>
</style>

Non dimenticare di definire i tuoi attributi personalizzati nel file attrs.xml

Il mio file attrsl.xml:

<declare-styleable name="CustomWidget">
    <attr name="customTextColor" format="color" />
    <attr name="customDividerColor" format="color" />
</declare-styleable>

Nota che puoi usare qualsiasi nome per il tuo stile (il mio personalWidget)

Ora consente di impostare lo stile sul widget Programmaticamente Ecco il mio semplice widget:

public class StyleableWidget extends LinearLayout {

private final StyleLoader styleLoader = new StyleLoader();

private TextView textView;
private View divider;

public StyleableWidget(Context context) {
    super(context);
    init();
}

private void init() {
    inflate(getContext(), R.layout.widget_styleable, this);
    textView = (TextView) findViewById(R.id.text_view);
    divider = findViewById(R.id.divider);
    setOrientation(VERTICAL);
}

protected void apply(StyleLoader.StyleAttrs styleAttrs) {
    textView.setTextColor(styleAttrs.textColor);
    divider.setBackgroundColor(styleAttrs.dividerColor);
}

public void setStyle(@StyleRes int style) {
    apply(styleLoader.load(getContext(), style));
}
}

disposizione:

<TextView
    android:id="@+id/text_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="22sp"
    android:layout_gravity="center"
    android:text="@string/styleble_title" />

<View
    android:id="@+id/divider"
    android:layout_width="match_parent"
    android:layout_height="1dp"/>

</merge>

E infine l'implementazione della classe StyleLoader

public class StyleLoader {

public StyleLoader() {

}

public static class StyleAttrs {
    public int textColor;
    public int dividerColor;
}

public StyleAttrs load(Context context, @StyleRes int styleResId) {
    final TypedArray styledAttributes = context.obtainStyledAttributes(styleResId, R.styleable.CustomWidget);
    return load(styledAttributes);
}

@NonNull
private StyleAttrs load(TypedArray styledAttributes) {
    StyleAttrs styleAttrs = new StyleAttrs();
    try {
        styleAttrs.textColor = styledAttributes.getColor(R.styleable.CustomWidget_customTextColor, 0);
        styleAttrs.dividerColor = styledAttributes.getColor(R.styleable.CustomWidget_customDividerColor, 0);
    } finally {
        styledAttributes.recycle();
    }
    return styleAttrs;
}
}

Puoi trovare un esempio pienamente funzionante su https://github.com/Defuera/SetStylableProgrammatic


13
Questo non è un vero stile, è solo un falso applicando / configurando le impostazioni salvate (sì, in realtà è un qualche tipo di impostazioni salvate nel tuo file XML) sulle tue Viste (qui hai solo 2 Viste fisse - e sicuramente dovrai conoscerle in anticipo). Tutta la magia è nel applymetodo che non fa nulla di interessante. Il vero significato dello stile è applicare automaticamente uno stile visivo a tutte le future viste aggiunte dinamicamente. Questo codice qui ovviamente non può farlo e non c'è nulla di dinamico qui, dobbiamo sapere quali viste e quali proprietà / campi impostare.
King King

1
Non mi dispiace specificare a quali viste applicare gli stili, ma questa soluzione ha gli elementi di stile codificati (ad es. TextColor e dividerColor). Non troverà in modo dinamico tutti gli elementi definiti nello stile e non li applicherà alla vista.
nasch

Il link che hai pubblicato non si apre. Puoi per favore ripubblicare?
IgorGanapolsky,

4

Questa è una domanda piuttosto vecchia, ma la soluzione che ha funzionato per me ora è usare il 4 ° parametro del costruttore defStyleRes- se disponibile .. in vista ... per impostare lo stile

Di seguito le opere per i miei scopi (kotlin):

val textView = TextView(context, null, 0, R.style.Headline1)

3

Questo è il mio semplice esempio, la chiave è il ContextThemeWrapperwrapper, senza di essa, il mio stile non funziona e usando il costruttore di tre parametri della Vista.

ContextThemeWrapper themeContext = new ContextThemeWrapper(this, R.style.DefaultLabelStyle);
TextView tv = new TextView(themeContext, null, 0);
tv.setText("blah blah ...");
layout.addView(tv);

2

il modo semplice sta passando attraverso il costruttore

RadioButton radioButton = new RadioButton(this,null,R.style.radiobutton_material_quiz);

Un altro esempio su come utilizzare questa soluzione sarebbe utile.
IgorGanapolsky,

1

Non propongo di utilizzare ContextThemeWrapper in questo modo:

Il tema specificato verrà applicato in cima al tema del contesto di base.

Cosa può fare risultati indesiderati nella tua applicazione. Invece, propongo una nuova biblioteca "Parigi" per questo dagli ingegneri di Airbnb:

https://github.com/airbnb/paris

Definisci e applica gli stili alle visualizzazioni Android a livello di codice.

Ma dopo un po 'di tempo, ho scoperto che in realtà è piuttosto limitato e ho smesso di usarlo perché non supporta molte proprietà di cui ho bisogno, quindi bisogna controllare e decidere come sempre.


Spiega il tuo amico downvote ... Ho perso un giorno e mezzo perché ho usato ContextThemeWrapper, e si è applicato al mio tema di contesto sfondo bianco, poi improvvisamente il widget Chip dalla libreria di materiali di Google si è
bloccato

La biblioteca di Parigi non usa ContextThemeWrapper sotto?
IgorGanapolsky,

@IgorGanapolsky no. Legge lo stile XML e lo converte nelle corrispondenti chiamate di metodo nella vista.
Nathanael

In realtà è abbastanza limitato che ho smesso di usarlo perché non supporta molte proprietà di cui avevo bisogno ...
Renetik

-1

Ho usato le viste definite in XML nel mio ViewGroup composito, gonfiandole aggiunte a Viewgroup. In questo modo non posso cambiare dinamicamente lo stile ma posso fare alcune personalizzazioni di stile. Il mio composito:

public class CalendarView extends LinearLayout {

private GridView mCalendarGrid;
private LinearLayout mActiveCalendars;

private CalendarAdapter calendarAdapter;

public CalendarView(Context context) {
    super(context);

}

public CalendarView(Context context, AttributeSet attrs) {
    super(context, attrs);

}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    init();
}

private void init() {
    mCalendarGrid = (GridView) findViewById(R.id.calendarContents);
    mCalendarGrid.setNumColumns(CalendarAdapter.NUM_COLS);

    calendarAdapter = new CalendarAdapter(getContext());
    mCalendarGrid.setAdapter(calendarAdapter);
    mActiveCalendars = (LinearLayout) findViewById(R.id.calendarFooter);
}

}

e la mia vista in XML dove posso assegnare gli stili:

<com.mfitbs.android.calendar.CalendarView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="vertical"
>

<GridView
    android:id="@+id/calendarContents"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

<LinearLayout
    android:id="@+id/calendarFooter"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    />


1
Dove stai impostando dinamicamente lo stile?
IgorGanapolsky,

-3

È possibile creare il file XML contenente il layout con lo stile desiderato e quindi modificare la risorsa di sfondo della vista, in questo modo .


Stai parlando di uno "stile" come in Android, ma dell '"aspetto" di un pulsante. questo è molto diverso.
Cristo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.