以编程方式创建具有特定样式的Android视图

15

其他问题指出风格不能以程序方式设置,但是View可使用样式进行初始化,例如在从XML加载时。

如何以编程方式初始化View的特定样式(不在XML中)?我尝试过使用View(Context context,AttributeSet attrs, int defStyle),但我不知道要解析什么作为第二个参数。传递null会导致View未显示。

3个回答

13

我遇到了同样的问题,但是迄今没有找到任何直接以编程方式设置样式的实用方法。我想用给定类型的大量小部件填充屏幕,比如按钮。在布局文件中定义所有这些小部件是不切实际的。我想以编程方式创建它们,但我也想在样式xml文件中定义它们的样式。

我设计的解决方案是在布局文件中仅定义一个小部件,然后以编程方式创建所有其他小部件,并将样式信息从第一个小部件克隆到其他小部件。

以下是一个示例。

在样式文件中,定义按钮的样式。例如:

<style name="niceButton">
    <item name="android:layout_width">160dip</item>
    <item name="android:layout_height">60dip</item>
    <item name="android:gravity">center</item>
    <item name="android:textSize">18dip</item>
    <item name="android:textColor">#000000</item>
</style>

通过派生一个名为“NiceButton”的类,来子类化“Button”类。定义在填充器中所需的构造函数:

public NiceButton(Context context, AttributeSet attrs) {
    super(context, attrs);
}

然后定义另一个构造函数,其目的是克隆现有按钮:

public NiceButton(int id, NiceButton origButton) {
    super(origButton.getContext());
    setId(id);
    setLayoutParams(origButton.getLayoutParams());
    setGravity(origButton.getGravity());
    setPadding(origButton.getPaddingLeft(),
                    origButton.getPaddingTop(),
                    origButton.getPaddingRight(),
                    origButton.getPaddingBottom());
    setTextSize(TypedValue.COMPLEX_UNIT_PX, origButton.getTextSize());
    setTextColor(origButton.getTextColors());
    // ... also copy whatever other attributes you care about
}

在您的布局文件中,仅定义第一个按钮。例如,假设您想将按钮放在表格中:

<TableLayout android:id="@+id/button_table"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <TableRow android:id="@+id/button_row_0">
        <com.mydomain.mypackage.NiceButton
                    style="@style/niceButton" android:id="@+id/button_0" />
        <!-- More rows/buttons created programmatically -->
    </TableRow>

</TableLayout>

注意完整的小部件类名已被使用;显然,您将不得不使用实际包名称替换com.mydomain.mypackage

在您的活动中,您可能希望定义一个数组,该数组将保存对所有按钮的引用,并调用一个通用监听器,以处理任何按钮按下事件:

NiceButton[] mButtonViews = new NiceButton[10];

private View.OnClickListener mNiceButtonClickListener = new View.OnClickListener() {
    public void onClick(View view) {
        int i = view.getId();
        mButtonViews[i].setText("PRESSED!");
    }
};

注意视图ID如何在按钮数组中用作索引。因此,您的按钮需要具有从0到n-1的ID。

最后,在onCreate方法中创建按钮的方法如下:

    // Retrieve some elements from the layout
    TableLayout table = (TableLayout)findViewById(R.id.button_table);
    TableRow row = (TableRow)findViewById(R.id.button_row_0);
    NiceButton origButton = (NiceButton)findViewById(R.id.button_0);

    // Prepare button 0
    origButton.setId(0);
    origButton.setText("Button 0");
    origButton.setOnClickListener(mNiceButtonClickListener);
    mButtonViews[0] = origButton;

    // Create buttons 1 to 10
    for (int i = 1; i < 10; i++) {
        if (i % 2 == 0) {
            row = new TableRow(this);
            table.addView(row);
        }
        NiceButton button = new NiceButton(i, origButton);
        button.setText("Button " + i);
        button.setOnClickListener(mNiceButtonClickListener);
        mButtonViews[i] = button; 
        row.addView(button);
    }

在按下一些按钮之后,屏幕显示的方式如下所示: 输入图像描述

虽然牵涉到一些代码,但最终你可以以编程方式创建任意数量的小部件,并且仍然可以将它们的属性定义为样式。


10

如果你想对一个视图进行样式设置,有两种选择:最简单的一种是在代码中指定所有元素:

button.setTextColor(Color.RED);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
另外一种选择是在XML中定义样式并将其应用于视图。通常情况下,你可以使用ContextThemeWrapper来实现:

另外一种选择是在XML中定义样式,并将其应用于视图。通常情况下,您可以使用ContextThemeWrapper来实现:

ContextThemeWrapper newContext = new ContextThemeWrapper(baseContext, R.style.MyStyle);
button = new Button(newContext);

要更改TextView(或其子类,如Button)上的与文本相关的属性,需要使用特殊方法:

button.setTextAppearance(context, R.style.MyTextStyle);

最后一个方法无法用于更改所有属性;例如,要更改填充,您需要使用ContextThemeWrapper。但是对于文本颜色、大小等,您可以使用setTextAppearance。


最好、最简单的解决方案。谢谢。 - Steelight
setTextApperance() 需要 API 23。 - Paul Wintz
1
@PaulrBear,有两个版本,一个在API 1中添加并在23中弃用,另一个在23中添加。 - beetstra
啊,我明白了。感谢 @beetstra 指出这一点。在 API 23 之前,应该使用 setTextAppearance(context, R.style.MyTextStyle);在 API 23 及以后,则应该使用 setTextAppearance(R.style.MyTextStyle)。 - Paul Wintz

5

AttributeSet 包含在 xml 中指定的属性列表(例如 layout_width、layout_height 等)。

如果将其设置为 null,则应明确设置视图的高度/宽度。


2
AttributeSet似乎没有构造函数。是否可能在不使用XML的情况下构建它? - Casebash
据我所知,你不能在不使用xml的情况下构建AttributeSet。但是,你可以使用该类提供的函数来设置所有属性。 - Karan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接