Android: Ansichtsstil programmgesteuert einstellen

226

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

Wie setze styleich Attribute programmgesteuert?

Jim
quelle
Siehe hier ['Antwort'] [1], das hat bei mir funktioniert. [1]: stackoverflow.com/a/5488652/2938493
Artificioo

Antworten:

211

Technisch gesehen können Sie Stile programmgesteuert anwenden, mit benutzerdefinierten Ansichten:

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

Der Konstruktor mit einem Argument wird verwendet, wenn Sie Ansichten programmgesteuert instanziieren.

Verketten Sie diesen Konstruktor also mit dem Super, der einen Stilparameter verwendet.

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

Oder wie @Dori einfach betonte:

RelativeLayout someLayout = new RelativeLayout(new ContextThemeWrapper(activity,R.style.LightStyle));
Blundell
quelle
34
Sie können dies einfach programmgesteuert tun, ohne es zu erweitern, da der Konstruktor mit 3 Argumenten sowieso öffentlich ist. Developer.android.com/reference/android/widget/… , android.util.AttributeSet, int)
Dori
1
@Turbo, sowohl die Dokumente als auch Eclipse sollten Ihnen Folgendes mitteilen : http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). Mit LinearLayout ist Level 11+ erforderlich.
TheOne
2
@ Dori Was würdest du für das geben AttributeSet?
Blundell
9
Wenn es sich um eine Textansicht handelt, müssen Sie setTextAppearance (R.style.small_text) für die Attribute verwenden, die sich auf Text auswirken (Größe, Farbe usw.)
Maragues
2
Ich habe keine Ahnung, warum der Ansatz mit dem dritten Argument nicht funktioniert. Ich habe mich beworben Button. @ Benjamin Piette Ansatz funktioniert gut.
Youngjae
124

Was hat bei mir funktioniert:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • Verwenden Sie einen ContextThemeWrapper

UND

  • Verwenden Sie den Konstruktor mit 3 Argumenten (funktioniert ohne diesen nicht)
Benjamin Piette
quelle
Die Verwendung Ihrer Methode funktioniert, aber ich erhalte W / ResourceType ﹕ Zu viele Attributreferenzen, gestoppt bei: 0x01010034. Irgendeine Problemumgehung?
HaloMediaz
Ich habe dieses Problem noch nie gesehen. Das kann ein gerätespezifisches Problem sein oder etwas, das mit einer aktuellen Android-Version zusammenhängt?
Benjamin Piette
11
WICHTIG! Diese Methode funktioniert , legt jedoch auch das Styling für jede untergeordnete Ansicht fest, wenn mit dem ContextThemeWrapper ein neues Layout erstellt wird.
aProperFox
@aProperFox kannst du es besser erklären? Bei mir funktioniert das Hinzufügen nur zu einem Button. Sie beziehen sich auf ein Layout?
Gilian
1
@Gilian genau, wenn Sie dies für eine zusammengesetzte Ansicht verwenden, die ein oder mehrere untergeordnete Elemente hat, erhalten diese das gleiche Design wie die übergeordnete Ansicht, für die Sie den Stil festgelegt haben. Dies kann zu zu viel Polsterung oder Rand in Innenansichten führen und Sie verrückt machen, wenn Sie sich dessen nicht bewusst sind :)
aProperFox
88

Update : Zum Zeitpunkt der Beantwortung dieser Frage (Mitte 2012, API-Ebene 14-15) war das programmgesteuerte Festlegen der Ansicht keine Option (obwohl es einige nicht triviale Problemumgehungen gab), obwohl dies nach der neueren API möglich war Veröffentlichungen. Siehe @ Blundells Antwort für Details.

ALTE Antwort:

Sie können den Stil einer Ansicht noch nicht programmgesteuert festlegen, aber dieser Thread ist möglicherweise hilfreich.

