Injecting attributes into drawable resources files on Android - android

I'm trying to find the best way to reuse resource files. In this example, I'm trying to create a ghost button for Android. I have a ghost button drawable xml file that defines the background, but I would like to be able to specify the color (specifically without using theme based defined colors).
ghost.xml:
<shape
android:shape="rectangle">
<corners android:radius="#dimen/ghost_button_corner" />
<solid android:color="#android:color/transparent" />
<stroke android:width="#dimen/ghost_button_stroke_size" android:color="?attr/ghost_color" /></shape>
ghost_style.xml:
<!-- STYLABLE -->
<attr name="ghost_color" format="reference" />
<!-- STYLES -->
<style name="GhostButtonBlack" parent="#style/GhostButton">
<item name="ghost_color">#android:color/black</item>
</style>
<style name="GhostButtonWhite" parent="#style/GhostButton">
<item name="ghost_color">#android:color/white</item>
</style>
<!-- BASE -->
<style name="GhostButton" parent="android:style/Widget.Button">
<item name="android:textSize">#dimen/ghost_button_text_size</item>
<item name="android:textColor">?attr/ghost_color</item>
<item name="android:background">#drawable/ghost</item>
</style>
within layout.xml:
<Button
style="#style/GhostButtonWhite"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:text="White Ghost Button" />
But I'm currently getting the following exception:
Caused by: java.lang.RuntimeException: Failed to resolve attribute at index 5
at android.content.res.TypedArray.getColorStateList(TypedArray.java:425)
at android.widget.TextView.<init>(TextView.java:987)
NOTE
I recognize this type of styling can be done via code. My ideal solution would involve no code; just resources.

I think you should get the GradientDrawable from your shape and apply a different color programmaticaly like this:
GradientDrawable mygrad = (GradientDrawable) view.getBackground();
color = inflater.getContext().getResources().getColor(yourcolorinstyles);
mygrad.setColor(color);

Related

Unable to use ?customColor in drawable

I'm trying to define a custom color for my app's theme.
Here is how I do:
define custom attribute:
<declare-styleable name="ApplicationStyle">
<attr name="colorWeekdaysBg" format="color"/>
</declare-styleable>
Define an application style:
<style name="ApplicationStyle" parent="Theme.AppCompat.NoActionBar">
<item name="android:editTextStyle">#style/EditTextStyle</item>
<item name="colorPrimaryDark">#color/dark_blue</item>
<item name="colorPrimary">#color/dark_blue</item>
<item name="colorAccent">#color/dark_blue</item>
<item name="colorWeekdaysBg">#color/access_weekdays</item>
</style>
Set style in the manifest:
<application
android:name=".App"
android:icon="#drawable/icon_launcher"
android:label="#string/app_name"
android:theme="#style/ApplicationStyle">
Use this attribute in the drawable xml:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="-1dp">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="?colorWeekdaysBg" />
<corners
android:bottomLeftRadius="100dp"
android:topLeftRadius="100dp" />
</shape>
</item>
</layer-list>
But for some reason it does not apply my color to the drawable. It applies a transparent color instead.
One more strange thing is if I replace my ?colorWeekdaysBg with ?colorAccent, which is defined in the Theme.AppCompat, then it applies correct color.
So finally the question: Do you have any idea why it doesn't work, and how to fix it?
As per answer give by mudit here it is a bug in the pre-lollipop OS.
It is reported in Google's Issue Tracker.
In the devices which have Android Lollipop and above OS version it will work fine.
Check below code:
attr.xml
<declare-styleable name="AppTheme">
<attr name="colorWeekdaysBg" format="color|reference" /> <!-- Or you can keep color only. It will be ok -->
</declare-styleable>
You have to set the attribute in the v21 style file. Might be you missed this one.
v21\styles.xml
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:splitMotionEvents">false</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:navigationBarColor">#color/black</item>
<item name="colorWeekdaysBg">#color/access_weekdays</item>
</style>
Create two drawable files to get it work on all devices. One for normal i.e. pre-lollipop version and another for Lollipop and above i.e. v21 drawable.
your_drawable.xml In this you have to set color from the color file.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="-1dp">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#color/access_weekdays" />
<corners
android:bottomLeftRadius="100dp"
android:topLeftRadius="100dp" />
</shape>
</item>
</layer-list>
v21\your_drawable.xml In this file you can set custom attribute like you did.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="-1dp">
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="?colorWeekdaysBg" />
<corners
android:bottomLeftRadius="100dp"
android:topLeftRadius="100dp" />
</shape>
</item>
</layer-list>
your_layout.xml In your layout you can give that drawable as below
<Button
android:id="#+id/btnTest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/your_drawable"
android:text="Test Text" />
Now check the answers of your questions.
But for some reason it does not apply my color to the drawable. It applies a transparent color instead.
Because you may not have defined your attribute in v21 style.xml file
One more strange thing is if I replace my ?colorWeekdaysBg with ?colorAccent, which is defined in the Theme.AppCompat, then it applies the correct color.
Android Studio displays color in preview but when you will run the application and reached on that screen your application will be crash with the Error inflating class error
android.view.InflateException: Binary XML file line #68: Error inflating class Button
So finally the question: Do you have any idea why it doesn't work, and how to fix it?
I think now you have got the idea that why it doesn't work and how to fix it.

