Android AppCompat AlertDialog styling with theme - android

I wish to be able to set a theme to set the message text size in an AppCompat AlertDialog. The theme needs to have parent="#style/Theme.AppCompat.Dialog". I have spent hours searching and trying all the suggestions, but none of them seem to work with that base theme.
If the parent is changed to the Holo theme, then I can alter the message text size using textAppearanceMedium, but the rest of the dialog looks really ugly :S
Currently my theme is (all this is currently hooked up and working):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyDialogTheme" parent="#style/Theme.AppCompat.Dialog">
<!-- Used for the buttons -->
<item name="colorAccent">#color/colorPrimary</item>
<!-- Button text size -->
<item name="android:textSize">#dimen/ui_text_size</item>
<!-- Content text color -->
<item name="android:textColorPrimary">#color/ui_text_color</item>
<!-- Title style -->
<item name="android:windowTitleStyle">#style/MyDialogTitleStyle</item>
<!-- Button style (except size) -->
<item name="android:textAppearanceButton">#style/MyDialogButtonTextAppearance</item>
<!-- Dialog background -->
<item name="android:windowBackground">#color/ui_background</item>
</style>
<style name="MyDialogTitleStyle" parent="#style/RtlOverlay.DialogWindowTitle.AppCompat">
<item name="android:textAppearance">#style/MyDialogTitleTextAppearance</item>
<item name="android:textSize">#dimen/ui_large_text_size</item>
</style>
<style name="MyDialogTitleTextAppearance">
<item name="android:textSize">#dimen/ui_large_text_size</item>
<item name="android:textAllCaps">true</item>
<item name="android:textColor">#color/ui_title_color</item>
</style>
<style name="MyDialogButtonTextAppearance">
<item name="android:fontFamily">sans-serif-light</item>
<item name="android:textAllCaps">true</item>
</style>
</resources>

