Applying ThemeOverlay for custom theming a MaterialAlertDialogBuilder dialog - android

My app theme is set up like this:
<style name="Theme.App" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="colorOnSurface">#color/appColorOnSurface</item>
...
</style>
But when I use MaterialAlertDialogBuilder the text contrast is very poor (because material dialog uses colorOnSurface with 60% alpha, instead of textColorPrimary). So I tried to use this ThemeOverlay:
<style name="ThemeOverlay.App.Dialog.HighContrast" parent="ThemeOverlay.MaterialComponents.Dialog">
<item name="colorOnSurface">#color/appColorOnSurfaceHighContrast</item>
</style>
and applying it like this:
<style name="Theme.App" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="materialAlertDialogTheme">#style/ThemeOverlay.App.Dialog.HighContrast</item>
<item name="colorOnSurface">#color/appColorOnSurface</item>
...
</style>
However, this causes problems when displaying a list of items in the dialog. Each item touch area is limited to the area of text being displayed instead of stretching the width of the dialog like normal.
Furthermore, the theme does not appear to be Material, but rather AppCompat style.
Why does the ThemeOverlay approach cause the unexpected touch area (as if WRAP_CONTENT) issue? Is that not the correct way to apply a ThemeOverlay? Or is there another way to get the alert dialog to use #color/appColorOnSurfaceHighContrast?

I fixed this by using ThemeOverlay.MaterialComponents.MaterialAlertDialog instead of ThemeOverlay.MaterialComponents.Dialog.Alert, and also using materialAlertDialogBodyTextStyle to make sure only the dialog text body was being styled:
<style name="ThemeOverlay.App.Dialog.HighContrast" parent="ThemeOverlay.MaterialComponents.MaterialAlertDialog">
<item name="materialAlertDialogBodyTextStyle">#style/MaterialAlertDialog.App.Body.Text.HighContrast</item>
</style>
<style name="MaterialAlertDialog.App.Body.Text.HighContrast" parent="#style/MaterialAlertDialog.MaterialComponents.Body.Text">
<item name="android:textColor">#color/appColorOnSurfaceHighContrast</item>
</style>
But why does AndroidStudio auto-complete only show ThemeOverlay.MaterialComponents.Dialog.Alert and not ThemeOverlay.MaterialComponents.MaterialAlertDialog?
Note: there were actually two issues going on here:
Changing the parent ThemeOverlay from ThemeOverlay.MaterialComponents.Dialog to ThemeOverlay.MaterialComponents.Dialog.Alert fixed the touch area issue, but I was still getting an AppCompat (non-Material) theme.
Changing the parent ThemeOverlay from ThemeOverlay.MaterialComponents.Dialog.Alert to ThemeOverlay.MaterialComponents.MaterialAlertDialog fixed the theme to make it appear Material.
UPDATE: It looks like ThemeOverlay.MaterialComponents.Dialog.Alert is for use with alertDialogTheme and ThemeOverlay.MaterialComponents.MaterialAlertDialog is for use with materialAlertDialogTheme. See: https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/dialog/res/values/themes.xml#L60
However, that still doesn't explain why the latter doesn't auto-complete.

Related

Overriding the theme attribute inside of a style?

I have a project where I defined all the styles in the theme (Button style, Checkbox Style, EditText style and so on) This way I don't need to apply any style or theme in the layouts where I use those views, because they are applied automatically by my AppTheme.
Now I encountered a problem. I wanted to define the Switch style inside the theme but it should use another color for the colorControlActivated and colorControlHighlight. By default it uses the colorPrimary which I defined in the theme, but what if I want to change that.
The problem can be fixed easy with a theme overlay or a style where I override the needed attributes that I mentioned above and apply that style/theme everywhere where I use the Swtch view. But I want to know if I can avoid that and define a default style for my Switch views inside the same theme where the colorControlActivated and colorControlHighlight are already defined.
I tried several things but this looked like the one that actually might work but it does not:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorControlActivated">#color/colorPrimary</item>
<item name="colorControlHighlight">#color/colorPrimary</item>
<item name="colorSwitchThumbNormal">#color/white</item>
<item name="switchStyle">#style/SwitchStyle</item>
</style>
<style name="AppTheme.GreenControlOverlay">
<item name="colorControlActivated">#color/green</item>
<item name="colorControlHighlight">#color/green</item>
</style>
the SwitchStyle looks like this
<style name="SwitchStyle" parent="Widget.AppCompat.CompoundButton.Switch">
<item name="android:theme">#style/AppTheme.GreenControlOverlay</item>
</style>
I dont know why this is not working because if I set the android:theme inside my AppTheme directly it does override the colorControl attributes, but if you override it from a style it does not work. If I apply this GreenControlOverlay on the Switch view inside of my layout it also works.
Is it even possible to do this?
If you have any questions please don't hesitate to ask. I hope I explained my problem well.

Material design: Where to place elevation in android styles?

