263

I'm trying to use the TextView constructor with style like this:

TextView myText = new TextView(MyActivity.this, null, R.style.my_style);

However, when I do this, the text view does not appear to take the style (I verified the style by setting it on a static object).

I've also tried using myText.setTextAppearance(MyActivity.this, R.style.my_style) but it also doesn't work.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Ben
  • 16,124
  • 22
  • 77
  • 122

13 Answers13

331

I do not believe you can set the style programatically. To get around this you can create a template layout xml file with the style assigned, for example in res/layout create tvtemplate.xml as with the following content:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="This is a template"
        style="@style/my_style" />

then inflate this to instantiate your new TextView:

TextView myText = (TextView)getLayoutInflater().inflate(R.layout.tvtemplate, null);
Halo
  • 1,730
  • 1
  • 8
  • 31
Dan Kilpatrick
  • 3,929
  • 2
  • 22
  • 15
  • 1
    Where this wins over Dandre Allison's answer is that it doesn't require API v11. – Martin Capodici Jun 21 '14 at 04:05
  • 2
    It might have worked, but this doesn't make sense. How can it possibly be set with the xml file? if not **programmatically**. There are reasons not to use xml files, one of them is I am used to write code to build the UI so I don't want to learn a new way of doing it since my memory is limited and I want to keeps some room for other things. – Iharob Al Asimi Aug 12 '15 at 13:59
  • @IharobAlAsimi that's right, all things can be done programmatically, and LayoutInflater knows everything about turning XML into objects. Sadly, many such things are hidden under private APIs, and the only way of creating some objects is supplying AttributeSet to the constructor. – Miha_x64 Apr 21 '17 at 09:47
  • Unlike all the other answers this actually worked with spinners so a gold star for you – Rowan Berry Dec 19 '19 at 00:52
  • Only this solution works with all attributes defined in my style, unlike solution with 4-arguments constructor (as example, textAppearance defined as style). – Myroslav Oct 07 '20 at 06:19
  • the only useful answer! – Zhou Hongbo Feb 15 '22 at 15:13
130

You can create a generic style and re-use it on multiple textviews like the one below:

textView.setTextAppearance(this, R.style.MyTextStyle);

Edit: this refers to the Context object.

Bikram Kumar
  • 393
  • 1
  • 4
  • 15
Shahul3D
  • 2,129
  • 1
  • 15
  • 16
  • 55
    Your answer works as long as all your doing is monkeying with the "style" of the text. It does not work if you're trying to do other things to the TextView like add padding or margins. So, I'm not saying you're wrong, but your answer is limited. Inflating the view at runtime is the only way to apply a comprehensive style. – Bill Mote Feb 05 '13 at 14:14
  • 1
    Both solutions of using an inflated template and using setTextAppearance are reasonable. To address the padding/margins issue for the 2nd solution you can call textView.setLayoutParams(layoutParams) – AlanKley Nov 14 '13 at 16:45
  • This method was deprecated in API level 23. Use setTextAppearance(int) instead in API 23+. – Sergii Nov 28 '15 at 12:36
  • Make sure the version is at least API 23 (M) – Mouhamed Ndiaye Apr 21 '16 at 14:07
  • 5
    use the method from the support library, `TextViewCompat.setTextAppearance` – Rubin Yoo Dec 02 '16 at 20:29
104

You can pass a ContextThemeWrapper to the constructor like this:

TextView myText = new TextView(new ContextThemeWrapper(MyActivity.this, R.style.my_style));
maxcanna
  • 1,755
  • 2
  • 12
  • 15
  • 1
    great stuff! the only way I could set styles programmatically while supporting API 8. – tbraun Nov 23 '13 at 18:08
  • 1
    For some reason, it doesn't affect my button's style. I have defined my style like: ``. And then I invoke it with a construction: `new Button(new ContextThemeWrapper(context, R.style.TabButton));`. But the button simply ignores my settings. Am I doing anything wrong here? – Aleks N. Jan 06 '14 at 15:46
  • @AlaksiejN.You should inherit from Widget.Button style like this `parent="@android:style/Widget.Button"` – maxcanna Jan 06 '14 at 16:12
  • @maxcanna For some reason adding `parent` didn't change a bit. So I just went ahead with the `inflate` solution. – Aleks N. Jan 06 '14 at 16:58
  • 11
    @AliakseiN. You need to use the 3-arg constructor, e.g. `new Button(new ContextThemeWrapper(context, R.style.TabButton), null, 0)`. Otherwise, the default button style will be applied, and this style will override the button style that you've merged into the theme via the ContextThemeWrapper. – Newtonx Feb 09 '15 at 18:51
  • Using this solution combined with a flow layout and setting a shape drawable in the style, the margin setting for the @style was not being recognized. I was using this first, but after adding the shape drawable to the style, I had to go with the accepted answer - inflating a designated xml file that uses the style. – Gene Bo Nov 21 '16 at 01:43
  • Funnily enough with spinners it sets the style to each individual drop down item instead of the spinner itself, which could be handy for someone creating spinners programatically but not what I was going for – Rowan Berry Dec 19 '19 at 00:54
18

You can set the style in the constructor (but styles can not be dynamically changed/set).

View(Context, AttributeSet, int) (the int is an attribute in the current theme that contains a reference to a style)

Answer from Romain Guy

reference

