Android: встановити стиль перегляду програмно


226

Ось 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>

Як встановити styleатрибут програмно?


Дивіться тут ['відповідь'] [1], це працювало для мене. [1]: stackoverflow.com/a/5488652/2938493
Artificioo

Відповіді:


211

Технічно ви можете застосовувати стилі програмно, з будь-якими власними представленнями:

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

Один конструктор аргументів - це той, який використовується при інстанціюванні подань програмно.

Так що ланцюжок цього конструктора до супер, який приймає параметр стилю.

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

Або як просто вказав @Dori:

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

34
Ви можете просто робити це програмно, не розширюючи, оскільки конструктор 3 аргументів є загальнодоступним будь-яким чином developer.android.com/reference/android/widget/… , android.util.AttributeSet, int)
Дорі,

1
@Turbo, обидва документи і затемнення повинні сказати вам , що: http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). З рівнем LinearLayout необхідний рівень 11+.
TheOne

2
@Dori Що б ти пройшов AttributeSet?
Блонделл

9
Якщо це TextView, вам потрібно використовувати setTextAppearance (R.style.small_text) для тих атрибутів, які впливають на текст (розмір, колір тощо)
Maragues

2
Я поняття не маю, чому підхід третього аргументу не працює. Я звернувся до Button. Підхід @Benjamin Piette чудово працює.
Youngjae

124

Що для мене спрацювало:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • Використовуйте ContextThemeWrapper

І

  • Використовуйте конструктор 3-аргументів (без цього не вийде)

Використання вашого методу працює, але я отримую W / ResourceType ﹕ Забагато посилань на атрибути, зупинені на: 0x01010034. Будь-яке вирішення?
HaloMediaz

Я ніколи не бачив цього питання. Це може бути проблема, пов’язана з пристроєм, чи щось пов’язане з останньою версією Android?
Бенджамін Піет

11
ВАЖЛИВО! Цей метод робить роботу, але буде встановити стиль для кожного зору дитини, а якщо створити новий макет з ContextThemeWrapper.
aProperFox

@aProperFox ви можете пояснити краще? Зі мною працює, додаючи просто кнопку. Ви посилаєтесь на макет?
Гільян

1
@Gilian точно, якщо ви використовуєте це для складеного представлення, у якого є одне або більше дітей, вони отримають таку ж стильову форму, як і для батьківського подання, для якого ви встановили стиль. Це може призвести до занадто великої потужності або запасу всередині внутрішніх поглядів і може звести вас з розуму, якщо ви цього не знаєте :)
aProperFox

88

Оновлення : На момент відповіді на це запитання (середина 2012 р., Рівень API 14-15) встановити перегляд програмно не було можливим варіантом (навіть незважаючи на те, що існували деякі нетривіальні способи вирішення), тоді як це стало можливим після більш пізнього API випуски. Детальніше див. У відповіді @ Blundell.

СТАРИЙ відповідь:

Ви ще не можете встановити стиль перегляду програмно, але ця тема може бути корисною.


16
Неправда. Дивіться відповідь @ Blundell.
a.bertucci

31
У деяких ситуаціях (наприклад, TextView) ви можете використовувати textView.setTextAppearance(context, R.style.mystyle);. Відповідно до doc "Встановлює колір тексту, розмір, стиль, колір підказки та колір виділення із зазначеного ресурсу TextAppearance." developer.android.com/reference/android/widget/… , int)
Rogel Garcia

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

1
Цю відповідь я опублікував понад 4 роки тому @HaydenKai. і API з цього часу сильно змінився, що дозволило програмно застосовувати стилі.
Корхан Озтурк

3
@KorhanOzturk погодився, але щодо таких питань, які мають активність, питання слід знову відкрити і прийняти нову відповідь
HaydenKai

16

Для нової кнопки / TextView:

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

Для існуючого примірника:

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

Для зображення або макетів:

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

8

Якщо ви хочете продовжувати використовувати XML (що прийнята відповідь не дозволяє вам робити) та встановити стиль після створення представлення, ви, можливо, зможете використовувати паризьку бібліотеку, яка підтримує підмножину всіх доступних атрибутів.

Оскільки ви надуваєте свій погляд з XML, вам потрібно буде вказати ідентифікатор у макеті:

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

Потім, коли вам потрібно змінити стиль програмно, після того, як макет був завищений:

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

Докладніше: список підтримуваних типів та атрибутів перегляду (включає фон, підкладку, поле тощо і може бути легко розширений) та інструкції з встановлення додаткової документації .

Відмова: Я є оригінальним автором згаданої бібліотеки.


Це все-таки рекомендований підхід до використання у 2019 році?
ІгорГанапольський

1
@IgorGanapolsky afaik так! Я не знаю жодного кращого.
Натанаїл

