【问题标题】:How to programmatically create/initialise a Button with a custom style?如何以编程方式创建/初始化具有自定义样式的按钮?
【发布时间】:2014-08-07 09:14:22
【问题描述】:

我正在尝试以编程方式创建一些按钮以将它们添加到现有的 ViewGroup。这工作正常,但我无法用正确的样式初始化按钮。

我知道,一旦创建了视图样式,就不可能设置/更改。但到目前为止我发现的所有解决方案都说,创建具有自定义样式的视图应该没有问题(我认为从 API 级别 11 开始,我正在使用 14+):

Button button = new Button (getActivity(), null, R.style.MyButtonStyle);

唯一的效果是,按钮是在没有任何样式的情况下创建的。没有背景,所以选择器,没有边距/填充,只是纯文本。我认为 MyButtonStyle 会被破坏,但是使用 MyButtonStyle 在 XML 中创建按钮没问题。

为什么这不起作用?

【问题讨论】:

标签: android button user-interface styles


【解决方案1】:

我终于找到了解决办法!问题是,为什么以下方法不起作用:

Button button = new Button (getActivity(), null, R.style.MyButtonStyle);

事实证明,问题在于使用的是 R.style.xxx 而不是 R.attr.xxx。似乎这是View(Context context, AttributeSet attrs, int defStyleAttr) 实现中的bug 或至少在此构造函数的文档中:第三个参数必须是 R.attr 构造函数才能正常工作并正确应用样式。

因此,为了让构造函数工作,必须向/res/values/attr.xml/res/values/styles.xml 添加更多代码:

<!-- /res/values/attr.xml -->
<declare-styleable name="AppTheme">
    <attr name="specialButtonStyle" format="reference"/>
</declare-styleable>


<!-- /res/values/styles.xml -->
<style name="AppTheme" parent="AppBaseTheme">
    ...
    <item name="specialButtonStyle">@style/MyButtonStyle</item>
</style>

<style name="MyButtonStyle" parent="@android:style/Widget.Button">
    ...
</style>


// In Java we can now use R.attr.specialButtonStyle instead of R.style.MyButtonStyle
// getActivity() is used because I am working in a Fragment. Within an
// Activity this can be used instead...
Button button = new Button(getActivity(), null, R.attr.specialButtonStyle);

这很烦人,文档没有更新关于这个问题。早在 2011 年就提交了有关此问题的第一个错误报告...

还必须编写一些额外的代码才能运行此解决方案,该解决方案比通常建议的扩展 XML 布局要快得多(从我的角度来看)要好得多。

【讨论】:

  • 感谢您找到这个!我只想添加另一个注释,说明正在使用 attr 的项目必须与定义 attr 的项目相同。我遇到了一个问题,我在依赖库项目中定义了 attr,但它仍然无法正常工作。我通过将 attr 移动到我的应用程序的项目资源中并让它引用仍在库中的样式来修复它。
【解决方案2】:

您可能可以通过使用ContextThemeWrapper 来实现这一点

ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.MyButtonStyle);
Button = new Button(ctw);

编辑:

我刚刚检查了源代码,您的代码(我猜是我的代码)不起作用的原因现在很清楚了。

public View(Context context, AttributeSet attrs, int defStyleAttr) {
    this(context);
    TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View,
            defStyleAttr, 0);

attrs 为 null,TypedArray 没有任何值可供使用。

我之前用于对话框的代码,我认为它可以工作。

您可以在View source code上查看。

因此,如果您在构造函数上传递AttributeSet,那么可能应该起作用的更新答案。我不知道该怎么做,但是查看文档 (HERE) 你可能可以这样做:

// the docs says `myResource` so probably the style ID
XmlPullParser parser = resources.getXml(R.style.MyButtonStyle); 
AttributeSet attributes = Xml.asAttributeSet(parser);
Button button = new Button (getActivity(), attributes, R.style.MyButtonStyle);

【讨论】:

  • 谢谢,但这也不起作用。如果我使用这种方法,按钮会以默认样式显示 = 使用的样式简单 new Button() 被使用。
  • 我无法运行它。在此示例中,resources 是什么?使用Resources.getSystem() 不起作用并导致android.content.res.Resources$NotFoundException。我不确定使用Resources.getSystem() 是问题还是使用R.style.MyButtonStyle 作为参数不正确。你能得到这个工作吗?但是我不确定这是否真的是问题的根源。如果View(Context context, AttributeSet attrs, int defStyleAttr) 将使用除 null 之外的其他内容作为 attrs,如果使用 null,它会抛出异常,不是吗?
  • 我找到了问题的解决方案并将其添加为答案。
  • 资源是getActivity().getResources()
【解决方案3】:

我不太确定它为什么不起作用。但是想分享我的答案,这有助于我拥有自定义样式按钮。

在您的活动中,包括以下内容:

Button btnMyCustomButton = (Button) findViewById(R.id.myTestButton);

在您的布局 xml 文件中,包括以下内容:

<Button
        android:id="@+id/myTestButton"
        android:background="@drawable/my_custom_button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center|bottom"
        android:layout_marginBottom="30dp"
        style="@style/my_custom_button_text"/>   

在您的可绘制文件夹中,创建 my_custom_button.xml 并包括以下示例:

    <?xml version="1.0" encoding="utf-8" ?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
    <shape>
      <solid
          android:color="#35adad" />
      <stroke
          android:width="1dp"
          android:color="#2f9999" />
      <corners
          android:radius="6dp" />
      <padding
          android:left="10dp"
          android:top="10dp"
          android:right="10dp"
          android:bottom="10dp" />
    </shape>
  </item>
  <item>
    <shape>
      <gradient
          android:startColor="#35adad"
          android:endColor="#2f9999"
          android:angle="270" />
      <stroke
          android:width="1dp"
          android:color="#2f9999" />
      <corners
          android:radius="6dp" />
      <padding
          android:left="10dp"
          android:top="10dp"
          android:right="10dp"
          android:bottom="10dp" />
    </shape>
    </item>
    </selector>

您还可以在 style.xml 中包含以下内容,以便自定义按钮文本。

<style name="my_custom_button_text" >
        <item name="android:layout_width" >fill_parent</item>
        <item name="android:layout_height" >wrap_content</item>
        <item name="android:textColor" >#ffffff</item>
        <item name="android:gravity" >center</item>
        <item name="android:layout_margin" >3dp</item>
        <item name="android:textSize" >30sp</item>
        <item name="android:textStyle" >bold</item>
        <item name="android:shadowColor" >#000000</item>
        <item name="android:shadowDx" >1</item>
        <item name="android:shadowDy" >1</item>
        <item name="android:shadowRadius" >2</item>
    </style>

【讨论】:

  • 谢谢,但是一般来说按钮的样式是没有问题的。问题是如何将样式应用于在代码中创建的按钮。
【解决方案4】:

你可以这样做。 首先在项目的res/drawable 文件夹中创建一个具有自定义样式的xml 文件。 (比如 buttonstyle.xml)。那么,

Button btn = new Button(this); btn.setText("Test Example"); btn.setId(R.string.btn_name); btn.setBackground(R.drawable.buttonstyle);

希望对你有所帮助。

【讨论】:

  • 如果样式不仅影响背景,还影响边距、内边距、文本样式等怎么办?
猜你喜欢
  • 2017-12-06
  • 2018-01-14
  • 1970-01-01
  • 2015-02-04
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多