Using attributes for bitmap src inside a drawable selector

I'm trying to create custom themes for my app and therefore, would like the selector to pick up the right drawable based on the current theme. Unfortunately, doesn't look like any image gets picked up at all.
This is my selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<bitmap android:src="?attr/test_a"
android:gravity="center" />
</item>
<item android:state_focused="true">
<bitmap android:src="?attr/test_a"
android:gravity="center" />
</item>
<item android:state_activated="true">
<bitmap android:src="?attr/test_a"
android:gravity="center" />
</item>
<item>
<bitmap android:src="?attr/test_b"
android:gravity="center" />
</item>
</selector>
My attributes are defined in attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="test_a" format="reference"/>
<attr name="test_b" format="reference"/>
</resources>
And my theme has the following:
<style name="MyTheme" parent="Theme.AppCompat.NoActionBar">
<item name="test_a">#drawable/test_a_dark</item>
<item name="test_b">#drawable/test_b_dark</item>
</style>
<style name="MyTheme.Light">
<item name="test_a">#drawable/test_a_light</item>
<item name="test_b">#drawable/test_b_light</item>
</style>
The theme is applied in the manifest as required. I have seen some questions on SO around this saying that there's a problem Pre-Lolipop, however, I'm testing on Marshmellow.
Still not sure why this happens but in case this is useful for someone, as a workaround I did the following:
1) Created two selectors - one for the dark theme, pointing directly at the dark drawables, and one for the light theme
2) Created one attribute with type reference
3) Modified the theme to use that attribute point at the selector instead of the drawable

How to change my android application's theme?

How can i change theme of my app.Buttons and other things are in an ordinary look.i just want to change those ordinary look.
Use appcompat in your app, it gives some of the good things from lollipop to all pre-lollipop supported apps. http://android-developers.blogspot.in/2014/10/appcompat-v21-material-design-for-pre.html
I have mimicked complete material design using appcompat.
Widgets supported by appcompat are:
EditText
Spinner
CheckBox
RadioButton
Switch (use the new android.support.v7.widget.SwitchCompat)
CheckedTextView
For styling button use the below style:
<style name="Button">
<item name="android:textColor">#color/white</item>
<item name="android:padding">0dp</item>
<item name="android:minWidth">88dp</item>
<item name="android:minHeight">36dp</item>
<item name="android:layout_margin">3dp</item>
<item name="android:elevation">1dp</item>
<item name="android:translationZ">1dp</item>
<item name="android:background">#drawable/primary_round</item>
</style>
Also you can use this library to prep up your app with material design, https://github.com/navasmdc/MaterialDesignLibrary
To change button style, you can change its background. Here is an example for you. Follow these steps:
1. Define button background
For example:
<Button
android:id="#+id/myButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:background="#drawable/button_background" // this is your button background
android:text="#string/myButton"
android:textColor="#color/white"/>
2. Create a new folder in res folder
Right click on res folder in your project > New > Folder. Name it with drawable.
3. Create a new xml file for your button background
Here, we can name it with button_background.xml. You may rename it later. Place it in drawable folder. So, fill it with:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color-->
<solid android:color="#color/your_background_color" >
</solid>
<!-- If you want to add some padding -->
<padding
android:left="5dp"
android:top="5dp"
android:right="5dp"
android:bottom="5dp" />
<!-- Here is the corner radius -->
<corners
android:radius="6dp" >
</corners>
</shape>
And, completed... For information about changing app's theme, this is a reference for you: Styles and Themes

Android : change button text and background color

