Casebash
Casebash

Reputation: 118762

Creating an Android View with a particular style programmatically

Other questions say that the style cannot be set programmatically, but a View can be initialised with a style such as when it is loaded from XML.

How can I initialise a View with a particular style programmaticly (not in XML)? I tried using View(Context context, AttributeSet attrs, int defStyle), but I don't know what to parse in for the second argument. Passing in null results in the View not being displayed

Upvotes: 15

Views: 17298

Answers (3)

Giorgio Barchiesi
Giorgio Barchiesi

Reputation: 6157

I'm having the same problem, but haven't found any practical way to directly set a style programmatically, so far. I would like to populate my screen with a lot of widgets, of a given type, let's say buttons. It is impractical to define them all in the layout file. I would like to create them programmatically, but I would also like to define their style in a style xml file.

The solution I have devised consists in defining just one of those widgets in the layout file, create all the others programmatically, and clone the style info from the first one to the other ones.

An example follows.

In the style file, define the style for your buttons. For example:

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

Then subclass class "Button", by deriving a class "NiceButton". Define the constructor that will be needed by the inflater:

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

Then define another constructor, which purpose is to clone an existing button:

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
}

In your layout file, define just the first one of your buttons. Suppose for example that you want to put your buttons in a table:

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

Notice that the full qualified name of the widget class is used; obviously, you will have to replace com.mydomain.mypackage with the actual package name.

In your activity, you may want to define an array which is going to hold a reference to all of the buttons, and a common listener to be called when any of the buttons is pressed:

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

Notice how the view id is used as an index in the array of buttons. So you will need your buttons to have an id from 0 to n-1.

Finally, here is the way you can create your buttons in the onCreate method:

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

Here's how the screen appears after you have pressed some buttons: enter image description here

Well, there's some code involved, but in the end you can create as many widgets you want programmatically, and still have their attributes defined as a style.

Upvotes: 13

beetstra
beetstra

Reputation: 7952

If you want to style a view you have 2 choices: the simplest one is to just specify all the elements in code:

button.setTextColor(Color.RED);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);

The other option is to define the style in XML, and apply it to the view. In the general case, you can use a ContextThemeWrapper for this:

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

To change the text-related attributes on a TextView (or its subclasses like Button) there is a special method:

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

This last one cannot be used to change all attributes; for example to change padding you need to use a ContextThemeWrapper. But for text color, size, etc. you can use setTextAppearance.

Upvotes: 10

Karan
Karan

Reputation: 12782

AttributeSet contains the list of attributes specified in xml (ex. layout_width, layout_height etc).

If you are passing it as null, then you should explicitly set the height/width of view.

Upvotes: 5

Related Questions