Android: görünüm stilini programlı olarak ayarla


227

İşte 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>

styleNitelik programlı olarak nasıl ayarlanır ?


Buraya bakın ['yanıt'] [1], bu benim için çalıştı. [1]: stackoverflow.com/a/5488652/2938493
Artificioo

Yanıtlar:


212

Teknik olarak, stilleri yine de özel görünümlerle programlı olarak uygulayabilirsiniz:

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

Bir bağımsız değişken yapıcısı, görünümleri programlı olarak başlatırken kullanılan yapıdır.

Bu yapıcıyı bir style parametresi alan süper ile zincirleyin.

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

Veya @Dori'nin belirttiği gibi:

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

34
3 arg yapıcı nasıl olsa halk olduğu gibi sadece programlama uzatmadan bu yapabileceğini developer.android.com/reference/android/widget/... , android.util.AttributeSet, int)
Dori

1
@Turbo, dokümanlar ve tutulması hem sen söylemelisin: http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). LinearLayout ile Level 11+ gereklidir.
TheOne

2
@Dori Ne için geçirdiniz AttributeSet?
Blundell

9
Bir TextView ise, metni etkileyen boyutlar (boyut, renk vb.) İçin setTextAppearance (R.style.small_text) kullanmanız gerekir
Maragues

2
Üçüncü argüman yaklaşımının neden işe yaramadığı hakkında hiçbir fikrim yok. Başvurdum Button. @ Benjamin Piette yaklaşımı iyi çalışıyor.
Youngjae

124

Benim için ne işe yaradı:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • ContextThemeWrapper kullanın

VE

  • 3 argüman yapıcısını kullanın (bu olmadan çalışmaz)

Yönteminizi kullanarak çalışır, ancak W / ResourceType alırım ﹕ Çok fazla öznitelik başvurusu, durdu: 0x01010034. Herhangi bir çözüm var mı?
HaloMediaz

Bu konuyu hiç görmedim. Bu aygıta özgü bir sorun veya son Android sürümüyle ilgili bir şey olabilir mi?
Benjamin Piette

11
ÖNEMLİ! Bu yöntem yapar işi, ama ilişkin stilleri ayarlayacaktır her çocuk görünümünde yanı ise ContextThemeWrapper ile yeni Düzeni yaratmak.
aProperFox

@aProperFox daha iyi açıklayabilir misiniz? Benimle sadece bir Button ekleyerek çalışır. Bir düzene mi bakıyorsunuz?
Gilian

1
@Gilian tam olarak, bunu bir veya daha fazla çocuğu olan bileşik bir görünümde kullanırsanız, stili ayarladığınız üst görünümle aynı stile sahip olurlar. Bu, iç görünümlerde çok fazla dolgu veya kenar boşluğuna yol açabilir ve farkında değilseniz sizi
çıldırtabilir

88

Güncelleme : Bu soruyu cevaplarken (2012 ortası, API düzeyi 14-15), görünümü programlı olarak ayarlamak bir seçenek değildi (önemsiz olmayan geçici çözümler olsa da), ancak bu daha yeni API'den sonra mümkün oldu Salıverme. Ayrıntılar için @ Blundell cevabına bakınız.

ESKİ Cevap:

Sen olamaz programlı henüz görünümün stili ayarlamak, ancak bulabilirsiniz Konuyu kullanışlı.


16
Doğru değil. Bkz. @ Blundell cevabı.
a.bertucci

31
Bazı durumlarda (örneğin, TextView kullanarak) kullanabilirsiniz textView.setTextAppearance(context, R.style.mystyle);. "Belirtilen TextAppearance kaynağından metin rengini, boyutunu, stilini, ipucu rengini ve vurgu rengini ayarlar." developer.android.com/reference/android/widget/… , int)
Rogel Garcia

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

1
Bu yanıtı 4 yıldan fazla bir süre önce @HaydenKai gönderdi. ve API, stilleri programlı olarak uygulamayı etkinleştirdiğinden beri çok değişti.
Korhan Ozturk

3
@KorhanOzturk kabul etti, ancak SO'da böyle bir aktiviteye sahip sorularla soru yeniden açılmalı ve yeni bir cevap kabul
edilmelidir

16

Yeni bir Button / TextView için:

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

Mevcut bir örnek için:

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

Görüntü veya düzenler için:

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

8

XML'i kullanmaya devam etmek istiyorsanız (kabul edilen cevap size izin vermez) ve görünüm oluşturulduktan sonra stili ayarlamak isterseniz, kullanılabilir tüm özelliklerin bir alt kümesini destekleyen Paris kütüphanesini kullanabilirsiniz.

Görünümünüzü XML'den şişirdiğiniz için mizanpajda bir kimlik belirtmeniz gerekir:

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

Ardından, stili şişirildikten sonra stili programlı olarak değiştirmeniz gerektiğinde:

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

Daha fazla bilgi için: desteklenen görünüm türleri ve özniteliklerinin listesi (arka plan, dolgu, kenar boşluğu vb. İçerir ve kolayca genişletilebilir) ve ek belgeler içeren kurulum talimatları .

Feragatname: Söz konusu kütüphanenin asıl yazarıyım.


Bu 2019'da hala önerilen bir yaklaşım mı?
IgorGanapolsky

1
@IgorGanapolsky afaik evet! Daha iyisini bilmiyorum.
Nathanael

@Nathanael'e bu çözümü sağladığınız için teşekkür ederiz. Ayrıca, en son line_height özniteliğine sahip olduğu için. İyi işlere devam edin! Gerçekten kullanışlı.
Guillem Roca

