Can i change accent color (AppCompat) programmatically? - android

I have:
<style name="AppTheme" parent="Theme.AppCompat">
<item name="colorAccent">#color/myColor</item>
</style>
But I want to allow the user to change the accent color. Can I do it with AppCompat?

No you can't, because the accent color is defined in the theme and themes are read-only in Android.
The only thing you can do is switch themes or set the color of each component manually.
Note: you can apply a theme to a portion of UI instead of the whole Activity in order to change the accent color (or other things) locally. To do so, you can use the android:theme attribute in your XML layout with the AppCompat library, or you can inflate a layout by providing a ContextThemeWrapper as context to your LayoutInflater.

Related

Change default TextInputLayout style?

I am using Material Design Components and want to change the default style of a TextInputLayout, meaning my changes shall apply to all instances of the TextInputLayout without me having to explicitely define a style="#style/my_style" on each of them.
If and how is that possible?
You can use the textInputStyle attribute in your app theme.
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<item name="textInputStyle">#style/myCustomStyle</item>
</style>

Change Theme.AppCompat global color

I am using Theme.AppCompat.Light.NoActionBar for my activities. In standard this theme sets one color (green/blue hue) for all button text, dialog titles and stripes, check boxes, etc. I just need to change this base color to another. How can i do it?
For now I can only change accent color with:
<item name="colorAccent">#color/actis_app_green_accent</item>
You can use Theme.AppCompat.NoActionBar (for dark theme) and Theme.AppCompat.Light.NoActionBar (for light theme).
It will change the backgrounds and text color of some basic Views.
To to change specific view's colors you should add specific items inside theme block.
e.g.
<item name="colorButtonNormal">#color/color_primary</item>
<item name="colorPrimary">#color/color_primary</item>
<item name="colorPrimaryDark">#color/color_primary_dark</item>
<item name="colorAccent">#color/color_accent</item>

Styling a Spinner, appcompat, material

So my app theme extends from AppCompat's Material Light theme with Dark Action Bar.
I applied an accent color.
Now I am trying to use a Spinner on a dark backround and because of the theme, the spinner has a dark gray arrow which changes to accent color when pressed.
How can I make this spinner's arrow white so that it is prominent on a dark background?
Here's the image of the Spinner:
If you want to apply same spinner style app wide, then in your values/styles.xml, override spinnerStyle with your custom style, which derives from an appcompat type and override android:background:
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="android:spinnerStyle">#style/AppSpinner</item>
</style>
<style name="AppSpinner" parent="Widget.AppCompat.Spinner">
<item name="android:background">#drawable/your_spinner_background</item>
</style>
If you need a quick way to generate a spinner background, try android-holo-colors, choose Colored Spinner and supply your accent color.
So the support library 22.1 enables use of android:theme attribute on views. That should help here.
with android:background you can specify your own background resource. I find the arrow rather useless (tapping the spinner brings dropdown menu even without arrow) so if you don't want to draw a custom arrow image, just leave the background black or transparent.

When should one use Theme.AppCompat vs ThemeOverlay.AppCompat?

There are the following Theme.AppCompat classes:
Theme.AppCompat
Theme.AppCompat.Light
Theme.AppCompat.Light.DarkActionBar
Theme.AppCompat.NoActionBar
Theme.AppCompat.Light.NoActionBar
Theme.AppCompat.DialogWhenLarge
Theme.AppCompat.Light.DialogWhenLarge
Theme.AppCompat.Dialog
Theme.AppCompat.Light.Dialog
Theme.AppCompat.CompactMenu
and the following ThemeOverlay.AppCompat classes:
ThemeOverlay.AppCompat
ThemeOverlay.AppCompat.Light
ThemeOverlay.AppCompat.Dark
ThemeOverlay.AppCompat.ActionBar
ThemeOverlay.AppCompat.Dark.ActionBar
Why would one use ThemeOverlay.AppCompat.light vs Theme.AppCompat.Light for example? I see that there are much less attributes defined for ThemeOverlay -- I am curious what the intended use case for ThemeOverlay is.
Theme.AppCompat is used to set the global theme for the entire app. ThemeOverlay.AppCompat is used to override (or "overlay") that theme for specific views, especially the Toolbar.
Let's look at an example for why this is necessary.
App themes with an ActionBar
The ActionBar is normally shown in an app. I can choose it's color by setting the colorPrimary value. However, changing the theme changes the color of the text on the ActionBar.
<style name="AppTheme" parent="Theme.AppCompat">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
Since my primary color is dark blue, I should probably use one of the themes that uses a light text color in the action bar because the black text is hard to read.
Hiding the ActionBar and using a Toolbar
The whole point of using Theme.AppCompat rather than Theme.Material is so that we can allow older versions of Android to use our material design theme. The problem is that older versions of Android don't support the ActionBar. Thus, the documentation recommends hiding the ActionBar and adding a Toolbar to your layout. To hide the ActionBar we have to use one of the NoActionBar themes. The following images show the Toolbar with the ActionBar hidden.
But what if I want something like a Light theme with a DarkActionBar? Since I have to use NoActionBar, that isn't an option.
Overriding the App Theme
Here is where ThemeOverlay comes in. I can specify the Dark ActionBar theme in my Toolbar xml layout.
<android.support.v7.widget.Toolbar
...
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
This finally allows us to have the effect we want. The Dark.ActionBar theme overlays the Light app theme for this particular occasion.
App Theme: Theme.AppCompat.Light.NoActionBar
Toolbar Theme: ThemeOverlay.AppCompat.Dark.ActionBar
If you wanted the popup menu to be light you could add this:
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
Further Study
I learned this through experimentation and through reading the following articles.
Setting Up the App Bar
Use android:theme and ThemeOverlay to theme specific Views and their descendents
Theming with AppCompat
Use colorPrimary to colorize your App Bar
Theme vs Style
Per this Theme vs Style blog post by the creator of AppCompat:
[ThemeOverlays] are special themes which overlay the normal Theme.Material themes, overwriting relevant attributes to make them either light/dark.
ThemeOverlay + ActionBar
The keen eyed of you will also have seen the ActionBar ThemeOverlay derivatives:
ThemeOverlay.Material.Light.ActionBar
ThemeOverlay.Material.Dark.ActionBar
These should only be used with the Action Bar via the new actionBarTheme attribute, or directly set on your Toolbar.
The only things these currently do differently to their parents is that they change the colorControlNormal to be android:textColorPrimary, thus making any text and icons opaque.

