Android: atur gaya tampilan secara terprogram

226

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

Bagaimana cara mengatur styleatribut secara terprogram?

Jim
sumber
Lihat di sini ['respons'] [1], ini berhasil untuk saya. [1]: stackoverflow.com/a/5488652/2938493
Artificioo

Jawaban:

211

Secara teknis Anda dapat menerapkan gaya secara terprogram, dengan pandangan khusus:

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

Konstruktor satu argumen adalah yang digunakan ketika Anda instantiate tampilan pemrograman.

Jadi rangkai konstruktor ini ke super yang mengambil parameter style.

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

Atau seperti yang ditunjukkan oleh @Dori:

RelativeLayout someLayout = new RelativeLayout(new ContextThemeWrapper(activity,R.style.LightStyle));
Blundell
sumber
34
Anda bisa melakukan ini secara programatik tanpa memperluas karena konstruktor 3 arg bersifat publik , developer.android.com/reference/android/widget/… , android.util.AttributeSet, int)
Dori
1
@Turbo, baik dokumen, dan gerhana harus memberitahu Anda bahwa: http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). Dengan LinearLayout Level 11+ diperlukan.
TheOne
2
@Dori Apa yang akan Anda lewati untuk AttributeSet?
Blundell
9
Jika itu adalah TextView, Anda perlu menggunakan setTextAppearance (R.style.small_text) untuk atribut yang memengaruhi teks (ukuran, warna, dll.)
Maragues
2
Saya tidak tahu mengapa pendekatan argumen ke-3 tidak berhasil. Saya melamar Button. Pendekatan @Benjamin Piette bekerja dengan baik.
Youngjae
124

Apa yang berhasil untuk saya:

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

DAN

  • Gunakan konstruktor 3-argumen (tidak akan berfungsi tanpa ini)
Benjamin Piette
sumber
Menggunakan metode Anda berfungsi, tetapi saya mendapatkan W / ResourceType ﹕ Terlalu banyak referensi atribut, berhenti di: 0x01010034. Ada solusi?
HaloMediaz
Saya belum pernah melihat masalah itu. Itu mungkin masalah khusus perangkat, atau sesuatu yang terkait dengan versi Android terbaru?
Benjamin Piette
11
PENTING! Metode ini berfungsi, tetapi akan mengatur gaya untuk setiap tampilan anak juga jika membuat Layout baru dengan ContextThemeWrapper.
aProperFox
@ aProperFox dapatkah Anda menjelaskan lebih baik? Dengan saya berfungsi dengan menambahkan hanya ke Tombol. Anda merujuk ke tata letak?
Gilian
1
@Gilian tepatnya, jika Anda menggunakan ini pada tampilan majemuk yang memiliki satu atau lebih anak, mereka akan mendapatkan gaya yang sama dengan tampilan induk yang Anda atur gaya. Hal ini dapat menyebabkan terlalu banyak bantalan atau margin dalam tampilan bagian dalam dan dapat membuat Anda gila jika Anda tidak menyadarinya :)
aProperFox
88

Pembaruan : Pada saat menjawab pertanyaan ini (pertengahan 2012, API level 14-15), pengaturan tampilan secara terprogram bukanlah suatu pilihan (meskipun ada beberapa penyelesaian non-sepele) di mana hal ini dimungkinkan setelah API yang lebih baru rilis. Lihat jawaban @ Blundell untuk detailnya.

Jawaban LAMA:

Anda belum dapat menetapkan gaya tampilan secara terprogram, tetapi Anda dapat menemukan utas ini berguna.