Дякую @Nathanael за надання цього рішення. Також для того, щоб бути його підтримувачем з останнім атрибутом line_height. Продовжуй гарно працювати! Дійсно корисна.
Гільем Рока

7

Ви можете застосувати стиль до своєї діяльності, виконавши:

super.setTheme( R.style.MyAppTheme );

або за замовчуванням Android:

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

у вашій діяльності, раніше setContentView().


4
@siemian Ви можете, будь ласка, дозвольте FOM самовиражатися? Йому не потрібно редагування!
Міка

6

Не надані відповіді є правильними.

МОЖЕТЕ задавати стиль програмно.

Коротка відповідь - подивіться на http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435

Довга відповідь. Ось мій фрагмент, щоб програмно встановити визначений стиль програмно для вашого перегляду:

1) Створіть стиль у вашому файлі styles.xml

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

Не забудьте визначити свої власні атрибути у файлі attrs.xml

Мій файл attrsl.xml:

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

Зауважте, що ви можете використовувати будь-яке ім'я для стилізації (мій CustomWidget)

Тепер давайте задамо стиль на віджет Програматично Ось мій простий віджет:

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

макет:

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

І нарешті реалізація класу 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;
}
}

Ви можете знайти повноцінний приклад на https://github.com/Defuera/SetStylableProgramatic


13
Це не справжній стиль, це просто підробка, застосувавши / встановивши збережені налаштування (так, це насправді якісь налаштування, збережені у вашому XML-файлі) у ваших представленнях (тут у вас є лише 2 виправлені види перегляду - і вам неодмінно потрібно знати їх заздалегідь). Вся магія полягає в тому applyметоді, який не робить нічого цікавого. Справжнє значення стилю полягає в тому, що він автоматично застосовує деякий візуальний стиль на всі майбутні динамічно додані представлення. Цей код тут, звичайно , не може зробити це , і немає нічого динамічного тут, ми повинні знати , які уявлення і які властивості / поля в набір.
Король Король

1
Я не проти вказувати, до яких поглядів слід застосувати стилі, але в цьому рішенні елементи стилів жорстко закодовані (наприклад, textColor і роздільникColor). Він не буде динамічно знаходити всі елементи, визначені у стилі, та застосовуватиме їх до перегляду.
nasch

Посилання, яке ви опублікували, не відкривається. Чи можете ви, будь ласка, повторно опублікувати?
ІгорГанапольський

4

Це досить старе питання, але рішенням, яке працювало для мене зараз, є використання 4-го параметра конструктора defStyleRes- якщо він доступний .. перегляд ... для встановлення стилю

Наступні роботи для моїх цілей (котлін):

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

3

Це мій простий приклад, ключ - це ContextThemeWrapperобгортка, без неї мій стиль не працює, і з використанням конструктора трьох параметрів View.

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

2

простий спосіб - проходження через конструктор

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

Трохи більше ілюстрації про те, як використовувати це рішення, було б корисно.
ІгорГанапольський

1

Я не пропоную використовувати ContextThemeWrapper, як це зробити:

Зазначена тема буде застосована поверх теми базового контексту.

Що може призвести до небажаних результатів у вашій заявці. Натомість я пропоную нову бібліотеку "париж" для цього від інженерів Airbnb:

https://github.com/airbnb/paris

Визначте та застосуйте стилі до переглядів Android програмно.

Але через деякий час його використання я виявив, що це насправді досить обмежено, і я перестав його використовувати, оскільки він не підтримує багато властивостей, які мені потрібні поза коробкою, тому потрібно перевірити та вирішити, як завжди.


Поясніть своєму приятелю downvote ... Я втратив день і півтора тому, що використовував ContextThemeWrapper, і він застосував до мого контексту білого тла теми, тоді раптом віджет Chip з бібліотеки матеріалів Google вийшов з ладу, здогадайтесь, чому ...
Renetik

Чи не працює в Паризькій бібліотеці ContextThemeWrapper ?
ІгорГанапольський

@IgorGanapolsky це не так. Він зчитує стиль XML і перетворює його у відповідний метод викликів у представленні.
Натанаїл

Це насправді досить обмежено, я перестав його використовувати, оскільки він не підтримує багато потрібних мені властивостей ...
Renetik

-1

Я використовував представлення, визначені в XML, у складеній ViewGroup, завищені ними додані до Viewgroup. Таким чином я не можу динамічно змінювати стиль, але можу зробити деякі налаштування стилів. Мій композит:

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

}

і мій погляд у xml, де я можу призначити стилі:

<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
Де ти динамічно встановлюєш стиль?
ІгорГанапольський

-3

Ви можете створити xml, що містить макет із потрібним стилем, а потім змінити фоновий ресурс вашого перегляду, як це .


Ви говорите про "стиль", як в Android, а про "аспект" кнопки. це дуже різне.
Христос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.