How to define a custom Application theme to specify a default background for a layout in Android?

I am creating a default theme for our Android apps to specify default custom theme to be applied to the whole app. The idea is we shouldn't have to specify appearance related attributes in the layout and they should be automatically injected by applying the custom theme to the entire app.
I am able to do this for UI widgets like TextView and EditText by overriding their styles.
For example overriding android:textViewStyle and android:buttonStyle, etc.
How can I do the same for a layout (LinearLayout or RelativeLayout, etc) so that I can specify a default background for a layout?
The application element in android manifest looks like this:
....
<application android:icon="#drawable/ic_launcher" android:label="#string/app_title" android:allowBackup="false"
android:theme="#style/Theme.MyCustomTheme" android:name="MyAppClass">
Theme.MyCustomTheme looks like this:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme.MyCustomTheme" parent="Theme.AppCompat">
<item name="android:textViewStyle">#style/my_custom_text_view_style</item>
<item name="android:editTextStyle">#style/my_custom_edit_text_style</item>
<item name="android:buttonStyle">#style/my_custom_button_style</item>
<item name="android:listViewStyle">#style/my_custom_list_style</item>
The custom styles above inherit from the respective android base styles.
I am looking for the right android attribute to use above to override the style of a layout so that I can apply my custom default background to every layout (LinearLayout or RelativeLayout, etc) declared in the layout xml file without having to explicitly specify it in the layout xml. I tried overriding android:colorBackground but that didn't make any difference. I tried overriding android:windowBackground but that changes the color of the action bar as well. Please note that I am using the appcompat theme from the appcompat support library.
I finally figured out how to define a custom default background for every container layout in my application
First, I defined a a custom theme as a style with the app compat background as the parent background which overrides the default window background. Please note that I am using the theme from the Android compatibility library to support pre-honeycomb Android devices
<style name="Theme.MyCustomAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">#color/my_custom_window_background</item>
<item name="android:colorBackground">#color/my_custom_window_background</item>
</style>
I applied the above theme to the whole application in the AndroidManifest
<
application android:icon="#drawable/ic_launcher" android:label="#string/app_title" android:theme="#style/Theme.MyCustomTheme"/>
The above steps resulted in every window having my default window background color defined in step 1 above including action bar. I definitely did not want my action bar, edit text, text view etc to be the default window color. So, I needed to to go back to step 1 and override the style of specific UI widgets I did not want to have the default window background
<style name="Theme.MyCustomAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">#color/my_custom_window_background</item>
<item name="android:colorBackground">#color/my_custom_window_background</item>
<item name="android:actionMenuTextColor">#color/customMenuColor</item>
<item name="android:textViewStyle">#style/customTextViewStyle</item>
<item name="android:editTextStyle">#style/customEditTextStyle</item>
<item name="android:buttonStyle">#style/customButtonStyle</item>
<item name="android:listViewStyle">#style/customListViewStyle</item>
<item name="android:tabWidgetStyle">#style/customTabWidgetStyle</item>
<!-- Support library compatibility -->
<item name="actionBarStyle">#style/customActionBarStyle</item>
<item name="actionMenuTextColor">#color/customMenuColor</item>
The last step was to define the each custom style define above either to have custom styles for them or have then assigned the system default styles (overridden because of custom window background)
For example, the custom action bar style will look like this:
<style name="customActionBarStyle"
parent="#style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">#color/light_black</item>
<item name="android:displayOptions">showHome|showTitle</item>
<item name="android:titleTextStyle">#style/customActionBarTitleTextStyle</item>
<!-- Support library compatibility -->
<item name="background">#color/light_black</item>
<item name="displayOptions">showHome|showTitle</item>
<item name="titleTextStyle">#style/customActionBarTitleTextStyle</item>
</style>
The advantage of this approach is you can define a default theme in a centralized way and don't have to define a background for each layout as it will be injected through the custom theme applied to the entire app.. Any future re-theming of the app will be very easy with this approach
Please refer to the Android Documentation on theming including how to theme the action bar for more information
Looking at themes.xml i didn't see anything applicable to layouts and ViewGroups in general, (although there are styles support for lists and some widgets as you can see).
Therefore I am not sure that it is possible to have your custom style applied to all layouts.
I guess you would still have to apply your custom layout style, (where you could change background color as
<item name="android:background">#ff0000</item>
) to each of your layouts yourself.
Feel free to prove me wrong.

Categories

Resources