Korhan Ozturk
sumber
16
Tidak benar. Lihat jawaban @ Blundell.
a.bertucci
31
Untuk beberapa situasi (menggunakan TextView misalnya) Anda dapat menggunakan textView.setTextAppearance(context, R.style.mystyle);. Menurut dokumen "Mengatur warna teks, ukuran, gaya, warna petunjuk, dan sorot warna dari sumber daya TextAppearance yang ditentukan." developer.android.com/reference/android/widget/… , int)
Rogel Garcia
4
api> 23; textView.setTextAppearance (R.style.mystyle);
alican akyol
1
Saya memposting jawaban ini lebih dari 4 tahun yang lalu @HaydenKai. dan API telah banyak berubah sejak saat itu memungkinkan penerapan gaya pemrograman.
Korhan Ozturk
3
@KorhanOzturk setuju, tetapi pada SO dengan pertanyaan-pertanyaan seperti ini yang memiliki aktivitas pertanyaan harus dibuka kembali dan jawaban baru diterima
HaydenKai
16

Untuk Tombol / TextView baru:

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

Untuk contoh yang ada:

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

Untuk Gambar atau tata letak:

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

Jika Anda ingin terus menggunakan XML (yang mana jawaban yang diterima tidak membiarkan Anda melakukannya) dan mengatur gaya setelah tampilan dibuat, Anda mungkin dapat menggunakan perpustakaan Paris yang mendukung subset dari semua atribut yang tersedia.

Karena Anda menggembungkan tampilan dari XML, Anda harus menentukan id di tata letak:

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

Kemudian ketika Anda perlu mengubah gaya pemrograman, setelah tata letak telah meningkat:

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

Untuk lebih lanjut: daftar jenis dan atribut tampilan yang didukung (termasuk latar belakang, lapisan, margin, dll. Dan dapat dengan mudah diperpanjang) dan petunjuk pemasangan dengan dokumentasi tambahan .

Penafian: Saya penulis asli perpustakaan tersebut.

Nathanael
sumber
Apakah ini masih merupakan pendekatan yang disarankan untuk digunakan pada 2019?
IgorGanapolsky
1
@IgorGanapolsky afaik ya! Saya tidak tahu yang lebih baik.
Nathanael
Terima kasih @Nathanael untuk menyediakan solusi ini. Juga karena telah mempertahankannya dengan atribut line_height terbaru. Pertahankan kerja bagus! Sangat bermanfaat.
Guillem Roca
7

Anda dapat menerapkan gaya pada aktivitas Anda dengan melakukan:

super.setTheme( R.style.MyAppTheme );

atau Android bawaan:

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

dalam aktivitas Anda, sebelumnya setContentView().

FOMDeveloper
sumber
4
@siemian bisakah Anda membiarkan FOM mengekspresikan dirinya secara bebas? Dia tidak perlu diedit!
Mika
6

Tidak ada jawaban yang diberikan yang benar.

Anda BISA mengatur gaya secara pemrograman.

Jawaban singkatnya adalah lihat di http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1.1_r1/android/content/Context.java#435

Jawaban panjang. Inilah cuplikan saya untuk menetapkan gaya yang ditentukan khusus secara terprogram untuk tampilan Anda:

1) Buat gaya dalam file styles.xml Anda

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

Jangan lupa untuk mendefinisikan atribut khusus Anda dalam file attrs.xml

File attrsl.xml saya:

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

Perhatikan Anda dapat menggunakan nama apa pun untuk gaya Anda (CustomWidget saya)

Sekarang mari kita atur gaya ke widget Secara terprogram Inilah widget sederhana Saya:

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

tata letak:

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

Dan akhirnya implementasi kelas 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;
}
}

Anda dapat menemukan contoh yang berfungsi penuh di https://github.com/Defuera/SetStylableProgramatically

