How to set PreferenceFragmentCompat accentColor? - android

I'd like to override the accentColor used by v14 PreferenceFragmentCompat.
I'm using a pink accent color for the outer frame of my Android app. This creates problems in many situations as it causes standard controls to use an accent color that's close enough to red that the effect is disturbing. Be that as it may, I like the effect of having a pink FAB and button controls on the frame.
For child activities, I use a them with the standard teal accent color. However, I have a PreferenceFragment compat in a drawer on the main activity, and I cannot figure out how to override the main activity's accent color.
Things I have tried (none of which work):
Setting a theme on the frame of the fragment that receives the PreferenceFragmentCompat (doesn't work):
<FrameLayout android:id="#+id/preferenceFragmentFrame"
android:layout_width="match_parent" android:layout_height="0dp"
android:layout_weight="1"
android:theme="#style/AppTheme.TealAccentColor"
/>
where the AppTheme.TealAccentColor style provides an explicit teal acccentColor.
Setting the accentColor in a preference theme (doesn't work):
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="preferenceTheme">#style/MyPreferenceThemeOverlay</item>
</style>
<style name=MyPreferenceThemeOverlay parent="PreferenceThemeOverlay.v14.Material>
<item name="colorAccent">#color/colorAccentTeal</item>
</style>
Adding an accent color to preference-v14's PreferenceThemeOverlay (doens't work):
<!-- use the library's theme-->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="preferenceTheme">PreferenceThemeOverlay.v14.Material</item>
</style>
<!-- but add an accentColor item to the library's theme -->
<style name="PreferenceThemeOverlay.v14">
<item name="colorAccent">#color/colorAccentTeal</item>
</style>
No matter what I do, PreferenceFragmentCompat seems to take the pink accent color from the Activity's theme instead.
I'm sure it has something to do with a disconnect between the Activity's theme and a Fragment's theme. But there's no xml element for the fragment, since PreferenceFragmentCompat provides its own layout.
Maybe there's a way to do it programmatically with an override in the class that extends PreferenceFragmentCompat, but if there is, I can't imagine what it would be. Most of the attack points I can think of either have access to the internally-created layout, or have access to the layout after it has been created, which is too late.
A picture might help:

Have you tried overriding android:colorAccent instead of colorAccent?
Use the method you described as "Setting the accentColor in a preference theme", just change the attribute name.
The preference support library doesn't take into consideration appcompat at all, so
forget about appcompat attributes
color* attributes will only work on API 21, I think
If you want consistent behavior you can use my library Android Support Preference which aims to connect preference and appcompat support libraries.
Then you original style with colorAccent (unprefixed) will work as expected.

Related

How come the color I set for cardBackgroundColor isn't exactly the one that gets shown?

Background
I'm trying to prepare dark theme for an app, and one of the requirements is to have a specific color for cards and dialogs : #ff3c454c
The problem
Whether I set it by force ( app:cardBackgroundColor="#3c454c") , by reference ( app:cardBackgroundColor="#color/...) or just in the theme - in all cases I don't get the color I've set. Instead I get the color of #525A61.
I've tested just a red color (#f00) just to be sure it affects the card, and it does, and for this color it indeed gets to be fine. But for the color I've set, it doesn't.
What I've tried
As I wrote, I tried multiple ways to set the color. In the beginning I wanted to use just the theme itself, so I've set it as such:
styles.xml
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
...
<item name="colorBackgroundFloating">#color/colorBackgroundFloating</item>
<item name="colorSurface">#color/colorBackgroundFloating</item>
</style>
res/values-night/colors.xml
<color name="colorBackgroundFloating">#ff3c454c</color>
Later I tried to use the color directly and even set it as hard coded. Still got the incorrect color when it gets shown.
Seeing this could be a bug on the library itself, I've reported about this here (include a sample project, if you wish to check it out).
I've noticed the exact same issue occurs for BottomNavigationView and probably other similar cases.
The question
Why does it occur?
Is there any workaround for this?
Something that will fix it globally for all views that use these attributes ?
What you are seeing is the elevation overlay that they introduced to make elevation more noticeable while in Dark Theme, where shadows are not so visible. You can read about it here : https://material.io/develop/android/theming/dark/ in the section "Elevation Overlays"
The simple solution if you don't want this behavior is to add this to your theme.
<item name="elevationOverlayEnabled">false</item>
And you can also adjust it to another color or even a more subtle version of the overlay by changing the alpha:
<item name="elevationOverlayColor">#80FFFFFF</item>
EDIT with more info from https://github.com/material-components/material-components-android/issues/1133
If you want to disable it for only one component or widget, you can define a style for it with a theme overlay and use it in a specific layout:
<style name="ThemeOverlay.MyApp.ElevationOverlayDisabled" parent="">
<item name="elevationOverlayEnabled">false</item>
</style>
<style name="Widget.MyApp.CardView" parent="Widget.MaterialComponents.CardView">
<item name="materialThemeOverlay">#style/ThemeOverlay.MyApp.ElevationOverlayDisabled</item>
</style>
And if you want to disable it for all cards in your app but keep it in other components you can set that style as the default style for material card views:
# Set in your app theme
<item name="materialCardViewStyle">#style/Widget.MyApp.CardView</item>

Androidx AppCompatButton looks different from Button even on high API Level device

According to the documentation
A Button which supports compatible features on older versions of the
platform, including:
Allows dynamic tint of its background via the background tint methods
in ViewCompat. Allows setting of the background tint using
R.attr.backgroundTint and R.attr.backgroundTintMode. This will
automatically be used when you use Button in your layouts and the
top-level activity / dialog is provided by appcompat. You should only
need to manually use this class when writing custom views.
Now, this makes me assume that the following two buttons would look exactly the same on high level devices.
<androidx.appcompat.widget.AppCompatButton
android:text="AppCompatButton"
android:id="#+id/appcompatbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_below="#id/appcompatbutton"
android:id="#+id/button"
android:layout_width="wrap_content"
android:text="Button"
android:layout_height="wrap_content" />
However, here is how it actually looks:
I ran this on the following emulator:
Galaxy Nexus, API:28 (720 x 1280 xhdpi)
And when I apply buttonStyle in my appTheme like this:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="buttonStyle">#style/Widget.MaterialComponents.Button</item>
</style>
It changes the AppCompatButton but not the normal button like this:
(Note the slight difference in the rounded edges)
I also tried to create a custom button that both inherited from android.widget.Button and also androidx.appcompat.widget.AppCompatButton, both of these buttons show the same behaviour as using AppCompatButton in xml does. So it feels like the only outlier is Button in XML.
Question 1:
This all seems incredibly confusing according to me. Can someone clarify this as either a bug or feature?
EDIT 1
Doing debugging I found that the Button actually gets transformed into a MaterialButton, see the following:
Question 2:
Why is this transformation happening?
EDIT 2
Question 2 answer:
The transformation of Button to MaterialButton is due to the parent theme I was using.
Question 3:
How do you implement a custom button which works just like Button in xml would?
As a side note and personal opinion, also a slight repetition, this system is not only confusing but its hard to get it right and foolproof for future changes. In addition to this, the documentation is very poor. I would appreciate if an answer to this would be included as well, or at least a discussion regarding it, how to deal with it for example.
Short answers.
This all seems incredibly confusing according to me. Can someone clarify this as either a bug or feature?
They use different styles.
Why is this transformation happening?
There is an auto-inflation enabled which will replace <Button with <com.google.android.material.button.MaterialButton at runtime.
How do you implement a custom button which works just like Button in xml would?
You can customize the attributes in xml or the theme attributes.
Long answers.
They use different styles.
The default style of MaterialButton is Widget.MaterialComponents.Button.
This style inherits from Widget.AppCompat.Button but changes some attributes.
Here you can find the differences.
The main difference is here:
<item name="shapeAppearance">?attr/shapeAppearanceSmallComponent</item>
You can read more about shaping in the official doc.
If you navigate through the style you will find:
<style name="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerSize">#dimen/mtrl_shape_corner_size_small_component</item>
</style>
where mtrl_shape_corner_size_small_component = 4dp.
It explains the slight difference in the rounded edges.
Also you are using
<item name="buttonStyle">#style/Widget.MaterialComponents.Button</item>.
It doesn't work for the MaterialButton. You have to use:
<item name="materialButtonStyle">#style/Widget.MaterialComponents.Button</item>
The auto-inflation is here.
The MaterialComponentsViewInflater replaces some framework widgets with Material Components ones at inflation time, provided a Material Components theme is in use.
Something similar happens also with AppCompat (you can check that MaterialComponentsViewInflater extends AppCompatViewInflater).
It means that, the <Button is replaced <com.google.android.material.button.MaterialButton at runtime, if you are using a Material Theme.
There are different options. One of these is to define a custom style for buttons.
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
...
<item name="materialButtonStyle">#style/MyButtonStyle</item>
</style>
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
<item name="cornerRadius">xxx</item>
</style>
or
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
<item name="shapeAppearanceOverlay">#style/SShapeAppearanceOverlay.MyApp.Button.Rounded</item>
</style>
<style name="ShapeAppearanceOverlay.MyApp.Button.Rounded" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">xxdp</item>
</style>
I changed the <Button> to <ImageButton>
Quick and short way.
Don't forget to check & change references in java/kotlin files. Compiler will alert you any way.

Android AppCompat 22.1.1 default text color and ActionMode style

I am updating my application to use the version 22.1.1 of the Android Support Library. My application theme inherits from Theme.AppCompat.Light.DarkActionBar.
It works fine, except that all texts are white if the TextView style is set to one of the predefined style. So I end up with white texts on light background (default background color). With version 22.0.0, I had no issue.
I tried the follow in my theme, but it does not seem to work:
<item name="android:textColor">#color/black</item>
<item name="android:textColorPrimary">#color/black</item>
<item name="android:textColorPrimaryInverse">#color/black</item>
Moreover, the ActionMode now has a black background instead of white, as it used to be with 22.0.0.
Any idea on how to change this?
I was using the theme attribute in my theme to set the Toolbar theme. That's a mistake. The Toolbar theme has to be defined on the Toolbar tag directly.
For the ActionMode background color, it looks like I was taking profit of a bug without knowing it.

Styling / coloring the SwitchCompat button in Android Lollipop for Material Design

I have been trying to find resources explaining how I can style the Switch button in the Material Design theme.
This link does explain the color values and aesthetic details but doesn't say much on how I can achieve this by setting certain attributes in Material design theme.
http://www.google.com/design/spec/components/switches.html#switches-switch
If there's no direct way of setting the Switch's color, where are the drawables located that I can use to make my own version?
I have been trying to find resources explaining as to how I can style switch button in the Material Design theme.
Coloring widgets is pretty simple now with the new appcompat-v7:21.
As long as you are using appcompat-v7:21, you can replace all of your old Switch widgets with SwitchCompat widgets. So in your xml layouts, instead of using the old Switch tag, use android.support.v7.widget.SwitchCompat.
Then in your styles.xml, make sure your app's parent theme is a Theme.AppCompat theme such as Theme.AppCompat.Light.
Finally, the key is to specify your own value for colorAccent:
<item name="colorAccent">#color/my_fancy_color</item>
The color you specify for colorAccent will be used to color the widgets in your app such as SwitchCompats, EditTexts, RadioButtons, etc.
So your styles.xml might look something like:
<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#color/color_primary</item>
<!-- colorPrimaryDark is used to color the status bar -->
<item name="colorPrimaryDark">#color/color_primary_dark</item>
<!--
colorAccent is used as the default value for colorControlActivated
which is used to color widgets
-->
<item name="colorAccent">#color/my_fancy_color</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight & colorSwitchThumbNormal. -->
</style>
where are the drawables located that I can use to make my own version?
I wouldn't recommend altering the drawables directly, but they are located in
sdk/platforms/android-21/data/res/drawable-XXXX
and the files are called
btn_switch_to_off_mtrl_XXXXX.9.png
btn_switch_to_on_mtrl_XXXXX.9.png
switch_track_mtrl_alpha.9.png
To complete JDJ's answer:
There is a bug with a corrupt file in drawable-hdpi in AppCompat:
https://code.google.com/p/android/issues/detail?id=78262
To fix it, just override it with these 2 files:
https://github.com/lopespm/quick-fix-switchcompat-resources
Add them to your drawable-hdpi directory.
XML
<android.support.v7.widget.SwitchCompat
android:id="#+id/dev_switch_show_dev_only"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
And nothing was necessary in Java
In my case, I only wanted to style a particular switch, not all of them in the app. Here is how I did that using AppCompat-v7:23
xml layout:
<android.support.v7.widget.SwitchCompat
android:id="#+id/switchAffiliateMember"
android:theme="#style/Sugar.Switch.Affiliate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:textOff="No"
android:textOn="Yes" />
v21/styles.xml:
<style name="Sugar.Switch.Affiliate" parent="Base.Widget.AppCompat.CompoundButton.Switch">
<item name="colorSwitchThumbNormal">#color/red</item>
<item name="colorAccent">#color/white</item>
</style>
colorSwitchThumbNormal is the "off" state, colorAccent is the "on" state. Notice that neither of these have an "android" namespace prefix, I don't understand why, but it only works in this way for me.

override standard style with ABS

In my AndroidManifest file i do not declare a theme.
The result is:
black background and ABS with blue background, also states of list item's is blue.
thats fine.
now i want to make to set the indeterminateProgressStyle to Widget.ProgressBar.Small
Therefore i have to declare my own style like this:
<style name="Custom" parent="??">
<item name="android:actionBarStyle">#style/ActionBarIPS</item>
</style>
what should i enter in the parent parameter?
i want all style behaviors like before (black background with blue ABS and blue list item states etc as it is defined when i dont declare a theme attribute in AndroidManifest.
EDIT:
i also need to know this parent's value:
<style name="ActionBarIPS" parent="ABS with blue background">
<item name="android:indeterminateProgressStyle">#style/IndeterminateProgress</item>
</style>
the version without a style in manifest:
the version with custom style and parent=Theme.Sherlock
i want the first version with indeterminate spinner set to "small"
It's depend to your current style, It can be Theme.Sherlock, Theme.Sherlock.Light, Theme.Sherlock.ForceOverflow and etc, e.g:
<style name="Custom" parent="Theme.Sherlock or Theme.Sherlock.Light">
<item name="android:actionBarStyle">#style/ActionBarIPS</item>
<item name="android:indeterminateProgressStyle">#style/IndeterminateProgress</item>
</style>
Note: You must declare this style in style.xml in your values directory.
Edited:
You got blue ActionBar without using ABS because you're using Samsung TouchWiz default UI.
If you install your APK in non-samsung devices you won't see this blue action bar, But If you are forced to have blue actionbar then put the following image in your drawable directory and set it as your actionbar background through:
getSupportActionBar().setBackgroundDrawable(getResources()
.getDrawable(R.drawable.TouchWiz_ActionBar_Bg));
Try to use "Theme.Sherlock" as a parent. Also I suggest to add:
<item name="actionBarStyle">#style/ActionBarIPS</item>

Categories

Resources