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编程设置属性?


看到这里['response'] [1],这对我有用。[1]:stackoverflow.com/a/5488652/2938493
Artificioo

Answers:


211

从技术上讲,您可以通过编程方式应用样式,并始终使用自定义视图:

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

当您以编程方式实例化视图时,将使用一个参数构造函数。

因此,将此构造函数链接到采用样式参数的super。

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

或正如@Dori所简单指出的那样:

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

34
您可以以编程方式执行此操作而无需扩展,因为3 arg构造函数是公开的,无论如何developer.android.com/reference/android/widget / ...,android.util.AttributeSet,int)
Dori 2014年

1
@Turbo,文档和Eclipse都应该告诉您:http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int)。使用LinearLayout,要求级别为11+。
TheOne 2014年

2
@Dori您会通过什么AttributeSet
Blundell 2014年

9
如果是TextView,则需要对那些影响文本(大小,颜色等)的属性使用setTextAppearance(R.style.small_text)
Maragues

2
我不知道为什么第三参数方法不起作用。我申请了Button。@Benjamin Piette方法很好用。
Youngjae 2015年

124

对我有用的是:

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

  • 使用3个参数的构造函数(如果没有此函数将无法工作)

使用您的方法有效,但是我得到W / ResourceType:属性引用过多,停止于:0x01010034。任何解决方法?
HaloMediaz

我从来没有见过这个问题。这可能是特定于设备的问题,还是与最新的Android版本有关?
本杰明·皮耶特

11
重要!此方法确实有效,但是如果使用ContextThemeWrapper创建新的Layout,则还将为每个子视图设置样式。
aProperFox

@aProperFox您能解释得更好吗?和我一起工作时,只需添加一个按钮即可。您指的是布局?
吉利安

1
@Gilian确切地说,如果在具有一个或多个子级的复合视图上使用此样式,则它们将获得与为其设置样式的父级视图相同的样式。这可能会导致内部视图中出现过多的填充或边距,并且如果您不知道它,可能会使您发疯:)
aProperFox

88

更新:在回答此问题时(2012年中,API级别14-15),以编程方式设置视图是不可行的(即使有一些非常规的解决方法),但是在更新的API之后就可以实现发布。有关详细信息,请参见@Blundell的答案。

老答案:

您尚不能通过编程方式设置视图的样式,但是您可能会发现此线程很有用。


16
不对。请参阅@Blundell的答案。
a.bertucci 2014年

31
在某些情况下(例如使用TextView),您可以使用textView.setTextAppearance(context, R.style.mystyle);。根据doc“设置指定TextAppearance资源中的文本颜色,大小,样式,提示颜色和突出显示颜色。” developer.android.com/reference/android/widget/...,INT)
Rogel加西亚

4
api> 23; textView.setTextAppearance(R.style.mystyle);
阿利坎·阿乔尔

1
我在4年前@HaydenKai发布了此答案。自那时以来,API发生了很大变化,从而允许以编程方式应用样式。
Korhan Ozturk

3
@KorhanOzturk同意了,但是在这样的具有活动性的问题上,应该重新开放该问题并接受一个新的答案
HaydenKai 2016年

16

对于新的Button / 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(接受的答案不允许您这样做)并在创建视图后设置样式,则可以使用支持所有可用属性子集的Paris库。

由于要从XML扩展视图,因此需要在布局中指定一个ID:

<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年建议使用的方法吗?
IgorGanapolsky

1
@IgorGanapolsky afaik是的!我不知道有什么更好的。
Nathanael

感谢@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/SetStylableProgramatically找到完整的示例


13
这是不正确的风格,它只是一个应用/在你的浏览设置保存的设置(是的,它实际上是某种形式的设置保存在XML文件)(在这里你只有2个固定视图假- 你一定需要知道它们预先)。所有的魔力都在apply方法中,没有什么有趣的。样式的真正含义是它会在以后所有动态添加的视图中自动应用某种视觉样式。这里当然此代码不能做到这一点并没有什么这里充满活力,我们需要知道什么意见和的属性/字段集。
金王

1
我不介意指定将哪些样式应用于哪些视图,但是此解决方案具有硬编码的样式元素(例如,textColor和dividerColor)。它不会动态查找样式中定义的所有元素并将其应用于视图。
nasch

您发布的链接无法打开。你能重新发布吗?
IgorGanapolsky '19

4

这是一个很老的问题,但是现在对我有用的解决方案是使用构造函数的第4个参数defStyleRes-如果可用,则在视图上设置样式

以下是我的作品(kotlin):

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

关于如何使用此解决方案的更多说明会有所帮助。
IgorGanapolsky,

1

我不建议使用ContextThemeWrapper,因为它这样做:

指定的主题将应用于基础上下文主题的顶部。

什么会在您的应用程序中产生不良结果。相反,我建议Airbnb的工程师为此提供新的“ paris”库:

https://github.com/airbnb/paris

以编程方式定义样式并将其应用于Android视图。

但是在使用了一段时间后,我发现它实际上是非常有限的,我停止使用它,因为它不支持我需要立即可用的许多属性,因此必须像往常一样签出并做出决定。


解释你的票友吧...我输了一天半,因为我使用了ContextThemeWrapper,并将它应用于我的上下文主题白色背景,然后突然Google素材库中的Chip小部件崩溃了,猜猜为什么...
Renetik

巴黎图书馆不在下面使用ContextThemeWrapper吗?
IgorGanapolsky,

@IgorGanapolsky,事实并非如此。它读取XML样式并将其转换为视图上的相应方法调用。
Nathanael

它实际上非常有限,我停止使用它,因为它不支持我需要的许多属性...
Renetik

-1

我在复合ViewGroup中使用了XML中定义的视图,然后将它们夸大地添加到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
您在哪里动态设置样式?
IgorGanapolsky,

-3

您可以创建包含具有所需样式的布局的xml,然后像这样更改视图的背景资源。


您在谈论Android中的“样式”,但谈论按钮的“方面”。这是非常不同的。
基督
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.