Is it possible to rotate a drawable in the xml description? - android

I am creating an app, with resources that can be reused (because buttons are always the same, but mirrored or rotated). I do want to use the same resource so I don't have to add 3 more resources that are exactly like the original but rotated. But I also don't want to mix the code with things that can be declared in the XML or make transformations with a matrix that will cost processing time.
I've got a two state button declared in an XML.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#drawable/and_card_details_button_down_left_onclick" /> <!-- pressed -->
<item android:drawable="#drawable/and_card_details_button_down_left" /> <!-- default -->
</selector>
and I want to reuse the drawable because it will be the same but rotated 90º and 45º and I assign to the button as a drawable.
<Button android:id="#+id/Details_Buttons_Top_Left_Button"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/details_menu_large_button" />
I know that I can rotate it with a RotateDrawable or with a Matrix but as I already explained I don't like that approach.
Is it possible to achieve that directly on the XML or what do you think that will be the best way to do it? Put all resources but rotated, rotate them in the code?
--- EDIT ---
The answer of #dmaxi works great, this is how to combine it with an item list :)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<rotate
android:fromDegrees="90"
android:toDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="#drawable/and_card_details_button_up_onclick"/>
</item>
<item>
<rotate
android:fromDegrees="90"
android:toDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="#drawable/and_card_details_button_up_onclick"/>
</item>
</selector>

I could rotate in XML:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="90"
android:toDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="#drawable/mainmenu_background">
</rotate>
The fromDegrees is important.
Basically this is a rotate animation defined in XML. With fromDegrees you define the initial rotated state. The toDegrees is the final rotated state of the drawable in the animation sequence but can be anything if you don't want to use animation.
I don't think it allocates resources for animation as it doesn't have to be loaded as animation. As a drawable it is rendered as it's initial state and should be put in the drawable resource folder.
To use it as an animation you should put it in anim resource folder and can start the animation like this (just an example):
Animation rotation = AnimationUtils.loadAnimation(this, R.anim.rotation);
rotation.setRepeatCount(Animation.INFINITE);
myView.startAnimation(rotation);

I could rotate left arrow right in XML as:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="180"
android:toDegrees="0"
android:drawable="#drawable/left">
</rotate>
Attached image for reference.

If vector based drawables are used, in conjunction with an ImageView, style, and color state list, your button can be refactored as follows:
Note: Vector drawables are significantly smaller than images, so extra, explicit definitions don't incur much overhead, and makes for clear, explicit code (although I've read that hand modifying vector assets should be avoided, I'd rather deal with the overhead of updating a couple of files than having transformations on one):
Note: Android Studio is a great source for vector assets.
res\values\styles.xml
<!--ImageView-->
<style name="Details_Buttons_Top_Left_Button">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:tint">#color/button_csl</item>
</style>
res\color\button_csl.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#color/grey_disabled"/>
<item android:state_pressed="true" android:color="#color/orange_hilite"/>
<item android:color="#color/black"/>
</selector>
details_menu_large_button.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#drawable/and_card_details_button_down_left_onclick" /> <!-- pressed -->
<item android:drawable="#drawable/and_card_details_button_down_left" /> <!-- default -->
</selector>
Details_Buttons_Top_Left_Button
<ImageView android:id="#+id/Details_Buttons_Top_Left_Button"
style="#style/Details_Buttons_Top_Left_Button"
android:src="#drawable/details_menu_large_button" />
and_card_details_button_down_left.xml (ic_play_arrow_black_24dp.xml)
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M8,5v14l11,-7z"/>
</vector>
and_card_details_button_down_left_onclick.xml (ic_play_arrow_black_24dp.xml modified)
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<group android:name="rotationGroup"
android:pivotX="12"
android:pivotY="12"
android:rotation="90" >
<path
android:fillColor="#FF000000"
android:pathData="M8,5v14l11,-7z"/>
</group>
</vector>

If you want to rotation drawable in xml file then simple add android:rotation="180" in ImageView
<ImageView
android:id="#+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_dropdown"
android:rotation="180"/>
Programatically
val image = findViewById(R.id.imageview)
image.rotation = 180f

Related

Splash screen loader animation is not animating

I am using an XML drawable as splash screen which is a layer-list element. Inside it, I am using an animation.xml file, which contains a loading animation.
While showing the splash screen, I can see the loading animation drawable, but without any animation. I am probably doing something wrong.
Can anyone please point me out the correct way?
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/purple_700" />
<item
android:drawable="#drawable/ic_launcher_foreground"
android:gravity="center" />
<item
android:width="300dp"
android:height="300dp"
android:drawable="#drawable/loading_animation"
android:gravity="bottom" />
</layer-list>
Thanks for your help!
Try to place the last item with this:
<item
android:width="300dp"
android:height="300dp">
<animated-rotate
android:drawable="#drawable/loading_image"
android:pivotX="50%"
android:pivotY="50%" />
</item>