7

Etkinliğinize bir stil uygulayarak şunları yapabilirsiniz:

super.setTheme( R.style.MyAppTheme );

veya Android varsayılanı:

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

faaliyetinizde, daha önce setContentView().


4
@siemian lütfen FOM'un kendini özgürce ifade etmesine izin verebilir misin? Düzenlemeye ihtiyacı yok!
Mika

6

Verilen cevapların doğru olmaması.

Stili programlı olarak ayarlayabilirsiniz.

Kısa cevap http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435 adresine bakın.

Uzun cevap. Özel tanımlanmış stili programlı olarak görünümünüze ayarlamak için snippetim:

1) styles.xml dosyanızda bir stil oluşturun

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

Özel niteliklerinizi attrs.xml dosyasında tanımlamayı unutmayın

Attrsl.xml dosyam:

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

Stillenebilir öğeniz için herhangi bir ad kullanabileceğinize dikkat edin (CustomWidget'ım)

Şimdi stili widget olarak ayarlayalım Programlı İşte İşte benim basit 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));
}
}

Yerleşim:

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

Ve son olarak StyleLoader sınıfı uygulaması

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

Tam çalışan örneği https://github.com/Defuera/SetStylableProgramatically adresinde bulabilirsiniz.


13
Bu gerçek bir stil değil, Görünümlerinizde kaydedilen ayarları uygulayarak / ayarlayarak (evet aslında XML dosyanızda kaydedilmiş bir tür ayar) sahte (burada sadece 2 sabit Görünümünüz var - ve mutlaka bilmeniz gerekir) önceden). Tüm sihir applyilginç bir şey yapmayan yöntemdedir. Stilin gerçek anlamı , gelecekteki dinamik olarak eklenen Görünümlere otomatik olarak bazı görsel stiller uygulamaktır. Bu kod elbette bunu yapamaz ve burada dinamik bir şey yoktur, hangi Görünümlerin ve hangi özelliklerin / alanların ayarlanacağını bilmemiz gerekir .
Kral Kral

1
Hangi görünümleri stil uygulamak için belirtmek için umursamıyorum, ama bu çözüm (örneğin textColor ve dividerColor) sabit kodlanmış stil öğelerine sahiptir. Stilde tanımlanan tüm öğeleri dinamik olarak bulamaz ve bunları görünüme uygulayamaz.
17'de

Gönderdiğiniz bağlantı açılmıyor. Lütfen yeniden gönderebilir misiniz?
IgorGanapolsky

4

Bu oldukça eski bir soru ama benim için işe yarayan çözüm yapıcı 4. parametresini kullanmak defStyleRes- eğer varsa .. görünümde ... stili ayarlamak için

Benim amacım için aşağıdaki işler (kotlin):

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

3

Bu benim basit örneğim, anahtar ContextThemeWrappersarıcı, onsuz, tarzım çalışmıyor ve Görünümün üç parametre yapıcısını kullanıyor.

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

2

basit yol yapıcıdan geçmek

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

Bu çözümün nasıl kullanılacağına dair biraz daha örnek yardımcı olacaktır.
IgorGanapolsky

1

Bunu yapmak gibi ContextThemeWrapper kullanmayı önermiyoruz:

Belirtilen tema, temel içeriğin temasının üstüne uygulanacaktır.

Başvurunuzda istenmeyen sonuçlara ne yol açabilir? Bunun yerine Airbnb'deki mühendislerden yeni bir "paris" kütüphanesi öneriyorum:

https://github.com/airbnb/paris

Android görünümlerini programlı olarak tanımlayın ve uygulayın.

Ama bir süre kullandıktan sonra aslında oldukça sınırlı olduğunu öğrendim ve ben kutudan dışarı ihtiyaç duyduğum birçok özelliği desteklemediği için kullanmayı bıraktım, bu yüzden bir kontrol etmeli ve her zaman olduğu gibi karar vermeliyim.


Downvote arkadaşınızı açıklayın ... ContextThemeWrapper'ı kullandığım için bir buçuk gün kaybettim ve bağlam teması beyaz arka planıma uygulandı, sonra aniden google malzeme kütüphanesinden Chip widget'ı çöküyordu, tahmin et neden ...
Renetik

Paris kütüphanesi altında ContextThemeWrapper kullanmıyor mu?
IgorGanapolsky

@IgorGanapolsky değil. XML stilini okur ve görünümde karşılık gelen yöntem çağrılarına dönüştürür.
Nathanael

Aslında oldukça sınırlıdır, çünkü ihtiyacım olan birçok özelliği desteklemediğinden kullanmayı bıraktım ...
Renetik

-1

Kompozit ViewGroup'ta XML'de tanımlanan görünümleri kullandım, onları Viewgroup'a ekledim. Bu şekilde stili dinamik olarak değiştiremiyorum ancak bazı stil özelleştirmeleri yapabilirim. Kompozitim:

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

}

ve stilleri atayabileceğim xml'de görünümüm:

<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
Stili dinamik olarak nerede ayarlıyorsunuz?
IgorGanapolsky

-3

İstediğiniz stile sahip düzeni içeren xml oluşturabilir ve ardından görünümünüzün arka plan kaynağını bu şekilde değiştirebilirsiniz .


Android'de olduğu gibi bir "stil" hakkında, ancak bir düğmenin "yönü" hakkında konuşuyorsunuz. bu çok farklı.
Mesih
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.