Apply style resource in drawable xml - android

I have this in res/values/styles.xml
<style name="ListViewRowBorder" >
<item name="android:width">1dp</item>
<item name="android:color">#color/listview_row_stroke_color</item>
</style>
I am able to access color resources.How do i access this style resource in res/drawable/file.xml (shown below)
The way i have tried below does not seem to work.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/list_item_dark_background"/>
<stroke style="#style/ListViewRowBorder" />
</shape>
</item>

i don't think you can use a style for a stroke, please have a look at:
http://developer.android.com/guide/topics/resources/drawable-resource.html#stroke-element

I'm not sure if you can use Styles with shapes
As per the Style dev page:
A style can be applied to an individual View (from within a layout
file) or to an entire Activity or application (from within the
manifest file).

Related

Create button formatting in android

I am working on a project where I will have many buttons of the same size.
I was wondering if there is a way to create a standard button formatting with a set
height
weight
padding
etc.
I have looked into styles but I am not sure if that is the road I should be taking. I also thought about extending the button class and programmatically setting these values to a standard.
Hello, how are you!
The best way is to create a style in the style.xml resource, all the necessary features.
just add the style with style = "#style/mystyle" to all the buttons.
example:
<style name="mystyle">
<item name="android:textSize">20sp</item>
<item name="android:gravity">center|center_horizontal</item>
<item name="android:textAlignment">center</item>
</style>
In the same way when you want to create a customized button (java/kotlin)
it will also be added in the same way.
Greetings.
You can create a reusable component in a separate .xml file and use it everywhere since you said the dimensions exactly the same all across the app. Here is a sample:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="4dp" />
<!--customize and animate stuff-->
<gradient
android:angle="270"
android:endColor="#88b823"
android:startColor="#b0dc54" />
</shape>

Add rounded corners when having android:drawableLeft with png

