'preferenceCategory' style background isn't working in Lollipop - android

I used to use the following style to set my preferenceCategory.
But as it looks, the background color isn't applied when running on Lollipop.
<style name="Theme.Preference.Category" parent="#android:attr/listSeparatorTextViewStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#color/primary_light</item>
<item name="android:background">#color/primary_dark</item>
<item name="android:paddingTop">4dp</item>
<item name="android:paddingBottom">4dp</item>
<item name="android:paddingLeft">4dp</item>
</style>
And I set it : <item name="android:listSeparatorTextViewStyle">#style/Theme.Preference.Category</item> in my theme.
is the background attribute changed in Lollipop ?

Because of the way Preference is structured, you will need to create a layout with these properties and set the android:layout attribute in the style referenced by your themes's android:preferenceCategoryStyle.
The example code below is suitable for Material. You will need to find appropriate substitutes if you're targeting Holo or AppCompat.
res/values/themes.xml:
<style name="MyAppTheme" parent="#android:style/Theme.Material.Light.DarkActionBar">
...
<item name="android:preferenceCategoryStyle">#style/MyCategoryPreferenceStyle</item>
</style>
res/values/styles.xml
<style name="MyCategoryPreferenceStyle" parent="#android:style/Preference.Material.Category">
...
<item name="android:layout">#layout/my_category_preference</item>
</style>
You will apply whatever attributes you need in the following layout. You could also continue to use a style and specify a style attribute on the TextView element, but just make sure you're using a valid parent style.
res/layout/my_category_preference.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:textAppearance="#android:style/TextAppearance.Material.Body2"
android:textColor="?android:attr/colorAccent"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="16dip" />

Related

Outlined Edit Text stroke color

I'm trying to style a TextInputLayout:
<style name="AppTheme.TextInputLayout.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">#color/text_input_layout_outlined_box_stroke</item>
<item name="hintTextColor">#color/text_input_layout_outlined_box_stroke</item>
</style>
And that's the color selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/green_2" android:state_focused="true" />
<item android:color="#color/green_2" android:state_hovered="true" />
<item android:color="#color/green_2" android:state_enabled="false" />
<item android:color="#color/green_2" />
</selector>
And that's my View:
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:hint="#string/surname">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
Why this works as expected applying to the view:
style="#style/AppTheme.TextInputLayout.OutlinedBox"
And theme is not working:
android:theme="#style/AppTheme.TextInputLayout.OutlinedBox"
I'm not getting the differences between these two...
EDIT: maybe I've found this to avoid repeating for each view:
<item name="textInputStyle">#style/AppTheme.TextInputLayout.OutlinedBox</item>
You can define a style:
<style name="AppTheme.TextInputLayout.OutlinedBox" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="boxStrokeColor">#color/text_input_layout_outlined_box_stroke</item>
<item name="hintTextColor">#color/text_input_layout_outlined_box_stroke</item>
</style>
and apply it to a view with:
<com.google.android.material.textfield.TextInputLayout
style="#style/AppTheme.TextInputLayout.OutlinedBox"
..>
At the same time you can define:
<style name="textInputPrimaryColor" parent="">
<item name="colorPrimary">#color/.....</item>
</style>
and then use it with the android:theme attribute:
<com.google.android.material.textfield.TextInputLayout
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:theme="#style/textInputPrimaryColor"
..>
In this way you can modify the theme attributes for that view and any child views, which is useful for overriding theme color palettes in a specific portion of your interface.
More info here.
In this way you are overriding the colorPrimary attribute in the style Widget.MaterialComponents.TextInputLayout.OutlinedBox.
For example it is the default selector used by the boxStrokeColor.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimary" android:state_focused="true"/>
<item android:alpha="0.87" android:color="?attr/colorOnSurface" android:state_hovered="true"/>
<item android:alpha="0.12" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
<item android:alpha="0.38" android:color="?attr/colorOnSurface"/>
</selector>
Using the android:theme="#style/textInputPrimaryColor" you can are changing the colorPrimary for this view without extending the style.
You can achieve the same behavior using the materialThemeOverlay attribute in your style:
<style name="My.OutlinedBox" parent="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<item name="materialThemeOverlay">#style/ThemeOverlay.My.OutlinedBox</item>
</style>
with:
<style name="ThemeOverlay.My.OutlinedBox" parent="ThemeOverlay.MaterialComponents.TextInputEditText.OutlinedBox">
<item name="colorPrimary">#color/......</item>
</style>
and then apply it to your view:
<com.google.android.material.textfield.TextInputLayout
style="#style/My.OutlinedBox"
..>
I want all my items with style OutlinedBox to have the box green colored"? I'd like to avoid repeating theme and style for every view...I mean a "global" style that inherit from AppTheme, which is already applied to the whole application in the manifest
Currently there isn't an attribute to define a style only for the TextInputLayout with an OutlinedBox style.
You can only assign a global style for all TextInputLayout views in your app using the textInputStyle attribute in your app theme:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
...
<item name="textInputStyle">#style/My.OutlinedBox</item>
</style>
Note: it requires the version 1.1.0 of the Material Components Library.