Korhan Ozturk
quelle
16
Nicht wahr. Siehe @ Blundells Antwort.
a.bertucci
31
In einigen Situationen (z. B. mit TextView) können Sie verwenden textView.setTextAppearance(context, R.style.mystyle);. Laut Dokument "Legt die Textfarbe, Größe, den Stil, die Hinweisfarbe und die Hervorhebungsfarbe aus der angegebenen TextAppearance-Ressource fest." developer.android.com/reference/android/widget/… , int)
Rogel Garcia
4
api> 23; textView.setTextAppearance (R.style.mystyle);
Alican Akyol
1
Ich habe diese Antwort vor über 4 Jahren gepostet @HaydenKai. und die API hat sich seitdem stark verändert, sodass Stile programmgesteuert angewendet werden können.
Korhan Ozturk
3
@ KorhanOzturk stimmte zu, aber auf SO mit Fragen wie diesen, die Aktivität haben, sollte die Frage wieder geöffnet und eine neue Antwort akzeptiert werden
HaydenKai
16

Für eine neue Button / TextView:

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

Für eine vorhandene Instanz:

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

Für Bilder oder Layouts:

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

Wenn Sie weiterhin XML verwenden möchten (was die akzeptierte Antwort nicht zulässt) und den Stil festlegen möchten, nachdem die Ansicht erstellt wurde, können Sie möglicherweise die Pariser Bibliothek verwenden, die eine Teilmenge aller verfügbaren Attribute unterstützt.

Da Sie Ihre Ansicht aus XML aufblasen, müssen Sie im Layout eine ID angeben:

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

Wenn Sie dann den Stil programmgesteuert ändern müssen, nachdem das Layout aufgeblasen wurde:

// 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);

Weitere Informationen: Die Liste der unterstützten Ansichtstypen und -attribute (einschließlich Hintergrund, Abstand, Rand usw., die problemlos erweitert werden können) und Installationsanweisungen mit zusätzlicher Dokumentation .

Haftungsausschluss: Ich bin der ursprüngliche Autor dieser Bibliothek.

Nathanael
quelle
Ist dies noch ein empfohlener Ansatz für 2019?
Igor Ganapolsky
1
@IgorGanapolsky afaik ja! Ich kenne keinen besseren.
Nathanael
Vielen Dank an @Nathanael für die Bereitstellung dieser Lösung. Auch als Betreuer mit dem neuesten Attribut line_height. Mach weiter so! Sehr nützlich.
Guillem Roca
7

Sie können Ihrer Aktivität einen Stil zuweisen, indem Sie Folgendes tun:

super.setTheme( R.style.MyAppTheme );

oder Android Standard:

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

in Ihrer Tätigkeit vor setContentView().

FOMDeveloper
quelle
4
@siemian kannst du bitte FOM sich frei ausdrücken lassen? Er braucht keine Bearbeitung!
Mika
6

Keine der angegebenen Antworten ist korrekt.

Sie können den Stil programmgesteuert festlegen.

Kurze Antwort ist einen Blick darauf http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435

Lange Antwort. Hier ist mein Snippet, um einen benutzerdefinierten Stil programmgesteuert auf Ihre Ansicht festzulegen:

1) Erstellen Sie einen Stil in Ihrer Datei styles.xml

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

Vergessen Sie nicht, Ihre benutzerdefinierten Attribute in der Datei attrs.xml zu definieren

Meine attrsl.xml-Datei:

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

Beachten Sie, dass Sie einen beliebigen Namen für Ihr Stylable verwenden können (mein CustomWidget).

Jetzt können Sie den Stil programmgesteuert auf das Widget einstellen. Hier ist mein einfaches 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));
}
}

Layout:

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

Und schließlich die Implementierung der StyleLoader-Klasse

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

Ein voll funktionsfähiges Beispiel finden Sie unter https://github.com/Defuera/SetStylableProgramatisch

