Android – Creating an Android View with a particular style programmatically

android

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

Best Answer

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.