To make it short, this is what I would like to add a custom button that looks like this:
IMG is a .png file in my mipmap folders and SOME TEXT is just a string value. What the dashed line is added just as a separator in the image, not in the button.
The issue is that the rounded edges don't appear where the image is added. It looks like this:
My questions are the following:
Can this be achieved?
Is there a way to override the <solid /> attribute in <shape />?
I will have to create 10 of these buttons each with different colors and if I add android:color with a different value, the color does not change
When adding the image, it makes me choose only one (e.g. the mdpi one). If this will be displayed on larger screens, will it take a different .png image based on the size?
Is there a specific type of button I should use? I would like to revert the colors when the button is pressed and stay as pressed. I have a vague idea about how this can be achieved, but is there a way to do this for the .png files as well or do I need to import into the project others with the colors already inverted and just switch them?
custom_button.xml
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="250px"
android:bottomLeftRadius="250px"
android:topRightRadius="50px"
android:bottomRightRadius="50px" />
<solid
android:color="#color/YellowPrimary"/>
</shape>
button_styles.xml
<resources>
<style name="CategoryToggle">
<item name="android:background">#drawable/custom_button</item>
<item name="android:textAllCaps">true</item>
</style>
<style name="CategoryToggle.First">
<item name="android:color">#color/bluePrimary</item> // Does not override <solid>
<item name="android:drawableLeft">#mipmap/icon_48mdpi</item>
<item name="android:text">#string/first_cat</item>
</style>
</resources>
button_layout.xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
style="#style/CategoryToggle.History"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
I have no java code at the moment as I just started and trying to implement this weird button format.
This is how it looks at my end:
Absolutely. As I mentioned in the comments, either make sure your drawable has a transparent background, or create a custom button to mask the drawable.
You'll want to use a style attribute apply a different style to each button. By this I mean the color defined in your custom_button.xml should reference a color attribute (something like colorAccent should work in your case), instead of a static color.
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorAccent"/>
</shape>
Then change this color in your button styles instead of android:color.
<style name="CategoryToggle">
<item name="colorAccent">#color/YellowPrimary</item>
</style>
Make sure you have the support library dependency added, or colorAccent will not be available.
Use the android:theme attribute, instead of the style attribute to apply the button theme.
<Button
android:width="wrap_content"
android:height="wrap_content"
android:theme="#style/CategoryToggle"/>
It looks like your drawables are not using resource qualifiers. You'll need to make sure each alternative resource has the exact same name as the original (i.e. your icon_48mdpi.png should instead be called icon_48dp.png for all configurations) and is placed in the corresponding drawable folder for its density. Your drawable resources should look like the following (in the Project view structure, not the Android view structure).
res/
|-- drawable/
| +-- custom_button.xml
|-- drawable-hdpi/
| +-- icon_48dp.png
|-- drawable-mdpi/
| +-- icon_48dp.png
|-- drawable-xhdpi/
| +-- icon_48dp.png
|-- drawable-xxhdpi/
| +-- icon_48dp.png
|-- drawable-xxxhpdi/
| +-- icon_48dp.png
~
To change the color of a drawable based on state, you will need to abstract your color one step further and create a color state list.
res/color/button_color_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/pressed_color" android:state_pressed="true"/>
<item android:color="#color/focused_color" android:state_focused="true"/>
<item android:color="#color/state_hovered" android:state_hovered="true"/>
<item android:color="?attr/colorAccent"/>
</selector>
Then you can use this color resource in your shape drawable instead of colorAccent.
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/button_color_selector"/>
</shape>
You can also make each of the colors in your color state list a styleable attribute by defining custom attributes and referencing those attributes in your styles. I won't go into that further for the sake of brevity though.
You can do this for drawables similarly by creating a state list drawable.
Lastly, you'll want to get into the habit of using dp instead of px unless you are absolutely certain you want to use px. This will prevent strange appearances at different screen densities.
On 4 "is there a way to (revert colors when pressed) for the .png files".. yes there are ways.
The by-the-book option is to use xml styles to specify different drawables for different button states. Consider ImageButton which has an example of this in its docs: https://developer.android.com/reference/android/widget/ImageButton.html
Another option is to apply tints or other filters to the drawable in your own code in button interaction callbacks. Compared to using different drawables, in this approach you add custom code instead of leveraging builtin resources, so you may wind up testing and debugging more on different devices, and you get full control so you can do custom animations and other elaborate things that may not fit well into Android resource tooling. Can checkout setColorFilter for starters:
https://developer.android.com/reference/android/widget/ImageView.html#setColorFilter(int,%20android.graphics.PorterDuff.Mode)
Thanks for adding some code and images or your problem, helps in understanding it.
Big shout out to Bryan for his insight on this matter. It led me to the paths I needed to follow in order to solve this issue.
I am posting this answer so that others with similar cases will know the steps. Although I have quite a number of files, this procedure did the trick perfectly.
I have my custom button as described in the link provided by Bryan.
For the rest I have the following:
Change the text color:
button_text_color.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/redPrimary" android:state_pressed="true"/>
<item android:color="#color/redDark"/>
</selector>
Change the background: button_background.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:bottomLeftRadius="400dp" android:radius="100dp" android:topLeftRadius="400dp" />
<solid android:color="#color/redDark" />
</shape>
</item>
<item android:state_enabled="true">
<shape android:shape="rectangle">
<corners android:bottomLeftRadius="400dp" android:radius="100dp" android:topLeftRadius="400dp" />
<solid android:color="#color/redPrimary" />
</shape>
</item>
</selector>
Change the drawable: button_drawable.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_button_inverted" android:state_pressed="true" />
<item android:drawable="#drawable/ic_button"/>
</selector>
button_style.xml
<style name="MyButtonStyle">
<item name="android:background">#drawable/button_background</item>
<item name="android:drawableLeft">#drawable/button_drawable</item>
<item name="android:text">#string/button_text</item>
<item name="android:textColor">#color/button_text_color</item>
</style>
Implementing it in main_layout.xml
<packagename.MyCustomButton xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/myButton"
style="#style/MyBUttonStyle"
android:layout_marginBottom="8dp" />
Just use the official library.
Add the MaterialButton component using these attributes:
app:icon to add the icon
app:iconGravity to decide the position of the icon
app:iconPadding to increase/decrease the space between the icon and the text
android:paddingLeft the padding between the edge and the icon
<com.google.android.material.button.MaterialButton
android:paddingLeft="2dp"
app:icon="#drawable/ic_add_24px"
app:iconGravity="start"
app:iconPadding="4dp"
app:shapeAppearanceOverlay="#style/ShapeAppearanceOverlay.Button.RoundedRight"
.../>
With the app:shapeAppearanceOverlay you can customize the shape of the component.
<style name="ShapeAppearanceOverlay.Button.RoundedRight" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSizeTopRight">4dp</item>
<item name="cornerSizeBottomRight">4dp</item>
<item name="cornerSizeTopLeft">16dp</item>
<item name="cornerSizeBottomLeft">16dp</item>
</style>
You can obtain the same result using a style.

How to apply 2 different kinds of styles to a single Android control?

