Android appCompat themes vs Base themes - android

Wha's the difference between the Android Theme.AppCompat and Base.Theme.AppCompat?
When should we use the Base theme?
<style name="flatButton" parent="Base.Widget.AppCompat.Button.Borderless">
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="flatButton2" parent="Widget.AppCompat.Button.Borderless">
<item name="colorAccent">#color/colorAccent</item>
</style>

You shouldn't use the Base theme at all - always use the standard themes. The Base themes are used internally to AppCompat and serve as a common base that applies to all API levels - it does not include the API level specific changes that are needed to properly function (something only the standard themes supply).

Related

Changing background colour of activities themed using the AppCompat themes in older Android versions

I am using the following theme for my application:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
I would like to change the background colour. In order to do so, according to the documentation I can add the following to the theme definition:
<item name="windowBackground">#color/windowBackground</item>
Unfortunately, however, this only compiles correctly if (as suggested in the answer at No resource found that matches the given name: attr 'windowBackground') I restrict it to being applied to Android versions with API 21 or higher.
How I can I make this work on earlier versions of Android? I would ideally like to specify a background colour for Android versions down to API 16, which is my current minimum.
That's true as you said that windowBackground so you will just need to replace it with android:windowBackground that is for API 14 and higher
You need to add
<item name="android:windowBackground">#color/window_background</item>
to ../values-v21/styles.xml
// Your Problem is that You are use Theme.Appcompat then extends ActionBarActivity
if you use AppcompatActivity then use
<style name="MyTheme" parent="Theme.AppCompat.Light">
<item name="android:windowBackground">#color/colorAccent</item>
</style>

Why and when we need to add android: prefix to style?

I have seen that some Style attributes require android prefix and some don't need it. What is the reason. like
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
Why we haven't use android:windowActionBar and android:windowNoTitle
Based on SDK version Android styles are grouped in different namespaces. In order to override a Theme you have to follow it's namespace.
That's the reason you don't need the android: prefix when extending an AppCompat Theme, but if you wanted something else, let's say Theme.Holo - you'd have 2 different styles for the them - one for pre-Lollipop devices, and one for -21, the latter having the android: prefix before each style attribute.
It depends on which Themes you're using and which context it is. These attributes are defined by different sources.
If the attribute name is prefixed with android:, it's a framework attribute and can only be used for the Android versions having it defined.
If the attribute is not prefixed at all, the attributes are defined by your own application. This includes all attribute definitions you pulled in with libraries.
In your example you're defining a theme for AppCompat which is part of the support library and thus of your application. The framework widgets won't recognize these colors directly.

Is this the correct way to have different values/styles for different versions