Bottom Navigation Not showing original color

I have designed a bottom navigation view for my application. The idea is simple, green colored bottom bar will have white colored icons. I wrote a selector for this
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:color="#android:color/white" />
<item android:color="#android:color/holo_blue_dark" />
</selector>
And it works, it changes the icon colors, but it does not make it completely white, the color looks gray-ish.
I have also tried the <item android:state_selected="true" android:color="#android:color/white" /> but it also doesn't work. I have added the images below for you to see the difference.
Please help
If you want your icon to have same default color use this in your activiy.
bottomNavigation.setItemIconTintList(null);
Here is what worked for me:
theme.xml
<item name="elevationOverlayEnabled">false</item>
It appears that for anything that has elevation set, there will be an overlay. In my case my BottomNavigationView had elevation manually set and thus received a dark overlay.
You should use state_selected
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true"
android:color="#color/color1" />
<item android:color="#color/color2" />
</selector>
app:itemIconTint="#color/navigate_state"
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#android:color/holo_blue_dark" />
<item android:color="#android:color/darker_gray" />
</selector>
and kind of
add it on android.support.design.widget.BottomNavigationView app:itemIconTint="#drawable/nav_item_color_state" app:itemTextColor="#drawable/nav_item_color_state"
If you using BottomNavigationView from com.google.android.material, you should specified colors especially for icon and text, for example:
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background"
app:itemIconTint="#color/bottom_bar_icon_tint"
app:itemTextColor="#color/bottom_bar_icon_tint"
app:menu="#menu/navigation_menu" />
and bottom_bar_icon_tint.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#color/white" />
<item android:color="#color/cool_grey" />
</selector>
also pay attention to: android:state_checked="true"
Your xml files seems to have an alpha channel/transparency
You need to change the "android:alpha" parameter to "1.0" or remove it in your icon.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#color/white"
android:alpha="0.8">
<path
android:fillColor="#color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM6.5,17.5l7.51,-3.49L17.5,6.5 9.99,9.99 6.5,17.5zM12,10.9c0.61,0 1.1,0.49 1.1,1.1s-0.49,1.1 -1.1,1.1 -1.1,-0.49 -1.1,-1.1 0.49,-1.1 1.1,-1.1z"/>

How to add space between bitmap of spinner selector and items of drop down list

I have following spinner:
<Spinner
android:id="#+id/safe_network_time_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="#drawable/spinner_selector"
android:entries="#array/schedule_edit_days_repeat"
android:popupBackground="#drawable/custom_dropdown_white_background"
android:spinnerMode="dropdown"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/divider4"
tool:listitem="#layout/custom_dropdown_spinner_button" />
The spinner_selector is:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="right|center_vertical" android:src="#drawable/down_red_arrow" />
</item>
</selector>
The dropdown list appears like this:
When I select an item of the dropdown list, if it is too long it overlaps the arrov bitmap. how can I avoid this?
Try using a layer-list
bg_spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<!-- This is the actual spinner background -->
<selector >
<!-- Feel free to use your own drawable for these states -->
<item android:state_window_focused="false" android:drawable="#drawable/bg_border_accent_thin"/>
<item android:state_pressed="true" android:drawable="#drawable/bg_border_accent_thin"/>
<item android:state_window_focused="true" android:state_pressed="false" android:drawable="#drawable/bg_border_grey_thin"/>
</selector>
</item>
<!-- This is the spinner drawable, use your custom drawable aswell. android:right does the magin to separate this drawable from the spinner content-->
<item android:drawable="#drawable/ic_ripple_arrow"
android:gravity="center_vertical|right"
android:right="16dp"/>
</layer-list>
Edit 02/02/2020
My apologies for a weekend-long lunch.
If you are using the androidx dependencies (which I suggest you do) here's the code that I use to properly add spacing between the text and the selected item in the spinner.
On your layout.xml
<!-- The line I think you need is the one giving padding to the right -->
<androidx.appcompat.widget.AppCompatSpinner
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:paddingRight="36dp"
android:background="#drawable/bg_spinner"
android:popupBackground="#drawable/bg_spinner_popup"/>
The bg_spinner.xml is the one provided a couple of lines above.
And the popup one doesn't really matter, since it gives some directives on how to paint a background, nothing important but here it is either way...
bg_spinner_popup.xml
<?xml version="1.0" encoding="utf-8" ?>
<shape xmlns:android="http://schemas.android.com/apk/res/android
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color ="#android:color/white"/>
<stroke android:width="5px" android:color="#color/primaryColor"/>
</shape>

Android drawable rotate inside button