Defuera
quelle
13
Dies ist kein wahrer Stil, es ist nur eine Fälschung, indem Sie die gespeicherten Einstellungen (ja, es handelt sich tatsächlich um eine Art von Einstellungen, die in Ihrer XML-Datei gespeichert sind) auf Ihre Ansichten anwenden / einstellen (hier haben Sie nur 2 feste Ansichten - und Sie müssen sie sicherlich kennen vorweg). Die ganze Magie steckt in der applyMethode, die nichts Interessantes bewirkt. Die wahre Bedeutung von Stil ist, dass er automatisch einen visuellen Stil auf alle zukünftigen dynamisch hinzugefügten Ansichten anwendet. Dieser Code hier kann das natürlich nicht und es gibt hier nichts Dynamisches. Wir müssen wissen, welche Ansichten und welche Eigenschaften / Felder festgelegt werden sollen.
König König
1
Es macht mir nichts aus, anzugeben, auf welche Ansichten Stile angewendet werden sollen, aber bei dieser Lösung sind die Stilelemente fest codiert (z. B. textColor und dividerColor). Es werden nicht alle im Stil definierten Elemente dynamisch gefunden und auf die Ansicht angewendet.
Nasch
Der von Ihnen gepostete Link wird nicht geöffnet. Kannst du bitte nochmal posten?
Igor Ganapolsky
4

Dies ist eine ziemlich alte Frage, aber die Lösung, die jetzt für mich funktioniert hat, besteht darin, den 4. Parameter des Konstruktors zu verwenden defStyleRes - falls verfügbar ... in der Ansicht ... um den Stil festzulegen

Folgende Arbeiten für meine Zwecke (Kotlin):

val textView = TextView(context, null, 0, R.style.Headline1)
konvexer Rumpf
quelle
3

Dies ist mein einfaches Beispiel. Der Schlüssel ist der ContextThemeWrapperWrapper. Ohne ihn funktioniert mein Stil nicht und der Konstruktor mit drei Parametern der Ansicht wird verwendet.

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

Der einfache Weg führt durch den Konstruktor

RadioButton radioButton = new RadioButton(this,null,R.style.radiobutton_material_quiz);
Sai Gopi N.
quelle
Ein wenig mehr Illustration zur Verwendung dieser Lösung wäre hilfreich.
Igor Ganapolsky
1

Ich schlage nicht vor, ContextThemeWrapper so zu verwenden:

Das angegebene Thema wird über dem Thema des Basiskontexts angewendet.

Was kann zu unerwünschten Ergebnissen in Ihrer Anwendung führen? Stattdessen schlage ich dafür eine neue Bibliothek "Paris" von Ingenieuren bei Airbnb vor:

https://github.com/airbnb/paris

Definieren und wenden Sie Stile programmgesteuert auf Android-Ansichten an.

Aber nach einiger Zeit habe ich herausgefunden, dass es tatsächlich ziemlich begrenzt ist und ich habe aufgehört, es zu verwenden, weil es nicht viele Eigenschaften unterstützt, die ich sofort brauche, also muss man wie immer auschecken und entscheiden.

Renetik
quelle
Erklären Sie Ihren Downvote-Freund ... Ich habe anderthalb Tage verloren, weil ich ContextThemeWrapper verwendet habe und es auf meinen weißen Hintergrund mit Kontextthema angewendet wurde. Dann stürzte plötzlich das Chip-Widget aus der Google-Materialbibliothek ab.
Ratet
Verwendet die Pariser Bibliothek nicht ContextThemeWrapper darunter?
Igor Ganapolsky
@IgorGanapolsky tut es nicht. Es liest den XML-Stil und konvertiert ihn in die entsprechenden Methodenaufrufe in der Ansicht.
Nathanael
Es ist eigentlich ziemlich begrenzt, dass ich es nicht mehr benutze, weil es nicht viele Eigenschaften unterstützt, die ich brauchte ...
Renetik
-1

Ich habe in meiner zusammengesetzten ViewGroup in XML definierte Ansichten verwendet und sie der Viewgroup hinzugefügt. Auf diese Weise kann ich den Stil nicht dynamisch ändern, aber ich kann einige Stilanpassungen vornehmen. Mein Composite:

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);
}

}}

und meine Ansicht in XML, wo ich Stile zuweisen kann:

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

user3918502
quelle
1
Wo setzen Sie den Stil dynamisch?
Igor Ganapolsky
-3

Sie können die XML erstellen , das Layout mit dem gewünschten Stil enthält , und ändern Sie dann den Hintergrund Ressource Ihrer Ansicht, wie diese .

rfsbraz
quelle
Sie sprechen von einem "Stil" wie in Android, aber von dem "Aspekt" einer Schaltfläche. das ist ganz anders.
Christus