Android: programowo ustaw styl widoku

226

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

Jak ustawić styleatrybut programowo?

Jim
źródło
Zobacz tutaj [„odpowiedź”] [1], to zadziałało dla mnie. [1]: stackoverflow.com/a/5488652/2938493
Artificioo

Odpowiedzi:

211

Technicznie możesz zastosować style programowo, z niestandardowymi widokami i tak:

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

Konstruktor jednego argumentu jest używany podczas programowego tworzenia widoków.

Połącz więc ten konstruktor z super, który pobiera parametr stylu.

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

Lub, jak zauważył po prostu @Dori:

RelativeLayout someLayout = new RelativeLayout(new ContextThemeWrapper(activity,R.style.LightStyle));
Blundell
źródło
34
Możesz to zrobić programowo bez rozszerzania, ponieważ konstruktor 3 arg jest publiczny w każdym razie developer.android.com/reference/android/widget/… , android.util.AttributeSet, int)
Dori
1
@Turbo obie docs i Eclipse powinien powiedzieć, że: http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). W przypadku LinearLayout wymagany jest poziom 11+.
TheOne
2
@Dori Co byś podał za AttributeSet?
Blundell
9
Jeśli jest to TextView, musisz użyć setTextAppearance (R.style.small_text) dla tych atrybutów, które wpływają na tekst (rozmiar, kolor itp.)
Maragues
2
Nie mam pojęcia, dlaczego podejście oparte na trzecim argumencie nie działa. Złożyłem podanie Button. Podejście @Benjamin Piette działa dobrze.
Youngjae
124

Co dla mnie zadziałało:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • Użyj ContextThemeWrapper

I

  • Użyj konstruktora z 3 argumentami (bez tego nie będzie działać)
Benjamin Piette
źródło
Używanie metody działa, ale otrzymuję W / ResourceType ﹕ Zbyt wiele odwołań do atrybutów, zatrzymanych na: 0x01010034. Jakieś obejście?
HaloMediaz,
Nigdy nie widziałem tego problemu. Może to być problem związany z urządzeniem lub coś związanego z najnowszą wersją Androida?
Benjamin Piette
11
WAŻNY! Ta metoda nie działa, ale będzie ustawić stylizacji dla każdej widzenia dziecka jak również czy tworząc nowy układ z ContextThemeWrapper.
aProperFox
@ aProperFox czy możesz to lepiej wyjaśnić? Ze mną działa, dodając tylko do przycisku. Masz na myśli układ?
Gilian
1
@Gilian dokładnie, jeśli użyjesz tego w widoku złożonym, który ma jedno lub więcej dzieci, otrzymają taki sam styl jak widok nadrzędny, dla którego ustawiłeś styl. Może to prowadzić do zbyt dużego wypełnienia lub marginesu w wewnętrznych widokach i może doprowadzić cię do szaleństwa, jeśli nie jesteś tego świadomy :)
aProperFox
88

Aktualizacja : w momencie udzielenia odpowiedzi na to pytanie (połowa 2012 r., Poziom interfejsu API 14-15) programowe ustawienie widoku nie było opcją (nawet jeśli były pewne niebanalne obejścia), podczas gdy stało się to możliwe po nowszym interfejsie API wydania. Szczegóły znajdują się w odpowiedzi @ Blundell.

Stara odpowiedź:

Nie możesz jeszcze ustawić stylu widoku programowo, ale ten wątek może ci się przydać.

Korhan Ozturk
źródło
16
Nie prawda. Zobacz odpowiedź @ Blundell.
a.bertucci
31
W niektórych sytuacjach (na przykład przy użyciu TextView) możesz użyć textView.setTextAppearance(context, R.style.mystyle);. Zgodnie z dokumentem „Ustawia kolor tekstu, rozmiar, styl, kolor podpowiedzi i kolor podświetlenia z określonego zasobu TextAppearance”. developer.android.com/reference/android/widget/… , int)
Rogel Garcia
4
api> 23; textView.setTextAppearance (R.style.mystyle);
alican akyol
1
Opublikowałem tę odpowiedź ponad 4 lata temu @HaydenKai. a interfejs API bardzo się zmienił od tego czasu umożliwiając programowe stosowanie stylów.
Korhan Ozturk,
3
@KorhanOzturk zgodził się, ale w przypadku SO z takimi pytaniami, które mają aktywność, pytanie należy otworzyć ponownie i zaakceptować nową odpowiedź
HaydenKai
16

W przypadku nowego Button / TextView:

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

W przypadku istniejącej instancji:

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

W przypadku obrazu lub układów:

Image mMyImage = new ImageView(new ContextThemeWrapper(context, R.style.article_image), null, 0);
Alon Kogan
źródło
8

Jeśli chcesz nadal używać XML (na co nie pozwala zaakceptowana odpowiedź) i ustawić styl po utworzeniu widoku, możesz użyć biblioteki Paris, która obsługuje podzbiór wszystkich dostępnych atrybutów.

Ponieważ nadmuchujesz swój widok z XML, musisz określić identyfikator w układzie:

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

Następnie, gdy trzeba programowo zmienić styl, po napompowaniu układu:

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

Więcej informacji: lista obsługiwanych typów widoków i atrybutów (w tym tło, wypełnienie, margines itp., Które można łatwo rozszerzyć) oraz instrukcje instalacji z dodatkową dokumentacją .

Oświadczenie: Jestem oryginalnym autorem wspomnianej biblioteki.

Natanael
źródło
Czy nadal jest to zalecane podejście do stosowania w 2019 roku?
IgorGanapolsky
1
@IgorGanapolsky afaik yes! Nie znam lepszego.
Natanael
Dziękujemy @Nathanael za dostarczenie tego rozwiązania. Również za to, że jest jego opiekunem dzięki najnowszemu atrybutowi line_height. Tak trzymaj! Naprawdę użyteczne.
Guillem Roca
7