Is it possible to change TextInputLayout colors programmatically without using theme?

I use this in my theme now I am wondering if possible without using theme either programmatically changing colors of textinputlayout
or I can change in xml still without using theme, as I need to fetch colors dynamically and I write code for that or do databinding in xml.
<item name="colorControlActivated">#color/primaryTextColor</item>
<item name="android:textColorHint">#color/primaryTextColor</item>
<item name="android:textColor">#color/primaryTextColor</item>
<item name="android:editTextColor">#color/primaryTextColor</item>```
Yes, we can use setBackgroundColor().
But in your case I think you need to build your own style, here is an example:
Creating TextInputLayout Theme
Let's define a couple of text Styles that will be used as part of the theme. These styles correspond to the different texts used, such as the Hint and Error texts.
<style name="ErrorText" parent="TextAppearance.AppCompat">
<item name="android:textColor">#android:color/red</item>
<item name="android:textSize">16sp</item>
</style>
<style name="HintText" parent="TextAppearance.AppCompat">
<item name="android:textColor">#android:color/white</item>
<item name="android:textSize">14sp</item>
</style>
Then, we create our TextInputLayout theme, referencing the above:
<style name="TextInputLayoutAppearance" parent="Widget.Design.TextInputLayout">
<!-- reference our hint & error styles -->
<item name="hintTextAppearance">#style/HintText</item>
<item name="errorTextAppearance">#style/ErrorText</item>
<item name="android:textColor">#color/user_input_color</item>
<item name="android:textColorHint">#color/unfocused_color</item>
<item name="colorControlNormal">#color/white</item>
<item name="colorControlActivated">#color/blue</item>
<item name="colorControlHighlight">#color/green</item>
</style>
And for the last step, we build our layout.xml using the android:theme attribute with the style we defined above:
<android.support.design.widget.TextInputLayout
android:theme="#style/TextInputLayoutAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/hint_email"/>
</android.support.design.widget.TextInputLayout>

"android:theme" attribute ignore gravity

There is my app_style.xml
<style name="EditText.LargePassword" parent="Widget.AppCompat.EditText">
<item name="android:gravity">center_horizontal</item>
<item name="android:imeOptions">flagNoExtractUi</item>
<item name="android:inputType">numberPassword</item>
<item name="android:textColorPrimary">#color/white</item>
<item name="android:textColor">#color/white</item>
<item name="android:textColorHint">#color/white</item>
<item name="android:textSize">56sp</item>
<item name="colorControlNormal">#color/white</item>
<item name="colorControlActivated">#color/white</item>
<item name="colorControlHighlight">#color/white</item>
</style>
And part of layout:
<EditText
android:id="#+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/giant_margin"
android:layout_marginRight="#dimen/giant_margin"
android:theme="#style/EditText.LargePassword"
tools:text="12345"
tools:ignore="TextFields"
/>
As you can see, I apply EditText.LargePassword style via android:theme attribute:
There is a problem: every attribute applied, except android:gravity.
Okay, let's try with style attribute:
style="#style/EditText.LargePassword"
Boom! Indicator and cursor are gone:
But now android:gravity="center_horizontal" works.
As I read, style == theme, but style don't apply to children of View. Are there any differences? Is it a bug?
Styles and Themes whilst similar are not exactly the same. A style applies only to one specific view whereas a theme will apply to a View/ViewGroup/Activity and all of its children.
In your case you are actually mixing attributes from both styles and themes into one setting which is why it's not working properly. To get both you will need to take the three colorControl attributes and define them as a theme:
<style name="LargePasswordTheme" >
<item name="colorControlNormal">#color/white</item>
<item name="colorControlActivated">#color/white</item>
<item name="colorControlHighlight">#color/white</item>
</style>
The rest can stay as a style. Then you can add both this and your style to the EditText:
<EditText
android:id="#+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/giant_margin"
android:layout_marginRight="#dimen/giant_margin"
android:theme="#style/LargePasswordTheme"
android:style="#style/EditText.LargePassword"
tools:text="12345"
tools:ignore="TextFields"
/>
Further reading with good explanations can be found here and here.

