Is there a way to reference a color resource with modified alpha value in a xml resource file? What I'm looking for is something like this:
<!-- base color -->
<color name="myColor">#19AEE0</color>
<!-- redefined color with alpha - not particularly elegant -->
<color name="myColor2">#8019AEE0</color>
<!-- referenced color with alpha -->
<color name="myColorTransparent" alpha="0.5">#color/myColor</color>
I am aware that this can be easily done programmatically, but doing it the declarative way would be much clearer and more readable when defining several transparency values for the same color.
After searching around a bit to set the color accent as the ripple drawable's color, I've found that it can be done with the aid of a <selector>.
Add a color resource folder if not existing and create a new file there, whose base name will be used as color resource. For example, name it my_color_transparent.xml. Then, paste the following contents.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="#color/myColor"
android:alpha=".5" />
</selector>
At this point, you can reference it as #color/my_color_transparent via XML or programmatically as usual, like colors in the values folder.
NOTE:
The android:alpha attribute is applied as a mask, so the alpha is multiplied by that of the color specified via the android:color attribute. As an instance, if #color/myColor were 20% opaque and android:alpha were .5, then the opacity of #color/my_color_transparent would be 10%.
Related
I'm writing a really simple code but encountered a strange problem. I'm using a ColorStateList in order to tint my AppCompatImageButton. Here is the code:
In layout:
<android.support.v7.widget.AppCompatImageButton
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="#drawable/ic_my_image"
app:tint="#color/my_image_tint_color"
app:tintMode="src_in"
android:scaleType="fitXY"/>
my_image_tint_color.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/colorGray" android:state_enabled="false" />
<item android:color="#color/colorAccent" />
</selector>
This code works correctly and it tints my image button with colorGray if disabled while it is tinted by colorAccent by default.
Now I want to change my button picture with an image with multiple colors. So I decided to tint my button with colorGray if disabled while keeping images original colors if not disabled. But now I'm stuck. Is there anything that defines No Color in android ColorStateList? Because I need to define a color for my default state in ColorStateList. If I don't specify anything for default state, Button will not be shown(it seems like transparent as default color and button will be tinted by transparent color). I tried to specify #null as color in color list, but it didn't work too.
I know I can do it in code, but I prefer to do this in XML. Is there any way to tint button gray if disabled while keeping original colors if not in XML?
After a while, I found a proper approach for my problem and since no one suggested correct approach, I decided to post it myself. Maybe it will be useful for someone else.
For my problem, I need to use multiply tint mode which can solve my problem. Here how you use it:
In layout:
<android.support.v7.widget.AppCompatImageButton
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="#drawable/ic_my_image"
app:tint="#color/my_image_tint_color"
app:tintMode="multiply"
android:scaleType="fitXY"/>
my_image_tint_color.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#20909090" android:state_enabled="false" />
<item android:color="#FFFFFFFF" />
</selector>
With this code, you see your button as full-colored when it is enabled. But if you disable your button, it becomes gray-scale.
How this works:
The multiply tint mode is defined by following equation:
Multiplies the color and alpha channels of the drawable with those of
the tint. [Sa * Da, Sc * Dc]
This tint mode can only decrease color values, so it can used only to darken your colors. Just to understand following, remember that you need to scale 0x00-0xFF color values into 0.0f-1.0f, so 0x00 will be equal to 0.0f and 0xFF will be equal to 1.0f. In general it means you need to work with floating point values as color number where:
floating_point_color = byte_color / 255
In addition, remember that in 4 bytes color format like #AABBCCDD, AA is alpha, and other bytes show red, green and blue.
OK, how you use this feature for my problem?
I want to keep image colors when button is enabled. So I need to keep image alpha and colors as is. Then I need to use color #FFFFFFFF for my enable color. In this case color and alpha of each pixel of my original picture will be multiplied by 1.0f(since byte is 0xFF), so there will be no change in original image.
In order to gray scale my image in disabled mode, I used #20909090 value. First I used 90 for red, green, and blue. Because I want to darken these color, but all in same scale. This darken all colors in same scale, so your color will not be something abnormal. With this scale a white color become light gray (0x909090) while black stay black. But then I used 20 for my color alpha to make resulting colors more transparent. In this way, if your image background is white, you will see a great toned down gray scale image from original image.
This solved my problem, but I find this as a really useful example of tintMode property. I will everyone enjoyed this small tutorial.
You should have try with SRC_ATOP mode, I think it would have done what you expect.
In layout:
<android.support.v7.widget.AppCompatImageButton
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="#drawable/ic_my_image"
app:tint="#color/my_image_tint_color"
app:tintMode="src_atop"
android:scaleType="fitXY"/>
my_image_tint_color.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/colorGray" android:state_enabled="false" />
<item android:color="#color/transparent" />
</selector>
Adding 00 in the beginning will make it 100% transparent and adding FF will make it 100% solid.
Suppose your preferred color is red #FF0000
So, 100% transparent color is: #00ff0000 and 100% solid color is: #ffff0000
And any value in between 00 to ff can be used to adjust the transparency.
So add the colors transparent in colors.xml and then access it from drawable
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="trasnparent">#00ff0000</color>
</resources>
my_image_tint_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/colorGray" android:state_enabled="false" />
<item android:color="#color/colorAccent"
<item android:color="#color/transparent" android:state_something="true"/>
</selector>
please let me know if it helps you and give a vote. Thanks
You can add transparent color like #00ff0000
I try to change the color based on my theme. My TextView is using color-selector with different states for enabled and disabled and I want to use my theme based color in this selector.
I have followed this solution: android themes - defining colours in custom themes
My selector used as android:textColor in my view looks like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:color="#ffffff" />
<item android:state_enabled="false" android:color="?attr/ThemeTest"/>
</selector>
with ThemeTest being my custom attribut which has a color assigned in my themes. If I use this selector as my textColor, the color is actually not what I picked but just a simple plain RED! HOWEVER if I use the custom attribut directly in my view
android:textColor="?ThemeTest"
then it works but I obviously want to do this based on the change of state of my view...
Does anybody understand this behaviour and know how to fix it? Thanks in advance!
Using a theme attribute inside a color selector XML file is only supported in the most recent versions of Android. To overcome this limitation you need to create one color selector file for each theme, and fill them with plain colors. Then create a theme attribute which points to the correct color selector depending on the theme.
source: https://plus.google.com/102404231349657584821/posts/XEeehfwanGy
edit: tested and it works flawlessly!
I'm trying to define round drawable which needs primary color of material theme. Here's my xml code:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<solid android:color="?attr/colorPrimary"></solid>
</shape>
But I'm getting InflateException. I've read that we can not use attributes in drawable xml. So any workaround for this ?
If you are using API 21 or greater, you should use:
<solid android:color="?android:colorPrimary"></solid>
For older APIs you should just type:
<solid android:color="?colorPrimary"></solid>
Is your colorPrimary stored in yours colors.xml? If so, just reference it like #color/colorPrimary.
If not, just define it in colors.xml and reference it. These are the default teal color of meterial straight from the source code. I think material_deep_teal_500 is what you are looking for.
<!-- Primary & accent colors -->
<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_500">#ff009688</color>
<color name="material_blue_grey_800">#ff37474f</color>
<color name="material_blue_grey_900">#ff263238</color>
<color name="material_blue_grey_950">#ff21272b</color>
You can't use attribute values in drawables.
You would be best to use a semi-transparent white/black (depending on if you are light or dark) like #44FFFFFF and overlaying over the primary color background. You'll notice most material drawables are a shade lighter/darker over a primary color background...
Otherwise, if you need the color duplicated - you will have to use #color/myPrimaryColor - which should be the same as what you defined in your theme as primaryColor.
I want to see the definition of divider vertical, I'm not sure exactly what the meaning of an attribute is but when click through to the definition of the attribute in intellij I'm taken to attrs.xml and shown the following, which does not help.
<!-- Drawable to use for generic vertical dividers. -->
<attr name="dividerVertical" format="reference" />
My specific problem is I'm trying to achieve a list with an inset list divider with the dividerVertical style. In order to do this I have defined my own inset shape.
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="30dip"
android:insetRight="30dip">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?android:attr/dividerVertical"/>
</shape>
</inset>
This does not work as android will not accept the "?android:attr/dividerVertical" as the colour. It would not work anyway as divider vertical has an alpha component, so what I need to know is what colour and opacity is divider vertical?? But ideally Id like to know how I can check the source of any resource components in android so that I never encounter this problem again.
Thanks
Piers
According to developer.android, ?[<package_name>:][<resource_type>/]<resource_name> is used for References To Theme Attributes.
So, for ?android:attr/dividerVertical, you can navigate to android-sdk\platforms\android-16\data\res\values. There, looking at attrs.xml, you can see
<!-- Drawable to use for generic vertical dividers. -->
<attr name="dividerVertical" format="reference" />
But this is just a "reference" for the theme. Looking at your target platform's themes.xml, you can find many lines for different themes something like
<item name="dividerVertical">#drawable/divider_vertical_dark</item>
The line you want is the line contained within the theme element for the theme you are using. It's easiest to copy the whole theme element to another text file and search there. Which brings up
<item name="dividerVertical">?android:attr/listDivider</item>
Searching again in the theme for "listDivider" you can find
<item name="listDivider">#drawable/list_divider_holo_dark</item>
So that is a drawable.
Searching for matching files you can find
./platforms/android-16/data/res/drawable-hdpi/list_divider_holo_dark.9.png
./platforms/android-16/data/res/drawable-mdpi/list_divider_holo_dark.9.png
./platforms/android-16/data/res/drawable-xhdpi/list_divider_holo_dark.9.png
These pngs happen to be 9 patches with the content consisting of a white square with an alpha value of 38.
dividerVertical is defined in theme you are using. For example this is divider image for Holo.Light theme. There is <item name="dividerVertical">?android:attr/listDivider</item> row in themes.xml. This line is referencing forward to <item name="listDivider">#drawable/list_divider_holo_light</item>, from this you can see that it is drawable and not a color.
I want to create a style which uses the android textColorPrimary as a background color.
I tried the following which does not work, the result is my layout not beeing displayed at all.
<style name="horizontalLine">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">1dp</item>
<item name="android:background">?android:attr/textColorPrimary</item>
</style>
How do I use textColorPrimary as background color in a style?
This syntax seems to work for me, when trying to use attributes:
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="?android:textColorPrimary"
android:text="Hello"/>
(or)
<style name="MyStyle">
<item name="android:textColor">?android:textColorPrimary</item>
</style>
I can change the app theme from Holo to Holo.Light and the text color will change automatically to fit.
It doesn't work when I set it as a background of a View though - Android will crash complaining that the drawable referenced is a state list that does not specify drawables (it is a state list of colors).
Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #2: <item> tag requires a 'drawable' attribute or child tag defining a drawable
at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:178)
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:885)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:822)
at android.content.res.Resources.loadDrawable(Resources.java:1950)
... 39 more
I am using HoloEverywhere which lets me reference the resources directly, but you should get a similar problem in the native case. I don't think the primary, non-selected, non-activated (etc.) color used as a component in the state list xml is exposed through an attribute.
In any case, the text color used is dependent on the theme that you, the app developer, chooses. If you choose to use the Holo (dark) theme then your text will be a light color, and the user won't be able to affect this. You don't need to make the your line color dynamic for your app.
To apply the ?android:attr/textColorPrimary attribute as the background of a view, you have two options.
First Option
The first option is to define a shape drawable which gets its color from the ?android:attr/textColorPrimary attribute, as follows...
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="?android:attr/textColorPrimary" />
</shape>
... and, assuming you've named this drawable rectangle_shape_with_primary_text_color.xml and placed it in your application's res/drawable folder, you can set it as the background of your style as follows...
<item name="android:background">#drawable/rectangle_shape_with_primary_text_color</item>
... or set it as the background of your view directly, as follows...
android:background="#drawable/rectangle_shape_with_primary_text_color"
Second option
The second option is to set the backgroundTint property of your style or view.
You can set the backgroundTint property of your style as follows:
<style name="horizontalLine">
<item name="android:background">#android:color/white</item>
<item name="android:backgroundTint">?android:attr/textColorPrimary</item>
</style>
Or you can set the backgroundTint property of your view directly as follows:
<View
android:id="#+id/horizontalLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#android:color/white"
android:backgroundTint="?android:attr/textColorPrimary" />
Note that the exact value of the background property with this approach is not important but it must be set and it cannot be set to #null or #android:color/transparent.
The error message I get for this is:
org.xmlpull.v1.XmlPullParserException: Binary XML file line #18: <item> tag requires a 'drawable' attribute or child tag defining a drawable
Doing a little digging, the specs say the background attribute should support either a colour, or reference to a drawable resource:
... Looking at the resource you're referencing, it is a StateListDrawable.
platforms/android-17/data/res/color/primary_text_dark.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#android:color/bright_foreground_dark_disabled"/>
<item android:state_window_focused="false" android:color="#android:color/bright_foreground_dark"/>
<item android:state_pressed="true" android:color="#android:color/bright_foreground_dark_inverse"/>
<item android:state_selected="true" android:color="#android:color/bright_foreground_dark_inverse"/>
<item android:state_activated="true" android:color="#android:color/bright_foreground_dark_inverse"/>
<item android:color="#android:color/bright_foreground_dark"/> <!-- not selected -->
</selector>
However, the docs for StateListDrawable also explicitly say the drawable attribute must be defined for item elements:
https://developer.android.com/guide/topics/resources/drawable-resource.html
<item>
Defines a drawable to use during certain states, as described by its attributes. Must be a child of a <selector> element.
attributes:
android:drawable
Drawable resource. Required. Reference to a drawable resource.
... which isn't the case for the case for primary_text_dark.xml. So, it's not working because the drawable you're referencing doesn't seem to conform to the spec.
I think the workaround is to reference the colour that's used in primary_text_dark for the default state: bright_foreground_dark. Seeing as that's not public, you need to go directly to the one it references, which is:
android:background="#android:color/background_light"
I take it that you want to use native android primary text color.
<item name="android:background">#android:color/primary_text_dark</item>