Thomas Keller
Thomas Keller

Reputation: 6060

Apply built-in Android widget styles in a custom view

I have read and understood https://stackoverflow.com/a/5052401/305532, however what I want is not to generally style and override individual widget styles, but styles that are part of sub-widgets.

Say, I have a compound RelativeLayout that consists of a standard EditText and a standard Button. I could override android:buttonStyle to style this Button, but what I really want is

<my.custom.Widget
  ...
  pkg:buttonStyle="@style/CustomStyle" />

where the CustomStyle could derive from android:style/Widget.Button, but would be changeable for each instance of my.custom.Widget because of pkg:buttonStyle.

The only alternative I know is to add all styleable attributes individually into my attrs.xml (with the usual conflicts in case two or more of your sub-widgets need the same attribute, but with different values) and then manually copying / setting all these attributes in my.custom.Widget's constructor / init method.

Is there a way to achieve this?

Upvotes: 2

Views: 2617

Answers (2)

Jarett Millard
Jarett Millard

Reputation: 5958

Unfortunately, this doesn't seem to be possible. The only example I could find that does something similar is ActionBar: you can pass in styles for the title, subtitle, and progress indicators. Looking at the source for ActionBarView, the title and subtitle TextViews' styles are applied with setTextAppearance(). The ProgressBar class has an extra constructor that accepts a fourth parameter for the style. Since most View classes don't have this extra constructor, passing in a style to them is not possible. However, there are a few alternatives:

  1. Pass a layout for the subview instead of a style and inflate it in your widget.
  2. If the subview is a child of TextView (as Button and EditText are), use setTextAppearance() for the passed style. This will apply a good bit of the styling for text. If you want to allow the user to apply other styles like background or padding, you will still need to add custom attributes for each of those as well. If you're making a compound widget there's a good chance that the user won't need to apply every possible style to the subviews, so only exposing a subset will probably suffice.
  3. Add a theme-wide style, as you already mentioned.

Upvotes: 2

Austyn Mahoney
Austyn Mahoney

Reputation: 11408

Using Built-in Widget Styles in a Custom View

If you create a custom view that is a subclass of an Android widget and want to style it with the built-in Android widget styles, then you must implement the following structure.


Change your custom View to inherit its attributes from an Android Widget style

CustomTextView.java

public class CustomTextView extends TextView {
    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
                R.styleable.CustomTextView, R.attr.customImageButtonStyle, 0);
        String fontName = styledAttrs.getString(
                R.styleable.CustomTextView_customTypeface);
        styledAttrs.recycle();

        // Use custom attribute to do something...
    }
}

The defStyleAttr parameter of Context#obtainStyledAttributes() is where you specify the reference to the style you want to inherit. In this example, you use R.attr.customImageButtonStyle. You define these resources in themes.xml and styles.xml.

themes.xml

<resources>
    <style name="AppTheme">
        <!--Define a theme-wide customTextViewStyle -->
        <item name="customTextViewStyle">@style/Widget.TextView</item>
    </style>
</resources>

styles.xml

<resources>
    <style name="Widget.TextView"
        parent="@android:style/Widget.TextView">
        <item name="customTypeface">custom_font_typeface</item>
    </style>
</resources>

attrs.xml

<resources>
    <declare-styleable name="CustomTextView">
        <attr name="customTypeface" format="string" />
    </declare-styleable>
    <declare-styleable name="CustomTheme">
        <attr name="customTextViewStyle" format="reference"/>
    </declare-styleable>
</resources>

*activity_layout*

<com.packagename.ui.view.CustomTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Bacon ipsum" />

CustomTextView no longer requires you to define a style or customTypeface attribute, it is already defined in the theme-wide customTextViewStyle in themes.xml.

Upvotes: 1

Related Questions