Android Studio 2.1 preview 3
This is just a question, as I am confused as I have seen many alternatives in doing this.
I have created a new android project and my Activity extends AppCompatActivity
public class MainActivity extends AppCompatActivity {
I want to have the transparent statusbar on devices running 21 and over.
So in my values/styles I have the following
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
</resources>
And in my values-21/styles I have the following
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<!-- Make the statusbar transparent -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
My Manifest I select the theme
android:theme="#style/AppTheme"
Just some questions
Is this the correct way, or is there any better way to do this?
Would values-21/styles inherit all the colors in values/styles so I would have to repeat this?
It's the right way. May I suggest you to organize your style better?
values/styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="CommonTheme">
</style>
<style name="CommonTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
</resources>
values-v21/styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="CommonTheme">
<!-- All customization of the theme for this version -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
So you don't need to repeat the common values of the style for every api level.
I will try to answer it giving some references
Maintaining Compatibility
To avoid duplication of code, define your styles inside res/values/,
modify the styles in res/values-v21/ for the new APIs, and use style
inheritance, defining base styles in res/values/ and inheriting from
those in res/values-v21/
So you should try to avoid code duplication in your style.xml at different folders res/values/ and res/values-v21/ by using style inheritance.
Style Inheritence
If you want to inherit from styles that you've defined yourself, you
do not have to use the parent attribute. Instead, just prefix the name
of the style you want to inherit to the name of your new style,
separated by a period.
If you want to inherit a style that you've defined yourself you can skip adding a parent attribute and inherit from it using a dot or period notation.
With this, you can define a base theme BaseTheme in res/values/ with different colors and inherit from it as BaseTheme.StyledStatusBar without specifying a parent attribute.
<resources>
<style name="BaseTheme.StyledStatusBar"></style>
<!-- Base application theme. -->
<style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
</resources>
In values-21/, add item android:windowTranslucentStatus to BaseTheme.StyledStatusBar
<resources>
<style name="BaseTheme.StyledStatusBar">
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
In manifest, select the theme
android:theme="#style/BaseTheme.StyledStatusBar"
1) Is this the correct way, or is there any better way to do this?
Yes. That's the correct/recommended way of having different values for different API versions.
2) Would values21/styles inherit all the colors in values/styles so I would have to repeat this?
I'm not sure I fully follow this question. Both styles you showed will inherit from Theme.AppCompat.Light.NoActionBar so your colors should be declared again, but I'll present two better alternatives:
Alternative 1, a little bit better:
Use a BaseTheme that is common for both. To view the code for it, please check #mimmo-grottoli answer.
Alternative 2, much better:
If the only different on the two themes is the android:windowTranslucentStatus that was introduced in KitKat (API level 19), you can put it all in the same theme in values/styles, like the following:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<!-- Make the statusbar transparent -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
The Android Framework ignores XML parameters that it does not recognize. That means that on JellyBean or ICS, the device will ignore windowTranslucentStatus while correctly applying the colors and in KitKat and up, it will correctly apply windowTranslucentStatus.
That tricky is valid for all XML in Android (even layouts), the IDE might give you warnings about API level, but in XML they're always safe to use.
Different folders of values/styles are made to give a unique style when your app is running on a specific version of Android.
So yes you are right when saying that the newer version inherits from the older one. When adding items in your latest version of styles you keep the latest version up to date to the latest APIs.
To conclude, your way is the very commun way, it's an organized and a clean way to keep your app updated.
Is this the correct way, or is there any better way to do this?
Yes. That's the right way of having different values for different API versions.
Would values-21/styles inherit all the colors in values/styles so I would have to repeat this?
Yes
technically <item name="android:windowTranslucentStatus">true</item> won't give you fully transparent statusbar.
If you want it to by fully transparent, you can use <item name="android:statusBarColor">#android:color/transparent</item>

Repeating style in v19/v21