I need to have a button series with inside text and icon.
The icon inside the 4 buttons must rotate to cover every poly.
Follow an example with two buttons where the top is create with the original (vector drawable) icon and the "left" button rotating the vector.
<Button
style="#style/Buttons.Small"
android:drawableLeft="#drawable/ic_vertical_align_top_white_12dp"
android:text="#string/optional" />
<Button
style="#style/Buttons.Small"
android:drawableLeft="#drawable/arrow_left"
android:text="#string/optional" />
The vector drawable:
ic_vertical_align_top_white_12dp
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M8,11h3v10h2V11h3l-4,-4 -4,4zM4,3v2h16V3H4z" />
</vector>
The rotate drawable:
arrow_left.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="-90"
android:toDegrees="-90"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="#drawable/ic_vertical_align_top_white_12dp">
</rotate>
The style
<style name="Buttons.Small">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">#color/buttonSmallBackground</item>
<item name="android:layout_margin">2dp</item>
<item name="android:minHeight">0dp</item>
<item name="android:minWidth">0dp</item>
<item name="android:textSize">12sp</item>
<item name="android:drawablePadding">4dp</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
</style>
And following the result
Nougat (PERFECT)
Marshmallow (WRONG)
I already tried to play with the vector viewport without success.
Thanks
I solved with a trick.
Appling directly the rotation inside the vector.
Now arrow_left.xml become
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<group android:rotation="-90"
android:pivotX="12"
android:pivotY="12">
<path
android:fillColor="#FFFFFF"
android:pathData="M8,11h3v10h2V11h3l-4,-4 -4,4zM4,3v2h16V3H4z" />
</group>
</vector>
I don't know why in Marshmallow the rotation not work properly but this solve my case.
Thanks

Android: How to change android:fillcolor with selector in one Vector Drawable xml

Tab Icons: My current method is to create two files (ic_list_selected_24dp.xml and ic_list_unselected_24dp.xml; they are basically the same but only the android:fillColor='Color HEX CODE' are different), and then create a selector (selector_tabitem_list.xml) to change the drawable color when the state is changed.
// #drawable/selector_tabitem_list.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:drawable="#drawable/ic_list_selected_24dp"
android:state_selected="true" />
<item android:drawable="#drawable/ic_list_unselected_24dp"
android:state_selected="false" />
</selector>
It's kind of duplicated because two drawables are the same.
Selector cannot be used in vector drawable.
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#drawable/selector"
android:pathData="M19,3...."
</vector>
--
// #drawable/selector
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<color android:color="#color/itemSelected" />
</item>
<item android:state_selected="false">
<color android:color="#color/itemUnselected" />
</item>
</selector>
, and android:fillColor="#color/state" either.
// #color/state
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#android:color/white" android:state_selected="true" />
<item android:color="#android:color/black" android:state_selected="false" />
</selector>
Is there any way to use one drawable and change its color dynamically?
Using hard hex code is better?
Thanks.
Here is the complete list of steps to use a vector asset as tinted icon in a TabItem (which is part of the support design lib). All parts are present in the original question and linked answer, but are easy to miss.
Create the selector. Note that it has to switch the color for state_selected (as included in the question, but not in the answer linked by #cmingmai. There it only states android:state_enabled which is not relevant for tabs):
res/color/selector_navigation.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false" android:color="#android:color/black" />
<item android:state_selected="true" android:color="#android:color/white" />
</selector>
Adjust the vector drawable by adding android:tintMode and android:tint to the vector tag.
In addition for the tinting to work with multiply, the fillColor of the path needs to be set to white!
res/drawable/ic_tab_list:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0"
android:tintMode="multiply"
android:tint="#color/selector_navigation">
<path
android:fillColor="#android:color/white"
android:pathData="..." />
</vector>
Use vector drawable in Layout – or use to create the tabs in code as shown in the developer guide on Tabs. Note that I also modified the tab indicator color to match the active icon color to follow the material design guidelines.
Relevant part of the layout:
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="#android:color/white">
<android.support.design.widget.TabItem
android:id="#+id/tabItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="#drawable/ic_tab_list" />
<!-- More Tabs -->
</android.support.design.widget.TabLayout>
Adjust build.gradle with following to activate vector support for old Android versions (in case it was not already previously added):
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
Upgrade to Support Library 28.0.0+ (presumably same for androidx.. didn't test).
On Support Library 28.0.0 using a selector color xml resource seems to work now when used as vector's android:fillColor.
In fact the previous solution (using vector's android:tintMode, android:tint and white for android:fillColor) no longer works for me on Support Library 28.0.0.
Tested on API 21 and 27 Emulators.
Try replacing the AppTheme in style.xml with a different parent like so:
style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar"

Categories

Resources