Defuera
sumber
13
Ini bukan gaya yang sebenarnya, itu hanya palsu dengan menerapkan / mengatur pengaturan yang disimpan (ya itu sebenarnya semacam pengaturan yang disimpan dalam file XML Anda) pada Tampilan Anda (di sini Anda hanya memiliki 2 Tampilan tetap - dan Anda pasti perlu mengetahuinya sebelumnya). Semua keajaiban ada dalam applymetode yang tidak menarik. Arti sebenarnya dari gaya adalah secara otomatis menerapkan beberapa gaya visual pada semua Tampilan yang ditambahkan secara dinamis di masa depan. Kode ini di sini tentu saja tidak bisa melakukan itu dan tidak ada yang dinamis di sini, kita perlu tahu apa yang dilihat dan yang sifat / ladang untuk set.
King King
1
Saya tidak keberatan menentukan tampilan untuk menerapkan gaya, tetapi solusi ini memiliki elemen gaya hard-coded (misalnya textColor dan dividerColor). Itu tidak akan secara dinamis menemukan semua elemen yang didefinisikan dalam gaya dan menerapkannya pada tampilan.
nasch
Tautan yang Anda poskan tidak terbuka. Bisakah Anda memposting ulang?
IgorGanapolsky
4

Ini pertanyaan yang cukup lama tetapi solusi yang bekerja untuk saya sekarang adalah dengan menggunakan parameter konstruktor ke-4 defStyleRes- jika tersedia .. pada tampilan ... untuk mengatur gaya

Pekerjaan berikut untuk tujuan saya (kotlin):

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

Ini adalah contoh sederhana saya, kuncinya adalah ContextThemeWrapperpembungkus, tanpa itu, gaya saya tidak berfungsi, dan menggunakan tiga parameter konstruktor View.

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

cara sederhana melewati konstruktor

RadioButton radioButton = new RadioButton(this,null,R.style.radiobutton_material_quiz);
Sai Gopi N
sumber
Ilustrasi lebih sedikit tentang cara menggunakan solusi ini akan sangat membantu.
IgorGanapolsky
1

Saya tidak menyarankan untuk menggunakan ContextThemeWrapper karena ia melakukan ini:

Tema yang ditentukan akan diterapkan di atas tema konteks dasar.

Apa yang dapat membuat hasil yang tidak diinginkan dalam aplikasi Anda. Sebagai gantinya saya mengusulkan perpustakaan baru "paris" untuk ini dari para insinyur di Airbnb:

https://github.com/airbnb/paris

Tetapkan dan terapkan gaya ke tampilan Android secara terprogram.

Tetapi setelah beberapa waktu menggunakannya saya menemukan itu sebenarnya sangat terbatas dan saya berhenti menggunakannya karena tidak mendukung banyak properti yang saya butuhkan di luar kotak, jadi kita harus memeriksa dan memutuskan seperti biasa.

Renetik
sumber
Jelaskan teman downvote Anda ... Saya kehilangan satu setengah hari karena saya telah menggunakan ContextThemeWrapper, dan itu diterapkan pada latar belakang putih tema konteks saya, lalu tiba-tiba widget Chip dari pustaka materi google mogok,
coba
Bukankah perpustakaan Paris menggunakan ContextThemeWrapper di bawahnya?
IgorGanapolsky
@ IgorGanapolsky tidak. Itu membaca gaya XML dan mengubahnya menjadi panggilan metode yang sesuai pada tampilan.
Nathanael
Ini sebenarnya sangat terbatas saya berhenti menggunakannya karena tidak mendukung banyak properti yang saya butuhkan ...
Renetik
-1

Saya menggunakan tampilan yang didefinisikan dalam XML dalam ViewGroup komposit saya, menggembungkannya ditambahkan ke Viewgroup. Dengan cara ini saya tidak dapat mengubah gaya secara dinamis tetapi saya dapat membuat beberapa penyesuaian gaya. Komposit saya:

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

}

dan tampilan saya di xml tempat saya dapat menetapkan gaya:

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

pengguna3918502
sumber
1
Di mana Anda secara dinamis mengatur gaya?
IgorGanapolsky
-3

Anda dapat membuat xml yang berisi tata letak dengan gaya yang diinginkan dan kemudian mengubah sumber latar belakang tampilan Anda, seperti ini .

rfsbraz
sumber
Anda lebih banyak berbicara tentang "gaya" seperti di Android, tetapi tentang "aspek" tombol. ini sangat berbeda.
Kristus