Search code examples
androidxmlandroid-custom-viewdeclare-styleable

Custom views and defStyleAttr


I'm struggling with custom views defStyleAttr. (Short note I'm using a Preference as example cause it's the same way Google uses it)

So for almost every View or Preference that is provided by Android you'll have a constructor like this:

public SeekBarPreference(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.seekBarPreferenceStyle);
}

This defines the default style attribute to be R.attr.seekBarPreferenceStyle.

If you now look into the definition you'll find this:

<attr name="seekBarPreferenceStyle" format="reference" />

Until now everything is clear. But this attribute is somehow linked to a theme:

<resources>
    <style name="PreferenceThemeOverlay">
        <!-- ... -->
        <item name="seekBarPreferenceStyle">@style/Preference.SeekBarPreference.Material</item>
        <!-- ... -->
    </style>
    <!-- ... -->
</resources>

Which then finally links a style with the needed layout resource id that will be handed over to the super class to be inflated:

<style name="Preference.SeekBarPreference.Material">
        <item name="android:layout">@layout/preference_widget_seekbar_material</item>
        <!-- ... -->
</style>

Unfortunately I wasn't able to find a hint on how the theme PreferenceThemeOverlay is linked to the attribute seekBarPreferenceStyle.

So how are these two linked?


Solution

  • I finally found an answer that explained the basics you need to know.

    Custom View

    For the examples I use SeekBarPreference as a custom object (Preference and View are very similar)

    So in short there are two ways to set your default style.

    Either set a custom theme to your activity (or the like) that links something to your custom style (seekBarPreferenceStyle) or set the style directly by the style XML attribute.

    Theme

    styles.xml

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="seekBarPreferenceStyle">@style/LINK_TO_DEFINING_STYLE</item>
    </style>
    

    AndroidManifest.xml

    <activity android:name=".SomeActivity" android:theme="@style/AppTheme">
    

    Style attribute

    some.xml

    <SeekBarPreference
    [...]
    style="@style/LINK_TO_DEFINING_STYLE"
    [...] />
    

    Androids Way

    But I wanted to know exactly how all of it is connected to then work without any style attributes in XML files for SeekBarPreference or other Preference and View objects provided by Android.

    So (via Android Studio) I followed Theme.AppCompat.Light.DarkActionBar down to its parent Theme.Holo.Light and look what I found there:

    <!-- ... -->
    <item name="seekBarPreferenceStyle">@style/Preference.Holo.SeekBarPreference</item>
    <!-- ... -->
    

    Linking to this style which links the layout resource:

    <style name="Preference.Holo.SeekBarPreference">
        <item name="layout">@layout/preference_widget_seekbar</item>
    </style>
    

    And to finally bring some more confusion to you again, Android seems to link a the Material style from the question instead of the Holo theme from the answer to the default theme (be it DeviceDefault or something else).

    So if you got any clue on this please feel free to add to the comments :)