Say I have this:
values/styles.xml
<resources>
<style name="MyEditText">
<item name="android:maxLines">1</item>
........
And this (not in a file yet):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<stroke
android:width="2dp"
android:color="#000000" />
</shape>
And an EditText.
In which file should I put the 2nd piece of the code?
How can I apply these 2 styles to a single EditBox?
Updated
The properties that are defined a style xml file and applied to a view ( by setting style="#style/my_custom_style" can be overridden.
For example, if in the style file I have defined a background, I can re-assign that property in the xml layout of that view again, or even programmatically.
Consequently, if for the example view, I set both style="#style/my_custom_style" (including background property with the value of drawable_one) and android:background="#drawable/**drawable_two**", then eventually the drawable_two will take effect.
In the style.xml file add the background item
<item name="android:background">#drawable/your_drawable_xml</item>
And for its value (your_drawable_xml), use the second drawable xml.
Now you can apply both in the layout declaration of EditText:
style="#style/MyEditText"

Using parents for drawable resources

When I define a style, it can be inherited from a parent style, e.g:
<style name="DialogNoTitle" parent="#android:style/Theme.Dialog">
<item name="android:windowNoTitle">true</item>
</style>
Now I want to do the same with drawable resources, something like this:
<shape xmlns:android="http://schemas.android.com/apk/res/android" name="ChildDrawable" parent="#drawable/ParentDrawable">
<solid android:color="#android:color/white"/>
<corners android:radius="6dp"/>
</shape>
Is there a way to accomplish this functionality?
Short answer - you cannot extend and override drawables. However,
Some drawables can be created from other drawables. e.g. layer-list will allow you to draw layers of drawables one on top of another. Refer to http://developer.android.com/guide/topics/resources/drawable-resource.html .
You create Drawable objects in code.

How to reference style attributes from a drawable?

I want to have 2 selectable themes for my application. In order to do that, I defined some attributes, like this:
<attr format="color" name="item_background" />
Then, I created both themes, like this:
<style name="ThemeA">
<item name="item_background">#123456</item>
</style>
<style name="ThemeB">
<item name="item_background">#ABCDEF</item>
</style>
This method works great, allowing me to create and modify several themes easily. The problem is that it seems that it can be used only in Views, and not in Drawables.
For example, referencing a value from a View inside a layout works:
<TextView android:background="?item_background" />
But doing the same in a Drawable doesn't:
<shape android:shape="rectangle">
<solid android:color="?item_background" />
</shape>
I get this error when running the application:
java.lang.UnsupportedOperationException: Can't convert to color: type=0x2
If instead of ?item_background I use a hardcoded color, it works, but that doesn't allow me to use my themes. I also tried ?attr:item_background, but the same happens.
How could I do this? And why does it work in Views but not in Drawables? I can't find this limitation anywhere in the documentation...
In my experience it is not possible to reference an attribute in an XML drawable.
In order to make your theme you need to:
Create one XML drawable per theme.
Include the needed color into you drawable directly with the #color tag or #RGB format.
Make an attribute for your drawable in attrs.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Attributes must be lowercase as we want to use them for drawables -->
<attr name="my_drawable" format="reference" />
</resources>
Add your drawable to your theme.xml.
<style name="MyTheme" parent="#android:style/Theme.NoTitleBar">
<item name="my_drawable">#drawable/my_drawable</item>
</style>
Reference your drawable in your layout using your attribute.
<TextView android:background="?my_drawable" />
Starting with lollipop (API 21) this feature is supported, see
https://code.google.com/p/android/issues/detail?id=26251
However, if you're targeting devices without lollipop, don't use it, as it will crash, use the workaround in the accepted answer instead.
Although it's not possible to reference style attributes from drawables on pre-Lollipop devices, but it's possible for color state lists. You can use AppCompatResources.getColorStateList(Context context, int resId) method from Android Support Library. The downside is that you will have to set those color state lists programmatically.
Here is a very basic example.
color/my_color_state.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="?colorControlActivated" />
<item android:color="?colorControlNormal" />
</selector>
A widget that needs a color state list:
<RadioButton
android:id="#+id/radio_button"
android:text="My Radio" />
And the most important:
ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);
Well, not the most elegant or shortest way, but this is what Android Support Library does to make it work on older versions (pre-Lollipop) of Android.
Unfortunately, the similar method for drawables doesn't work with style attributes.
I answered the same question in https://stackoverflow.com/a/59467269/3841352 but i will post it here as well:
I encountered the same problem and as of 2019 it hasn't been resolved so you can't have an attribute referenced in a selector as a drawable. I will share the solution I got for the problem as I don't see it posted in here. I found it in the last comment of the bug report.
The workaround is basically create a drawable resource that will be the one referring the attribute value.
To illustrate your case the solution would be instead of:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?attr/colorPrimary" android:state_enabled="true" android:state_window_focused="false"/>
<item android:drawable="?attr/colorPrimaryDark" android:state_pressed="true"/>
<item android:drawable="#android:color/darker_gray" android:state_enabled="false"/>
<item android:drawable="?attr/colorPrimary"/>
</selector>
you would replace the ?attr/* for a drawable resource:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/colorPrimaryDrawable" android:state_enabled="true" android:state_window_focused="false"/>
<item android:drawable="#drawable/colorPrimaryDarkDrawable" android:state_pressed="true"/>
<item android:drawable="#android:color/darker_gray" android:state_enabled="false"/>
<item android:drawable="#drawable/colorPrimaryDrawable"/>
</selector>
The drawables would be defined as:
drawable/colorPrimaryDrawable
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
<solid android:color="?attr/colorPrimary" />
</shape>
drawable/colorPrimaryDarkDrawable
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
<solid android:color="?attr/colorPrimaryDark" />
</shape>
Hope it helps!!
As #marmor stated this is now supported on API 21. But for those us who need to support legacy versions of Android, you can use this feature. Using the v7 support library you can still use it on apps with minimum SDK level all the way down to 7.
The AppCompatImageView in the v7 Android Support Library has a bug free implementation of this feature. Simply replace your usages of ImageView with AppCompatImageView.

Categories

Resources