I have this in my styles.xml:
<style name="UserTheme" parent="ThemeBase">
<item name="android:editTextStyle">#style/EditTextTheme</item>
</style>
Why do I have to repeat the editTextStyle line in v19/styles.xml and v21/styles.xml.
v21/styles.xml:
<style name="UserTheme" parent="ThemeBase">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:editTextStyle">#style/EditTextTheme</item>
</style>
Is there a way to just call it in the main styles.xml and have it apply everywhere so I don't have to write it multiple times?
I couldn't find any recommended solution so I i digged into AppCompat source. The way they do it is like this.
In your styles.xml
<style name="Base.V7.Theme.YourThemeName" parent="Theme.AppCompat.Light.NoActionBar">
</style>
<style name="Base.Theme.YourThemeName" parent="Base.V7.Theme.YourThemeName" />
<style name="Theme.YourThemeName" parent="Base.Theme.YourThemeName" >
<item name="colorPrimary">#color/primary</item>
<item name="colorPrimaryDark">#color/primary_dark</item>
<item name="colorAccent">#color/accent</item>
</style>
In your styles-v21.xml
<style name="Base.V21.Theme.YourThemeName" parent="Base.V7.Theme.YourThemeName">
<item name="android:navigationBarColor">#color/white</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
<style name="Base.Theme.YourThemeName" parent="Base.V21.Theme.YourThemeName" />
In your styles-v22.xml
<style name="Base.V22.Theme.YourThemeName" parent="Base.V21.Theme.YourThemeName">
<item name="android:navigationBarColor">#color/black</item>
<item name="android:windowTranslucentStatus">false</item>
</style>
<style name="Base.Theme.YourThemeName" parent="Base.V22.Theme.YourThemeName" />
For every new version you extend the previous base version. If you want to override any attribute for different version just put it inside Base.VXX.Theme.YourThemeName block on your new styles-vXX.xml file.
Why do I have to repeat the editTextStyle line in v19/styles.xml and
v21/styles.xml?
If you've applied some STYLE to some attribute, Android will search styles.xml file for highest api level for which file_api_level<=Android_device_api_level and searches for STYLE in it. If it finds it would apply that STYLE to view otherwise will continue searching for the STYLE in lower api level files.
e.g. - If you have four files styles.xml(default), v19/styles.xml, v21/styles.xml, v25/styles.xml and your devices is running on api level 24. Then it'll search for STYLE in v21/styles.xml first, then v19/styles.xml and finally in styles.xml(default). Only first occurrence of the STYLE will get applied. So you can't just define only extra attributes in version-specific styles.xml file.
If you don't want to repeat common attributes here is an alternate. To declare window transitions for Android 5.0 (API level 21) and higher, you need to use some new attributes. So your base theme in res/values/styles.xml could look like this:
<resources>
<!-- base set of styles that apply to all versions -->
<style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">#color/primaryColor</item>
<item name="colorPrimaryDark">#color/primaryTextColor</item>
<item name="colorAccent">#color/secondaryColor</item>
</style>
<!-- declare the theme name that's actually applied in the manifest file -->
<style name="AppTheme" parent="BaseAppTheme" />
</resources>
Then add the version-specific styles in res/values-v21/styles.xml as follows:
<resources>
<!-- extend the base theme to add styles available only with API level 21+ -->
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowEnterTransition">#android:transition/slide_right</item>
<item name="android:windowExitTransition">#android:transition/slide_left</item>
</style>
Now you can apply AppTheme in your manifest file and the system selects the styles available for each system version.
Is there a way to just call it in the main styles.xml and have it
apply everywhere so I don't have to write it multiple times?
Yes, there is a way in which you can maintain only one styles.xml file.
First of all, start using AppCompat themes. They provide backward compatibility and will work for older android versions as well.
Now define all of your styles in styles.xml(default) file and if your Android Studio is showing you some warning/error for some attribute which is supported in higher level apis:
You can suppress that warning using: tools:targetApi="SupportedAndroidVersionName"
Now Android will ignore that particular attribute if it's not supported and your whole style will work perfectly for both lower and higher api levels.
Read more about Styles and Themes here.
Hope it helps :)
Newer versions of Android have additional themes available to applications, and you might want to use these while running on those platforms while still being compatible with older versions. You can accomplish this through a custom theme that uses resource selection to switch between different parent themes, based on the platform version.
Why do I have to repeat the editTextStyle line in v19/styles.xml and
v21/styles.xml?
Because if your app is running on v21, v21/styles.xml will be loaded and if running on v19, v19/styles.xml will be loaded. In case you don't have v21/styles.xml or v19/styles.xml the app will automatically use your default values/styles.xml but you wont be able to take advantage of new features provide only for v21 or v19.
For more reference you can read Supporting Different Devices and Select a theme based on platform version.

Android actionbar style ignored by later devices, using appcompat v7

I am using the Action Bar support library (appcompat v7), my app is set to a minimum api of 7, and a target of 21.
I have two styles files, a base one, and one targeted at devices api 11+.
When running the app on a device running KitKat, it seems that android:actionBarStyle is ignored, leaving the action bar styled as default (#style/Widget.AppCompat.ActionBar.Solid), instead of applying the given background.
But if I remove my v11 styles/comment them out, KitKat listens to the actionBarStyle attribute set in the base styles.xml file and sets my custom background without any problems.
So my question, where am I going wrong with the v11 styles?
From what I understand, according to the android docs, you are supposed to supply the additional styles for devices running 11+ using the android: prefix, but this just doesn't seem to be working for me.
Stripped down, this is my /res/values/styles.xml file:
<style name="My.Theme" parent="#style/Theme.AppCompat">
<item name="actionBarStyle">#style/ActionBar.Solid</item>
</style>
<style name="ActionBar.Solid" parent="#style/Widget.AppCompat.ActionBar.Solid">
<item name="background">#drawable/ab_solid_</item>
</style>
and this is my /res/values-v11/styles.xml file:
<style name="My.Theme" parent="#style/Theme.AppCompat">
<item name="android:actionBarStyle">#style/ActionBar.Solid</item>
</style>
<style name="ActionBar.Solid" parent="#style/Widget.AppCompat.ActionBar.Solid">
<item name="android:background">#drawable/ab_solid_</item>
</style>
as you can see, the only difference between the two is the use of the android: prefix.
According to the official doc, with the new AppCompat-v21, you can remove all of values-v14+ Action Bar styles and use only one theme declaration, in values:
<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
<!-- Set AppCompat’s actionBarStyle -->
<item name="actionBarStyle">#style/MyActionBarStyle</item>
</style>

Categories

Resources