AppCompat Toolbar: set toolbar theme from upper theme

I have a "light"-themed application with:
<style name="Theme.MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/primary</item>
<item name="colorPrimaryDark">#color/primary_dark</item>
<item name="colorAccent">#color/accent</item>
<!-- etc. -->
</style>
I want my Toolbars to be dark themed, so I have setup the following style, just as suggested by Chris Banes:
<style name="Theme.MyTheme.Toolbar" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<!-- stuff -->
</style>
Then, by adding android:theme="#style/Theme.ByodTheme.Toolbar" to my android.support.v7.widget.Toolbar, everything works as expected (even though the Android Studio preview doesn't show white colors for the title, it works on devices):
Now, instead of specifying android:theme for every Toolbar in my application, I'd like to specify the style in my main theme and forget about it. I have tried the toolbarStyle property, but it looks like it doesn't work as intended, since it completely messes up standard properties:
I have also made other attempts by making the Toolbar theme inherit from Widget.AppCompat.Toolbar, and by changing titleTextAppearance and subtitleTextAppearance, but then it looks impossible to change the overflow icon color (yes, I have tried to set actionOverflowButtonStyle and inherit that style from Widget.AppCompat.ActionButton.Overflow, with no success in changing the overflow icon color).
Is there a way to specify, from a single point, the main theme for every toolbar in my application?
You can use a custom attribute for this -- basically just set your toolbars to use a custom value that you'll define in the theme.
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="?attr/toolbar_theme"
/>
The important part there is just android:theme="?attr/toolbar_theme" which references a custom attribute from the current theme.
You will need to declare this attribute somewhere, like so:
<resources>
<attr name="toolbar_theme" format="reference" />
</resources>
Then you can define what value you want the toolbar to use by assigning a value to toolbar_theme in your theme. For example, to make it use Theme.MyTheme.Toolbar you could define it like so:
<style name="Theme.MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/primary</item>
<item name="colorPrimaryDark">#color/primary_dark</item>
<item name="colorAccent">#color/accent</item>
<!-- etc. -->
<item name="toolbar_theme">#style/Theme.MyTheme.Toolbar</item>
</style>
The nice thing about using an attribute is that it lets your app have multiple themes, and that single toolbar resource will use whatever value you've set within the theme.
If I understand the question correctly, you want to set your app's theme once and apply all the styling to all the Toolbars in every activity/fragment.
If so, I would recommend this approach:
<style name="MyTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:textColorPrimary">#color/MyColorPrimaryText</item>
<item name="android:windowBackground">#color/MyColorWindowBackground</item>
<item name="colorPrimary">#color/MyColorPrimary</item>
<item name="colorPrimaryDark">#color/MyColorPrimaryDark</item>
<item name="colorAccent">#color/MyColorAccent</item>
<item name="colorControlNormal">#color/MyColorControlNormal</item>
<item name="colorControlHighlight">#color/MyColorControlHighlight</item>
<item name="toolbarStyle">#style/MyToolbar</item>
<item name="windowActionModeOverlay">true</item>
<item name="actionModeBackground">#color/MyColorPrimaryDark</item>
</style>
<style name="MyToolbar" parent="Widget.AppCompat.Toolbar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:minHeight">#dimen/MyToolbarMinHeight</item>
<item name="android:gravity">center_vertical</item>
<item name="android:background">#color/MyColorPrimary</item>
<item name="android:elevation" tools:ignore="NewApi">10dp</item>
<item name="theme">#style/MyToolbarTheme</item>
</style>
<style name="MyToolbarTheme" parent="ThemeOverlay.AppCompat.ActionBar">
<item name="android:textColorPrimary">#color/MyColorPrimaryText</item>
<item name="colorControlNormal">#color/MyToolbarColorControlNormal</item>
<item name="colorControlHighlight">#color/MyToolbarColorControlHighlight</item>
</style>
Then in your manifest:
<application
android:name=".MyApp"
android:theme="#style/MyTheme">
<activity android:name=".MyActivity1"/>
<activity android:name=".MyActivity2"/>
</application>
Then in your activity layout files, include the toolbar with:
style="?attr/toolbarStyle"
So myActivity1.xml layout file would look like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/toolbarStyle" />
<!-- ETC. -->
</LinearLayout>
And notice that to change the navigation back button color or the overflow button colors, you can set:
<item name="colorControlNormal">#color/MyColorControlNormal</item>
<item name="colorControlHighlight">#color/MyColorControlHighlight</item>
And:
<item name="android:textColorPrimary">#color/MyColorPrimaryText</item>
Can be used to update the actionbar text color but you'd define it in the Toolbar theme.
Hope this helps.

In Android, can apply different themes in a single XML layout's TextView at runtime without creating a custom widget?

I've seen similar questions here before, but none of them had a satisfactory answer. Basically, I want to have one layout instead of multiple ones and be able to apply themes at runtime. For example, let's take this layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="SAMPLE HEADING"
style="#style/Heading" />
</LinearLayout>
And the themes and styles are set up as follows:
<style name="AppTheme.Dark" parent="AppTheme">
<item name="android:radioButtonStyle">#style/radioButton.Dark</item>
<item name="android:checkboxStyle">#style/checkbox.Dark</item>
</style>
<style name="AppTheme.Light" parent="AppTheme">
<item name="android:radioButtonStyle">#style/radioButton.Ios</item>
<item name="android:checkboxStyle">#style/checkbox.Ios</item>
</style>
<style name="Heading">
<item name="android:typeface">sans</item>
<item name="android:textStyle">bold</item>
</style>
<style name="Heading.Dark" parent="Heading">
<item name="android:textColor">#color/red</item>
<item name="android:background">#drawable/dark_bg</item>
<item name="android:textSize">16dip</item>
</style>
<style name="Heading.Light" parent="Heading">
<item name="android:textColor">#color/black</item>
<item name="android:background">#drawable/light_bg</item>
<item name="android:textSize">17dip</item>
</style>
So, I want to be able to apply the dark and light Heading styles to that TextView by simply applying the dark or light AppTheme. And I don't want to apply those styles to all TextViews, but only specific ones. I also don't want to do this programmatically because there are way too many TextViews that would need this done.
Is there a way to do that, or do i have to create two identical XML layouts, where one uses the Heading.Light style and the other uses Heading.Dark?
First, your use of parent="..." property is incorrect.
As official docs state:
"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."
So, declaring your style name as Heading.Light is enough to specify that it's parent style is Heading.
Now to your question. Create a res/values/attrs.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="myTextViewColor" format="reference|color" />
</resources>
Then in your styles.xml you would declare your theme as follows:
<style name="AppTheme">
<!--parent style. could be overriden by Dark and Light theme -->
</style>
<style name="AppTheme.Dark">
...
<item name="myTextViewColor">#color/red</item>
</style>
<style name="AppTheme.Light">
...
<item name="myTextViewColor">#color/black</item>
</style>
<style name="Heading">
<item name="android:typeface">sans</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">16dip</item>
</style>
Now when you apply
<TextView ... style="#style/Heading" android:textColor="?myTextViewColor />
everything should work just fine. Just make sure you apply AppTheme.Light or AppTheme.Dark theme in your app (as AppTheme parent theme would not know the value of your custom attribute).
Edit: Also, as user496854 suggested, there's another simple workaround.
Declare headingStyle attr as a reference:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="headingStyle" format="reference" />
</resources>
Then in our AppTheme.Dark and AppTheme.Light styles we would point to a corresponding heading style:
<style name="AppTheme.Dark">
...
<item name="headingStyle">#style/Heading.Dark</item>
</style>
<style name="AppTheme.Light">
...
<item name="headingStyle">#style/Heading.Light</item>
</style>
I would suggest you to crate a class that extends TextView and apply your style in it. Use this textView where you want textview with this them and simple TextView where you don't need.

Categories

Resources