I want to set item elevation in some of my app's styles. Now elevation is only 21 and higher with no support library, so my natural inclination was to just create a styles-v21 xml and place it in there:
<style name="Widget.MyApp.Drawer" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:elevation">4dp</item>
</style>
The problem with this is any changes I make to Widget.MyApp.Drawer in the regular styles.xml file will be overwritten by this completely. What I'd want is for elevation to just be tacked on to the bottom of the list of style changes I made for the v21 version of this style listed in styles.xml.
So I took to creating base styles which the style I use in the views inherits from:
<style name="BaseListElement">
<item name="android:background">#drawable/listitem_background</item>
<item name="android:layout_height">#dimen/list_item_height</item>
</style>
<style name="BaseListElement.ListItem">
</style>
I leave the style blank in styles.xml, and in styles-v21, I add elevation and it works.
However this get's kind of tricky when I want to use some advanced styles:
<style name="BaseListElement">
<item name="android:background">#drawable/listitem_background</item>
<item name="android:layout_height">#dimen/list_item_height</item>
</style>
<style name="BaseListElement.BaseItem">
<item name="android:padding">#dimen/list_item_padding</item>
</style>
<style name="Widget.MyApp.ListItem" parent="#style/BaseListElement.BaseItem">
</style>
<style name="BaseListElement.BaseHeader">
</style>
In this case, BaseItem is just one style that inherits from BaseListElement, styles such as BaseHeader inherit from it as well. This is getting kind of ridiculous as you can see.
Am I overthinking this? The way I see it I have 3 choices here:
1) Continue as is and feel like an idiot
2) On the BaseListElement level, create a child style with some goofy name which is the point at which I apply the elevation, which would then (hopefully) trickle down to all the children. As soon as I have a difference between v21 children of the base however, this wouldn't work.
3) Just throw android:elevation into the styles.xml file (don't use a v21 file) and place an ignore flag on the element. I only have 5.0 devices here, so I can't easily test at the moment if this will cause a crash on older versions.
Any thoughts?
To accomplish something like this you could just create a BaseListElement.BaseItem in both styles.xml and syles-v21.xml the first one without the elevation and the second one with it. Then just extend Widget.MyApp.ListItem from BaseListElement.BaseItem which should get updated in v21 to use the elevation.
styles.xml
<style name="BaseListElement.BaseItem">
</style>
<style name="Widget.MyApp.ListItem" parent="#style/BaseListElement.BaseItem">
</style>
styles-v21.xml
<style name="BaseListElement.BaseItem">
<item name="android:padding">#dimen/list_item_padding</item>
</style>
Method 3 you can safely implement as follows:
<item name="android:elevation" tools:ignore="NewApi">4dp</item>

Change Dialog Theme for every Dialog

Im using Theme.Holo.Light.DarkActionBar but I dont really like the Light Dialogs/AlertDialogs.
I want to change every Dialog to the dark Holo Dialog.
<style name="CustomDialogTheme" parent="#android:style/Theme.Holo.Dialog">
<item name="#android:background">#9933CC</item>
<item name="#android:textColor">#02FA07</item>
</style>
<style name="Holo.Light.DarkActionBar" parent="#android:style/Theme.Holo.Light.DarkActionBar">
<item name="android:dialogTheme">#style/CustomDialogTheme</item>
<item name="android:alertDialogStyle">#style/CustomDialogTheme</item>
</style>
Thats what I tried but it has no effect on any Dialogs.
Ok nvm Im stupid its android:alertDialogTheme instead of android:alertDialogStyle. But this messes up the Preference Dialogs, so I just keep using the Light Dialogs.
In AndroidManifest.xml under the application tag, add this line :
android:theme="Holo.Light.DarkActionBar"
The issue is that the styles you're changing android:background and android:textColor are not dialog attributes.
You can see a full list here under Theme.Holo.Dialog on line 1617.
The ones you have to change are probably android:windowBackground and textAppearance

How can I modify Theme.Holo.Light.Dialog to take up less screen space?

My app is currently using the Holo Light theme, except where I've added customizations. This is mostly OK, but I'm having difficulty with styling the Dialog box.
The holo theme has the colours I want, but Theme.Dialog is more compact, i.e. it takes up less space on the screen which is what I also want.
When I use the Holo theme, with the following customisation
<style name="AlertDialogCustom" parent="#android:style/Theme.Holo.Light.Dialog">
<item name="android:buttonStyle">#style/general_button_style</item>
<item name="android:textColor">#color/my_blue</item>
</style>
it appears like this:
When I revert the dialog box to the non-Holo theme
<style name="AlertDialogCustom" parent="#android:style/Theme.Dialog">
<item name="android:buttonStyle">#style/general_button_style</item>
<item name="android:textColor">#color/my_blue</item>
</style>
it appears as follows:
What do I need to change to use the holo theme but to make it use less screen space?
The extra space used in Holo theme is used to accomodate for scrolling effect when you swipe up or down.
Both of the scrolling components are sitting inside of a view like this.
Specifying negative margins on top/bottom of both components should do the (although dirty) trick:
<TimePicker
android:id="#+id/timePicker1"
...
android:layout_marginBottom="-20dip"
android:layout_marginTop="-20dip"/>
Play with the numbers as needed as I didn't try it myself.

Light.DarkActionBar menu item text colour unchangeable?

The application I've been developing uses ActionBarSherlock, and the main theme inherits from Theme.Sherlock.Light.DarkActionBar. The design requires that the overflow menu popups have a dark coloured background and white text. This works fine for devices without a physical menu button, and the text appears white as intended. However, if the device DOES have a physical menu button, the text shown in the menu displayed remains black.
My main theme contains
<item name="android:panelBackground">#drawable/menu_hardkey_panel</item>
...Where #drawable/menu_hardkey_panel is a dark coloured 9patch.
The resulting appearance of the menu popup is...
I'm unable to determine why this is happening, or how to manually change the colour of the text. In my main theme, I've tried all of the following...
<item name="android:actionMenuTextColor">#android:color/white</item>
<item name="android:textAppearanceLargePopupMenu">#style/MyMenuTextAppearance.Large</item>
<item name="android:textAppearanceSmallPopupMenu">#style/MyMenuTextAppearance.Small</item>
I've even tried
<item name="android:actionBarWidgetTheme">#style/Theme.MyApp.Dark</item>
...Where Theme.MyApp.Dark is...
<style name="Theme.MyApp.Dark" parent="#style/Theme.Sherlock">
<item name="android:dropDownListViewStyle">#style/DropDownListView</item>
<item name="dropDownListViewStyle">#style/DropDownListView</item>
</style>
None have let me change the text to white. If I make my base theme inherit from Theme.Sherlock, the problem is solved and the text is white, but unfortunately that's not an option.
Not entirely sure about this, but I believe the pop-up menu uses the same styling as the overflow menu. In which case you'd just do something like this.
<item name="android:itemTextAppearance">#style/your_new_text_appearance</item>
<style name="your_new_text_appearance">
<item name="android:textColor">#android:color/white</item>
</style>
Giving it a chance: there is a text appearance called actionMenuTextAppearance. Have you tried that?
Update: I did some more digging and I believe that this file is the layout And there they refer to textAppearanceListItemSmall and textAppearanceSmall. However, it takes this value from a special theme which is specified as following in Theme.Holo.Light
<item name="panelMenuListTheme">#android:style/Theme.Holo.Light.CompactMenu</item>
And like this in Theme.Holo:
<item name="panelMenuListTheme">#android:style/Theme.Holo.CompactMenu</item>
The problems comes from the fact that the parent of Sherlock.__Theme.DarkActionBar is Theme.Sherlock.Light. This is not valid for the dark action bar. Taking the line from Theme.Holo should do the trick.
In my research I haven't found a way to change the text color, but you can at least handle hardkey menus gracefully.
This link provided me with a passable solution to the problem:
https://github.com/jgilfelt/android-actionbarstylegenerator/issues/30
Commenting out the "android:panelBackground" item from my generated theme allowed the text to at least be visible on hardkey menus, even if it doesn't perfectly match the theme.
You could also try replacing the "menu_hardkey_panel_whatever.9.png" drawable with something that will work for your theme and the black text.
For me this solves the problem, try this instead:
<style name="MyTheme" parent="Theme.Sherlock.Light.DarkActionBar">
...
<item name="actionBarWidgetTheme">#null</item>
<item name="android:actionBarWidgetTheme">#null</item>
...
</style>
I found the solution, use:
getSupportActionBarContext()
e.g.
ArrayAdapter<CharSequence> list =
ArrayAdapter.createFromResource(getSupportActionBarContext(), R.array.navigation, layout.simple_spinner_item);
list.setDropDownViewResource(layout.simple_spinner_dropdown_item);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
getSupportActionBar().setListNavigationCallbacks(list, this);
I think that due to the fact that Theme.Sherlock.Light.DarkActionBar don't style its contents right is due to the actionWidgetTheme attribute is used with a ContextThemeWrapper for inflating the action bar views (Jake Wharton's own words), thus something like the following (not tested) will be needed to fulfill your needs, though breaking your need of not using Theme.Sherlock as parent in one way:
<style name="MyColorTheme" parent="Theme.Sherlock">
<item name="android:actionMenuTextColor">#android:color/white</item>
<item name="actionMenuTextColor">#android:color/white</item>
</style>
<style name="YourMainTheme" parent="Theme.Sherlock.Light.DarkActionBar">
<item name="android:actionMenuTextAppearance">#style/MyColorTheme</item>
<item name="actionMenuTextAppearance">#style/MyColorTheme</item>
</style>
Might work or not work. That's the question :)

Categories

Resources