Możesz zastosować styl do swojej działalności, wykonując:

super.setTheme( R.style.MyAppTheme );

lub domyślny system Android:

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

w twojej działalności wcześniej setContentView().

FOMDeveloper
źródło
4
@siemian, czy możesz pozwolić FOM swobodnie wyrazić siebie? Nie potrzebuje edycji!
Mika
6

Brak podanych odpowiedzi jest poprawny.

Możesz ustawić styl programowo.

Krótka odpowiedź znajduje się na stronie http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435

Długa odpowiedź. Oto mój fragment, aby programowo ustawić niestandardowy styl zdefiniowany w widoku:

1) Utwórz styl w pliku styles.xml

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

Nie zapomnij zdefiniować niestandardowych atrybutów w pliku attrs.xml

Mój plik attrsl.xml:

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

Zauważ, że możesz używać dowolnej nazwy dla swojego stylowego (mój CustomWidget)

Teraz ustawmy styl widgetu Programowo Oto mój prosty 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));
}
}

układ:

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

I wreszcie implementacja klasy 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;
}
}

Możesz znaleźć w pełni działający przykład na https://github.com/Defuera/SetStylableProgramatically

Defuera
źródło
13
To nie jest prawdziwy styl, jest to po prostu fałsz, poprzez zastosowanie / ustawienie zapisanych ustawień (tak, to w rzeczywistości jakieś ustawienia zapisane w pliku XML) w widokach (tutaj masz tylko 2 stałe widoki - i na pewno musisz je znać uprzednio). Cała magia polega na applymetodzie, która nie robi nic interesującego. Prawdziwe znaczenie stylu polega na tym, że automatycznie nakłada pewien styl wizualny na wszystkie dynamicznie dodawane widoki w przyszłości. Ten kod tutaj oczywiście nie może tego zrobić i nie ma tu nic dynamicznego, musimy wiedzieć, jakie Widoki i jakie właściwości / pola ustawić.
Król Król
1
Nie mam nic przeciwko określaniu widoków, do których mają być stosowane style, ale w tym rozwiązaniu elementy stylu są zakodowane na stałe (np. TextColor i dividerColor). Nie znajdzie dynamicznie wszystkich elementów zdefiniowanych w stylu i zastosuje je do widoku.
nasch
Link, który opublikowałeś, nie otwiera się. Czy możesz ponownie wysłać wiadomość?
IgorGanapolsky
4

To dość stare pytanie, ale rozwiązaniem, które teraz działało, jest użycie czwartego parametru konstruktora defStyleRes- jeśli jest dostępny ... w widoku ... aby ustawić styl

Następujące prace do moich celów (kotlin):

val textView = TextView(context, null, 0, R.style.Headline1)
wypukły
źródło
3

To jest mój prosty przykład, kluczem jest ContextThemeWrapperopakowanie, bez niego mój styl nie działa i przy użyciu konstruktora trzech parametrów widoku.

ContextThemeWrapper themeContext = new ContextThemeWrapper(this, R.style.DefaultLabelStyle);
TextView tv = new TextView(themeContext, null, 0);
tv.setText("blah blah ...");
layout.addView(tv);
guogangj
źródło
2

najprostszym sposobem jest przejście przez konstruktor

RadioButton radioButton = new RadioButton(this,null,R.style.radiobutton_material_quiz);
Sai Gopi N.
źródło
Przydałaby się nieco więcej ilustracji na temat korzystania z tego rozwiązania.
IgorGanapolsky
1

Nie proponuję używać ContextThemeWrapper, ponieważ:

Określony motyw zostanie zastosowany nad motywem podstawowego kontekstu.

Co może powodować niepożądane wyniki w Twojej aplikacji. Zamiast tego proponuję nową bibliotekę „Paris” dla inżynierów z Airbnb:

https://github.com/airbnb/paris

Programowo definiuj i stosuj style do widoków Androida.

Ale po pewnym czasie korzystania z niego odkryłem, że jest naprawdę dość ograniczony i przestałem go używać, ponieważ nie obsługuje on wielu właściwości, których potrzebuję po wyjęciu z pudełka, więc trzeba to sprawdzić i jak zawsze zdecydować.

Renetik
źródło
Wyjaśnij kumpelowi, który przegłosował ... Straciłem półtora dnia, ponieważ użyłem ContextThemeWrapper i zastosowałem to do mojego kontekstu na białym tle, a potem nagle widżet Chip z biblioteki materiałów Google
załamał się
Czy biblioteka Paryża nie używa pod spodem ContextThemeWrapper ?
IgorGanapolsky
@IgorGanapolsky nie. Odczytuje styl XML i konwertuje go na odpowiednie wywołania metod w widoku.
Natanael
Jest właściwie dość ograniczony, że przestałem go używać, ponieważ nie obsługuje wielu potrzebnych właściwości ...
Renetik
-1

Użyłem widoków zdefiniowanych w XML w mojej złożonej grupie ViewGroup, zawyżając je dodając do grupy Viewgroup. W ten sposób nie mogę dynamicznie zmieniać stylu, ale mogę dokonać pewnych dostosowań stylu. Mój kompozyt:

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

}

i mój widok w xml, w którym mogę przypisywać style:

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

użytkownik3918502
źródło
1
Gdzie dynamicznie ustawiasz styl?
IgorGanapolsky
-3

Możesz utworzyć plik XML zawierający układ z pożądanym stylem, a następnie zmienić zasób tła swojego widoku, w ten sposób .

rfsbraz
źródło
Mówisz o „stylu” jak w Androidzie, ale o „aspekcie” przycisku. to jest bardzo różne.
Chrystus