Dandre Allison
  • 5,975
  • 5
  • 42
  • 56
  • your answer is misleading - have you tried reading this thread to the end? – andr Mar 14 '13 at 01:13
  • 4
    How is it mislead? The accepted answer is misleading, because Romain Guy explicitly says that you can "set" a style programmatically. There just isn't a facility to change it dynamically. This thread doesn't seem to think that is the case though. – Dandre Allison Mar 14 '13 at 22:33
  • 1
    Beware, this call requires API level 11. – Martin Capodici Jun 21 '14 at 03:58
  • please add quotes to the answer – Paul Verest Oct 24 '14 at 06:02
  • 1
    @PaulVerest it isn't a quote. – Dandre Allison Oct 26 '14 at 03:06
  • @MartinCapodici don't know what you mean about a call requiring API level 11. http://developer.android.com/reference/android/view/View.html#View(android.content.Context, android.util.AttributeSet, int) has been around since API level 1. – Dandre Allison Oct 26 '14 at 03:09
  • Stackoverflow says answer is not sharing links, but should include enough information from referenced resource. Users are not to read link to judge if answer if the best. – Paul Verest Oct 27 '14 at 02:12
  • 6
    The last int is *not* a style resource. It is "An attribute in the current theme that contains a reference to a style resource that supplies default values for the view." – rve Jan 15 '15 at 11:11
  • @rve thanks, you're correct. I updated the description as such – Dandre Allison Feb 10 '20 at 02:03
15

Parameter int defStyleAttr does not specifies the style. From the Android documentation:

defStyleAttr - An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.

To setup the style in View constructor we have 2 possible solutions:

  1. With use of ContextThemeWrapper:

    ContextThemeWrapper wrappedContext = new ContextThemeWrapper(yourContext, R.style.your_style);
    TextView textView = new TextView(wrappedContext, null, 0);
    
  2. With four-argument constructor (available starting from LOLLIPOP):

    TextView textView = new TextView(yourContext, null, 0, R.style.your_style);
    

Key thing for both solutions - defStyleAttr parameter should be 0 to apply our style to the view.

DmitryArc
  • 4,757
  • 2
  • 37
  • 42
5

Dynamically changing styles is not supported (yet). You have to set the style before the view gets created, via XML.

Chris Cashwell
  • 22,308
  • 13
  • 63
  • 94
  • 22
    which happens to be the same thing, actually – njzk2 Jan 04 '12 at 17:35
  • @njzk2 thanks... obviously didn't think about his comment before posting. There's no way to set style programmatically prior to the UI being built, thus the same code would be used to change or set the style programmatically. – Chris Cashwell Jan 05 '12 at 14:18
3

When using custom views that may use style inheritance (or event styleable attributes), you have to modify the second constructor in order not to lose the style. This worked for me, without needing to use setTextAppearence():

public CustomView(Context context, AttributeSet attrs) {
    this(context, attrs, attrs.getStyleAttribute());
}
saiyancoder
  • 1,285
  • 2
  • 13
  • 20
3

The accepted answer was great solution for me. The only thing to add is about inflate() method.

In accepted answer all android:layout_* parameters will not be applied.

The reason is no way to adjust it, cause null was passed as ViewGroup parent.

You can use it like this:

View view = inflater.inflate(R.layout.view, parent, false);

and the parent is the ViewGroup, from where you like to adjust android:layout_*.

In this case, all relative properties will be set.

Hope it'll be useful for someone.

Anor
  • 1,110
  • 13
  • 14
3

I met the problem too, and I found the way to set style programatically. Maybe you all need it, So I update there.

The third param of View constructor accepts a type of attr in your theme as the source code below:

public TextView(Context context, AttributeSet attrs) {
    this(context, attrs, com.android.internal.R.attr.textViewStyle);
}

So you must pass a type of R.attr.** rather than R.style.**

In my codes, I did following steps:

First, customize a customized attr to be used by themes in attr.xml.

<attr name="radio_button_style" format="reference" />

Second, specific your style in your used theme in style.xml.

 <style name="AppTheme" parent="android:Theme.Translucent">
    <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    <item name="radio_button_style">@style/radioButtonStyle</item>
</style>
<style name="radioButtonStyle" parent="@android:style/Widget.CompoundButton.RadioButton">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">64dp</item>
    <item name="android:background">#000</item>
    <item name="android:button">@null</item>
    <item name="android:gravity">center</item>
    <item name="android:saveEnabled">false</item>
    <item name="android:textColor">@drawable/option_text_color</item>
    <item name="android:textSize">9sp</item>
</style>

At the end, use it!

            RadioButton radioButton = new RadioButton(mContext, null, R.attr.radio_button_style);

the view created programatically will use the specified style in your theme.

You can have a try, and hope it can work for you perfectly.

mrtwo
  • 83
  • 1
  • 8
3

We can use TextViewCompact.setTextAppearance(textView, R.style.xyz).

Android doc for reference.

Kshitij Jain
  • 549
  • 6
  • 12
3
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
    textView.setTextAppearance(R.style.yourStyle)
Braian Coronel
  • 22,105
  • 4
  • 57
  • 62
1

you can use Extension Functions kotlin

fun TextView.setStyle(@StyleRes resId: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        setTextAppearance(resId)
    } else {
        setTextAppearance(context, resId)
    }
}
-1

I have only tested with EditText but you can use the method

public void setBackgroundResource (int resid)

to apply a style defined in an XML file.

Sine this method belongs to View I believe it will work with any UI element.

regards.

floydaddict
  • 1,147
  • 1
  • 7
  • 5
  • 1
    According to [the documentation](http://developer.android.com/reference/android/view/View.html#setBackgroundResource(int)) this should only work with drawables, not with style. Thus, if this really works, it's only "by accident" and you should not rely on it. – Heinzi Sep 14 '12 at 13:51