How can I change both text and background colors when my button is pressed, with xml ?
To change text color I can do :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="mycolor"/>
<item android:color="mycolor2"/>
</selector>
To change the background I can do (using it in a selector/item with drawable reference) :
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FF0079FF" />
</shape>
But how can I do both ? Let's say I want to have :
Default : black text / white background
Pressed : white text / blue background
EDIT : answer
I totaly forgot that the background and text color are managed separately, so this is how I did it :
<Button
android:textColor="#color/filtersbuttoncolors"
android:background="#drawable/mybackgroundcolors" />
In mybackgroundcolors.xml I manage the background and in filtersbuttoncolors.xml I manage the text color. In both xml files I manage the status (pressed, selected, default)
Since API level 21 you can use :
android:backgroundTint="#android:color/white"
you only have to add this in your xml
Here is an example of a drawable that will be white by default, black when pressed:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid
android:color="#1E669B"/>
<stroke
android:width="2dp"
android:color="#1B5E91"/>
<corners
android:radius="6dp"/>
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp"/>
</shape>
</item>
<item>
<shape>
<gradient
android:angle="270"
android:endColor="#1E669B"
android:startColor="#1E669B"/>
<stroke
android:width="4dp"
android:color="#1B5E91"/>
<corners
android:radius="7dp"/>
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp"/>
</shape>
</item>
</selector>
I think doing this way is much simpler:
button.setBackgroundColor(Color.BLACK);
And you need to import android.graphics.Color; not: import android.R.color;
Or you can just write the 4-byte hex code (not 3-byte) 0xFF000000 where the first byte is setting the alpha.
Just complementing #Jonsmoke's answer.
For API level 21 and above you can use :
android:backgroundTint="#android:color/white"
in XML for the button layout.
For API level below 21 use an AppCompatButton using app namespace instead of android for backgroundTint.
For example:
<android.support.v7.widget.AppCompatButton
android:id="#+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="My Button"
app:backgroundTint="#android:color/white" />
add below line in styles.xml
<style name="AppTheme.Gray" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorButtonNormal">#color/colorGray</item>
</style>
in button, add android:theme="#style/AppTheme.Gray", example:
<Button
android:theme="#style/AppTheme.Gray"
android:textColor="#color/colorWhite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#android:string/cancel"/>
When you create an App, a file called styles.xml will be created in your res/values folder. If you change the styles, you can change the background, text color, etc for all your layouts. That way you don’t have to go into each individual layout and change the it manually.
styles.xml:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme.AppBaseTheme" parent="#android:style/Theme.Light">
<item name="android:editTextColor">#295055</item>
<item name="android:textColorPrimary">#295055</item>
<item name="android:textColorSecondary">#295055</item>
<item name="android:textColorTertiary">#295055</item>
<item name="android:textColorPrimaryInverse">#295055</item>
<item name="android:textColorSecondaryInverse">#295055</item>
<item name="android:textColorTertiaryInverse">#295055</item>
<item name="android:windowBackground">#drawable/custom_background</item>
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
parent="#android:style/Theme.Light" is Google’s native colors. Here is a reference of what the native styles are:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/themes.xml
name="Theme.AppBaseTheme" means that you are creating a style that inherits all the styles from parent="#android:style/Theme.Light".
This part you can ignore unless you want to inherit from AppBaseTheme again. = <style name="AppTheme" parent="AppBaseTheme">
#drawable/custom_background is a custom image I put in the drawable’s folder. It is a 300x300 png image.
#295055 is a dark blue color.
My code changes the background and text color. For Button text, please look through Google’s native stlyes (the link I gave u above).
Then in Android Manifest, remember to include the code:
<application
android:theme="#style/Theme.AppBaseTheme">
Just use a MaterialButton and the app:backgroundTint and android:textColor attributes:
<MaterialButton
app:backgroundTint="#color/my_color"
android:textColor="#android:color/white"/>
add below lines in the styles.xml
<style name="AppTheme.Gray" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorGray</item>
</style>
and in button, add android:theme="#style/AppTheme.Gray", example:
<Button
android:theme="#style/AppTheme.Gray"
android:textColor="#color/colorWhite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#android:string/cancel"/>

Can a selector resource use a color defined in a style?

I'm trying to use a color defined in a stlyle in a selector but it is causing a Resources$NotFoundException.
First I added a new attribute to attr.xml:
<resources>
<attr name="unread_background" format="color" />
</resources>
Then I defined that attr value in styles.xml:
<style name="ThemeNoTitleBar" parent="android:Theme.NoTitleBar">
<item name="unread_background">#000000</item>
</style>
Then I tried to use that attr in my selector definition:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- other states snipped -->
<item android:state_selected="false"
android:drawable="?unread_background" />
</selector>
Lastly, the activity uses the ThemeNoTitleBar style theme in the manifest.
I've also tried creating a color in colors.xml and having it use the new attr but that also fails.
I'm obviously missing something but am not sure what to do to fix it. My intent is to create multiple themes and have the selector use the color in the currently selected theme.
<item android:state_selected="false"
android:drawable="?unread_background" />
this above section is wrong.
the drawable only take a reference to a drawable resource.
Please see this link. http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
Here is something, that works by me.
attrs.xml:
<attr name="color_selection" format="reference"/>
styles.xml, as child of main theme:
<item name="color_selection">#color/selection_background_inverse</item>
shape_background_selected.xml in drawable folder:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?attr/color_selection"/>
</shape>
your selector file, in my case: selector_background_recyclerview:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/shape_background_selected" android:state_activated="true" />
<item android:drawable="#drawable/shape_background_selected" android:state_pressed="true" /> <!-- pressed -->
<item android:drawable="#color/transparent" /> <!-- default -->
</selector>
finally, in your view's xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#drawable/selector_recyclerview_item_background"../>
Android button with different background colors Take a look onto the example. It looks like you need that.

Categories

Resources