Seems like there is no way to this via a theme attribute. Let's look at the source code of appcompat-v7 library. Following the TextView that reflects the message of the AlertDialog:
<android.support.v7.widget.AlertDialogLayout ... >
<!-- ... -->
<TextView
android:id="#android:id/message"
style="#style/TextAppearance.AppCompat.Subhead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"/>
<!-- ... -->
</android.support.v7.widget.AlertDialogLayout>
As you can see the TextView uses the TextAppearance.AppCompat.Subhead as the style. Following its definition:
<style name="TextAppearance.AppCompat.Subhead" parent="Base.TextAppearance.AppCompat.Subhead"/>
<style name="Base.TextAppearance.AppCompat.Subhead">
<item name="android:textSize">#dimen/abc_text_size_subhead_material</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>
The textSize is static and isn't resolved via an attribute like the textColor (which uses the textColorPrimary). Thus there's no option for us to set the textSize. The only way to do it would be to override the TextAppearance.AppCompat.Subhead style by adding it to your own styles.xml file and set the textSize to whatever value you need. But be aware there may be side effects since this style can be used in other places as well.
tl;dr
Options:
Define TextAppearance.AppCompat.Subhead in your styles.xml file and override the textSize attribute.
Do it programatically (find TextView by id and #setTextSize)
Use your own layout in the dialog - the source code of appcompat-v7 may be a good starting point.

Related

How to change color Toolbar icons?

I am currently trying to change the colors of the icons in the toolbar via the theme (I know the way to do it via kotlin but I am interested to be able to do it on the whole app via a theme). Even though I read the google doc on this subject and several topics, I was not able to change the color of these icons. I'm using MaterialTheme
Manifest where I defined my theme and my activity :
<application
android:name=".App"
android:theme="#style/Theme.MyApp">
<activity
android:name=".views.activity"
android:label="#string/title_activity" />
</application>
Themes.xml
<!--Top level DayNight theme to be used in AndroidManifest.xml-->
<style name="Theme.MyApp" parent="Base.Theme.MyApp" />
<!--Base custom theme which will be shared between both light and dark theme variants-->
<style name="Base.Theme.MyApp" parent="Base.Theme.MaterialThemeBuilder">
<!--Material color attributes (light theme) -->
<!--colorPrimary colors map to components and elements, such as app bars and buttons. -->
<!--colorSecondary colors are most often used as accents on components, such as FABs and -->
<!--selection controls.-->
<item name="colorPrimary">#color/primaryColor</item>
<item name="colorPrimaryVariant">#color/primaryLightColor</item>
<item name="colorSecondary">#color/secondaryColor</item>
<item name="colorSecondaryVariant">#color/secondaryLightColor</item>
<!--colorBackground appears behind scrollable content and is used for the default window-->
<!--background. colorSurface is mapped to the surface of components such as cards, sheets-->
<!--and menus. colorError is used to indicate an error state for components such as-->
<!--text fields.-->
<item name="android:colorBackground">#color/grey_200</item>
<item name="colorSurface">#color/black_800</item>
<item name="colorError">#color/red_600</item>
<!--"On" colors define how text, icons and strokes are colored in relation to the surface-->
<!--on which they appear.-->
<item name="colorOnPrimary">#color/black_800</item>
<item name="colorOnSecondary">#color/black_800</item>
<item name="colorOnBackground">#color/black_800</item>
<item name="colorOnSurface">#color/black_800</item>
<item name="colorOnError">#color/white</item>
<!--Material type attributes-->
...
<!--Material shape attributes-->
...
<item name="toolbarStyle">#style/Widget.MyTheme.Toolbar</item>
</style>
Styles.xml
<!--Toolbar-->
<style name="Widget.MyTheme.Toolbar" parent="Widget.MaterialComponents.Toolbar.Surface"> // I have also try ThemeOVerlay here and Toolbar.Primary
<item name="android:background">#color/grey_200</item>
<item name="titleTextAppearance">#style/TextAppearance.MyTheme.Headline6</item>
<item name="subtitleTextAppearance">#style/TextAppearance.MyTheme.Subtitle1</item>
<item name="titleTextColor">#color/black_800</item>
<!-- color used by navigation icon and overflow icon -->
<item name="colorOnPrimary">#color/red_800</item>
<item name="colorControlNormal">#color/red_800</item>
</style>
As you can see the toolbar is provided by the theme so the activity xml is not revelant here. My icons are in vector format, generated via AndroidStudio. I have try this solution but not working :/
The solution linked in the question works but you are using a style (with style="..") not a theme overlay (with android:theme="..").
<style name="Base.Theme.MyApp" parent="Base.Theme.MaterialThemeBuilder">
<item name="toolbarStyle">#style/Widget.MyTheme.Toolbar</item>
</style>
With the theme attribute toolbarStyle you are using a style:
<style name="Widget.MyTheme.Toolbar" parent="Widget.MaterialComponents.Toolbar">
<!-- Title text color -->
<item name="titleTextColor">#color/colorSecondary</item>
<!-- ..... -->
<!-- ThemeOverlay -->
<item name="materialThemeOverlay">#style/MyThemeOverlay_Toolbar</item>
</style>
<style name="MyThemeOverlay_Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Primary">
<!-- color used by navigation icon and overflow icon -->
<item name="colorOnPrimary">#color/red600Dark</item>
</style>
and in your layout use a MaterialToolbar:
<com.google.android.material.appbar.MaterialToolbar
.../>

Android TimePickerDialog styling guide/docs?

I'm trying to style a TimePickerDialog for sdk 21+ (Lollipop). So far I've figured out how to change the default colorscheme in XML:
<style name="TimePickerTheme" parent="#style/Theme.AppCompat.Light.Dialog">
<item name="colorPrimary">#ff2d6073</item> <!-- no effect -->
<item name="colorPrimaryDark">#ff2d6073</item> <!-- no effect -->
<item name="colorAccent">#ff2d6073</item>
<item name="android:textColor">#ffD0D102</item>
<item name="android:textColorPrimary">#ffD0D102</item>
</style>
This works but I'm looking for a guide or documentation for all the properties I can change.
AccentColor does the basic color scheme
TextColorPrimary does the text color
But what property, for example, do I need to change the big text in the 'header' of the dialog (where the current selected time is displayed)?
Is there some documentation that lists all the possible things you can change?
After digging through the AOSP theme and style xml files and a lot of googling I made some progress. I am now able to style most(!) things.
So this is a partial answer, not all the way there yet. But here's how far I got:
You can see that I'm now able to theme the header, the un(!)selected time part (minutes in this case), the circle, the numbers in that circle and the 'hand' (or selector). Oh, and the buttons are styled, too.
Let me explain how I got things working, first: the important thing is that you can't override things directly from you app's theme OR from a (alert)dialog theme/style. You have to go from one to the next, so to speak.
Example:
AndroidManifest.xml: Set custom theme for app and/or activity
<activity>
android:theme="#style/Theme.MyTheme"
</activity>
values-v21/styles.xml: (where your custom theme resides): set the timePickerDialogTheme
<style name="Theme.MyTheme" parent="#style/Theme.AppCompat.Light">
<item name="android:timePickerDialogTheme">#style/TimePickerDialogTheme</item>
</style>
Then below that, define the timePickerDialogTheme and set the timePickerStyle:
<style name="TimePickerDialogTheme" parent="#style/Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#ff2d6073</item> <!-- colorAccent here seems to work just fine? -->
<item name="android:timePickerStyle">#style/TimePickerDialogStyle</item>
</style>
Now you can define most of the styling here..
<style name="TimePickerDialogStyle" parent="#android:style/Widget.Material.Light.TimePicker">
<item name="colorAccent">#ff2d6073</item> <!-- colorAccent here seems to work just fine? -->
<item name="android:timePickerMode">clock</item>
<item name="android:headerBackground">#ff2d6073</item>
<item name="android:headerTimeTextAppearance">#style/TextAppearance.TimePickerDialogStyle.TimeLabel</item> <!-- TimePicker Time *TextAppearance* -->
<item name="android:numbersTextColor">#ff000000</item>
<item name="android:numbersSelectorColor">#ff2d6073</item>
<item name="android:numbersBackgroundColor">#ffdddddd</item>
</style>
The important line in the above is:
<item name="android:headerTimeTextAppearance">#style/TextAppearance.TimePickerDialogStyle.TimeLabel</item>
Because if you want to style the text (well, time, actually) in the header you need to define the headerTimeTextAppearance:
<style name="TextAppearance.TimePickerDialogStyle.TimeLabel" parent="#android:style/TextAppearance.Material">
<item name="android:textSize">60sp</item> <!-- from -->
<item name="android:textColor">#ffD0D102</item>
</style>
Now, if you take a look at the Widget.Material.TimePicker in AOSP styles.xml (ctrl-f 'timepicker' until you find it) you'll notice a bunch of other properties that you should be able to modify:
headerTimeTextAppearance
headerAmPmTextAppearance
headerSelectedTextColor
headerBackground
numbersTextColor
numbersBackgroundColor
amPmTextColor
amPmBackgroundColor
amPmSelectedBackgroundColor
numbersSelectorColor
Most of these work (as long as you prepend 'android:' for each of them) BUT I could not get 'headerSelectedTextColor' to work. I got a compile error saying something like "could not match property bla bla". Also, if you look at my example above, I hardcoded the textSize for the 'headerTimeTextAppearance' property because the '#dimen/timepicker_ampm_label_size' value threw errors.
In short: most of the things are listed above and how to get them working. But not all is clear. So I'd still see that complete documentation/guide :)
Android TimePicker material style with custom colors below, you can see http://www.zoftino.com/android-timepicker-example for TimePicker usage and styles.
<style name="MyAppThemeFour" parent="Theme.AppCompat.Light">
<item name="android:timePickerDialogTheme">#style/MyTimePickerDialogStyle</item>
</style>
<style name="MyTimePickerDialogStyle" parent="#style/ThemeOverlay.AppCompat.Dialog.Alert">
<item name="showTitle">false</item>
<item name="colorControlActivated">#ffd600</item>
<item name="colorAccent">#b71c1c</item>
<item name="android:textColorPrimary">#43a047</item>
<item name="android:textColorSecondary">#f44336</item>
</style>
When using version 1.5.0 of the Material Design Library for Android, I've found that I can get most of the theming with using this particular style:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyTimePickerTheme" parent="ThemeOverlay.MaterialComponents.TimePicker">
<item name="android:textColor">#FF121212</item>
<item name="android:textColorPrimary">#FF121212</item>
<item name="android:textColorSecondary">#FFF9F9F9</item>
<item name="colorAccent">#FF121212</item>
<item name="colorControlNormal">#FF121212</item>
<item name="colorPrimary">#FF121212</item>
<item name="colorSurface">#FFF9F9F9</item>
</style>
</resources>
This will yield in a generic - non colored - Dialog which works for white theme. For dark theme, simply invert the colors.
I've also asked here to have dynamic theming supported for this component.
Example screenshot using the above style:

How to change overflow menu textcolor in Android?

I have a custom theme that is (mostly) working great. The problem I have is that I cannot figure out a way to change the overflow menu's text color. I realize there are probably ways to do it programmatically but I'm really hoping I can find a solution I can put in the xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Light" parent="android:Theme.Material.Light.DarkActionBar">
<item name="themeName">Theme.Light</item>
<!--<item name="android:textColor">#ff000000</item>-->
<!-- colorPrimary is used for the default action bar background -->
<item name="android:colorPrimary">#color/blue</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="android:colorPrimaryDark">#color/medium_blue</item>
<!-- colorAccent is used as the default value for colorControlActivated,
which is used to tint widgets -->
<item name="android:colorAccent">#color/dark_blue</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight, and colorSwitchThumbNormal. -->
<item name="android:actionOverflowMenuStyle">#style/Theme.Light.PopupMenu</item>
<item name="android:textColor">#color/light_text</item>
<item name="android:textColorPrimary">#color/light_text</item>
<item name="actionBarWidgetTheme">#style/MyStyle</item>
</style>
<style name="MyStyle" parent="android:style/Widget">
<item name="android:textColor">#color/dark_text</item>
</style>
<style name="Theme.Light.PopupMenu" parent="android:style/Widget.Material.PopupMenu.Overflow">
<!-- Required for pre-Lollipop. -->
<item name="overlapAnchor">false</item>
<!-- Required for Lollipop. -->
<item name="android:overlapAnchor">false</item>
<item name="android:popupBackground">#color/medium_blue</item>
<item name="android:actionMenuTextColor">#style/Theme.Light.TextAppearance</item>
<item name="android:textColor">#color/dark_text</item>
<item name="android:textColorPrimary">#color/dark_text</item>
</style>
<style name="Theme.Light.TextAppearance">
<item name="android:textColor">#color/dark_text</item>
<item name="android:textColorPrimary">#color/dark_text</item>
</style>
</resources>
I realize this is rather messy but I left in several ways I've attempted to change the textcolor. Basically instead of using the default black for the Material theme, I want to the change the overflow menu textcolor to white.
My guess is there's just some attribute I'm not changing but obviously I don't know what it is. I've searched Google and here but haven't found a solution to this.
EDIT: Setting the textColor for the entire theme does affect the overflow menu's text color but also affects every other text's color, obviously. I'm looking for a more specific attribute.

Style selector?

I have two holo based ABS styles, Purple and Lime, users are able to set the theme from settings.
In my layout I have a TextView with a custom textAppearance, I want to change that textAppearance based on the active style.
(if the purple theme is activated the text must be white and if the lime theme is activated the text must be lime)
Is there a way to do that from the XML?
Edit
I'm sorry if the title is misleading.
(if the purple theme is activated the text must be white and if the
lime theme is activated the text must be lime)
Try that:
<style name="PurpleTheme" parent="...">
<!-- define the style for the text appearance here. Following is an example -->
<item name="android:textAppearance">#style/MyWhiteText</item>
</style>
<style name="LimeTheme" parent="...">
<!-- define the style for the text appearance here. Following is an example -->
<item name="android:textAppearance">#style/MyLimeText</item>
</style>
<style name="MyWhiteText" parent="#android:style/TextAppearance">
<item name="android:textColor">#color/white</item>
</style>
<style name="MyWhiteText" parent="#android:style/TextAppearance">
<item name="android:textColor">#color/lime</item>
</style>
Or if you don't want to set the color to all TextViews then do this:
Declare an attribute:
<attr name="myTextViewColor" format="reference" />
Use it like this in your theme:
<style name="PurpleTheme" parent="...">
<item name="myTextViewColor">#color/white</item>
</style>
<style name="LimeTheme" parent="...">
<item name="myTextViewColor">#color/lime</item>
</style>
Now you can set the color of the specific TextView like this:
<TextView
android:textColor="?attr/myTextViewColor"
[...] />

Actionbar fills transparent icon pixels with wrong background

I am using actionbar sherlock. I have an icon with transparent pixels. But when I run my app, it seems "something" is replacing these transparent pixels with the main background from the theme, not the actionbar background.
It does not matter if the main background is specified as a #color or a #drawable (9 patch) but in the latter case (which is what I actually want) there is an additional quirk in that a few pixels of the main background 9 patch appear at the right(!) hand edge of the actionbar. Go figure.
I have no idea what's going on here. Just that if I remove the background items from the main style, the actionbar looks as it should (so that seems to be the problem).
Has anyone else seen such behaviour before? Thanks for taking a look!
I'll paste my style.xml below:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ViewPagerIndicator">
<attr name="vpiSubTabPageIndicatorStyle" format="reference"/>
</declare-styleable>
<style name="Theme.StandBy" parent="Theme.Sherlock.Light.DarkActionBar">
<item name="vpiTabPageIndicatorStyle">#style/CustomTabPageIndicator</item>
<item name="vpiSubTabPageIndicatorStyle">#style/CustomSubTabPageIndicator</item>
<item name="android:actionBarStyle">#style/Theme.StandBy.App.ActionBar</item>
<item name="actionBarStyle">#style/Theme.StandBy.App.ActionBar</item>
<!-- ------------------------------------------ ->
<!-- I tried both of these, but can't get transparent pixels in my icon to work --->
<!-- when I use the 9 patch (frg_background) in stead of a plain color, there -->
<!-- are extra artefacts in that some of the 9 patch pixels end up on the righthand -->
<!-- side of the action bar -->
<!--<item name="android:background">#drawable/frg_background</item>
<item name="background">#drawable/frg_background</item>-->
<item name="android:background">#color/cream</item>
<item name="background">#color/cream</item>
<!-- ------------------------------------------ ->
</style>
<style name="Theme.StandBySubTab" parent="Theme.Sherlock.Light.DarkActionBar">
<item name="vpiTabPageIndicatorStyle">#style/CustomSubTabPageIndicator</item>
</style>
<style name="Theme.StandBy.App.ActionBar" parent="Widget.Sherlock.ActionBar">
<!--
Both `android:xyz` and `xyz` need to be set to support 4.x and 2.x devices.
-->
<item name="android:displayOptions">showHome</item>
<item name="displayOptions">showHome</item>
<item name="android:background">#drawable/bar</item>
<item name="background">#drawable/bar</item>
</style>
<!-- top tab style -->
<style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
<item name="android:background">#drawable/tab_background</item>
<item name="android:textAppearance">#style/CustomTabPageIndicator.Text</item>
<item name="android:divider">#drawable/tab_divider</item>
<item name="android:showDividers">middle</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
</style>
<style name="CustomTabPageIndicator.Text">
<item name="android:textColor">#color/tab_text</item>
<item name="android:textSize">10sp</item>
<item name="android:textStyle">bold</item>
</style>
<!-- sub tab style -->
<style name="CustomSubTabPageIndicator" parent="Widget.TabPageIndicator">
<item name="android:background">#drawable/sub_background</item>
<item name="android:textAppearance">#style/CustomSubTabPageIndicator.Text</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
</style>
<style name="CustomSubTabPageIndicator.Text">
<item name="android:textColor">#color/sub_text</item>
<item name="android:textSize">10sp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>
EDIT: since the problem goes away if I do not specify background and android:background in my main style (Theme.StandBy) it occurred to me I might be asking the wrong question. My purpose in putting these items in is to specify a default background for all of my fragments (content of tabs). That works, but has the unwanted side-effects I mentioned above. Should I be doing this in another way? Thanks for any suggestions!
Properties that you set on the theme will be inherited by EVERY view when the view resolves its styles. In your case, every view that doesn't have an explicit background set somewhere else will render an #color/cream background. This is bound to cause the kinds of visual problems you're experiencing, as well as creating massive amounts of unnecessary overdraw.
A much better way to apply common styling to your fragments is to simply create a style
<style name="Fragment">
<item name="android:background">#color/cream</item>
</style>
and reference it from the root view of each fragment, e.g.
<LinearLayout style="#style/Fragment">
...
</LinearLayout>
This means a bit of extra typing as the reference to the style needs to go into each fragment, but there is no good way to avoid this -- Conceptually only View classes can have their own default style set by the theme (e.g. you can point the textViewStyle attribute at a style definition, and it will apply to all TextViews). However Fragments (or Activities for that matter) aren't Views, so this mechanism doesn't apply.

Categories

Resources