I have an ImageView with a layer-list as source. The layer-list consists of an image and a frame. The frame has a negative inset of -4dp. This works great on Android 5 and above, but not on any Android 4 versions (tested on actual devices with 4.3 and 4.4.2).
On Android 5 and above devices, the frame is outside the actual image (the frame width is 4dp) but on Android 4 devices, the frame is inside the image.
layer list xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/image_id">
<bitmap
android:src="#drawable/checker_bmp"
android:antialias="true"/>
</item>
<item android:id="#+id/shadow">
<inset
android:antialias="true"
android:inset="-4dp">
<nine-patch android:src="#drawable/green_shadow"/>
</inset>
</item>
</layer-list>
InsetDrawable exists since API version 1.
I can not use the standard android:src and android:background for image and frame because I have to rotate the image and the background isn't capable of rotating with the ImageView.
Here is the result: The red and black checkerboard is the actual image. The transparent green frame shows the result of the xml on different Android versions. the negative inset should put the green frame around the checkerboard, like it does on Android 5+. On Android 4 it is inside the image, like it is ignored. How to achieve the correct result on Android 4?
EDIT: I found out that android:inset is only available from API level 21 (Android 5). There must be a way to get the same result on API levels below 21... Important is that the image must be able to scale and rotate and that the frame is a nine patch drawable.
EDIT2: Giving the imageview a positive inset instead gives the same result. This is the code I used:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/image_id">
<inset
android:antialias="true"
android:inset="4dp">
<bitmap
android:src="#drawable/checker_bmp"
android:antialias="true"/>
</inset>
</item>
<item android:id="#+id/shadow" >
<nine-patch android:src="#drawable/green_shadow"/>
</item>
</layer-list>
Setting 4dp padding on the image makes the whole image offset by 4dp:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/canvas_image_layer_id" android:top="4dp" android:bottom="4dp" android:left="4dp" android:right="4dp">
<bitmap
android:src="#drawable/canvas_shadow"
android:antialias="true"/>
</item>
<item android:id="#+id/background_shadow" >
<nine-patch android:src="#drawable/canvas_shadow"/>
</item>
</layer-list>
Rather than use a negative inset, put the frame first as a solid color, then put the image as a positive inset into that.
Related
So I have a background texture (image) that I put on all of my buttons. I want to create a circular button with an icon that retains this background texture.
So far, I have noticed it isn't supported to do this on the shape side:
<shape android:shape="rectangle">
<solid android:color="#drawable/myTexture" /> <!-- this isn't supported -->
</shape>
Lastly I would otherwise try to use <layer-list>, however as I stated above, I need to still crop the texture to my shape I'm creating.
Is the only way to do this to make my own circular images that combine the background texture and the button icon? This seems a bit excessive, as I would think there should be a programmatic way to accomplish this, but I could be wrong.
Here is an example of what I mean above:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/myTexture" />
<item>
<shape android:shape="rectangle">
<corners android:radius="40dp" />
<size
android:height="80dp"
android:width="80dp" />
<solid android:color="#color/black" />
</shape>
</item>
</layer-list>
In the picture bellow: black is the circle shape, silver is the texture/image (black for contrast)
I haven't solved the programmatic way, but I did end up creating new graphics that combined the icon and the background texture. Using this singular image, I was able to create circular ImageButton's.
I want to resize a bitmap in a layer-list, added as an item.
This is what I have tried,
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="#android:color/white" />
<size
android:width="46dp"
android:height="46dp" />
</shape>
</item>
<item
android:width="11dp"
android:height="24dp"
android:gravity="center">
<bitmap android:src="#drawable/facebook_f" />
</item>
</layer-list>
Using Android Studio 2.0 Preview 5, the preview shown is perfect but the actual image is a blunder.
Preview by AS,
Actual image,
Changing image resource size manually or in the xml itself does not change anything.
Note : 'f' shape image dimensions are 53 * 128.
EDIT : AS was using API version 23 to render layouts. When I changed it to 21 (on which I was testing it too), it appeared blurred. I checked the same on Android M device and the images were perfect. So now, this xml is behaving API specific.
The android:height and android:width for <item> are only available for API 23 and above. If you use these attributes for API below 23, it will not give you an error, but simply ignore it.
I am attempting to use a VectorDrawable in a LayerList without scaling the vector. For example:
<layer-list>
<item android:drawable="#color/grid_item_activated"/>
<item android:gravity="center" android:drawable="#drawable/ic_check_white_48dp"/>
</layer-list>
The drawable ic_check_white_48dp id defined as:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>
The desired effect is for the check icon to be centered in the layer drawable, without scaling. The issue is, the layer-list above causes the check icon to be scaled to fit the layer size.
I can produce the desired effect if I replace the vector drawable with PNGs for each density and modify the layer-list as such:
<layer-list>
<item android:drawable="#color/grid_item_activated"/>
<item>
<bitmap android:gravity="center" android:src="#drawable/ic_check_white_48dp"/>
</item>
</layer-list>
Is there any way I can do this using a VectorDrawable?
I ran into the same problem trying to center vectors drawables on a layered list.
I have a workaround, its not exactly the same but it works, you need to set a size for the entire drawable and add padding to the vector item:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<size android:height="120dp" android:width="120dp"/>
<solid android:color="#color/grid_item_activated"/>
</shape>
</item>
<item android:top="24dp"
android:bottom="24dp"
android:left="24dp"
android:right="24dp"
android:drawable="#drawable/ic_check_white_48dp"/>
</layer-list>
The size of the shape above sets the size of the entire drawable, 120dp in this example, the padding on the second item, 24dp in this example, centers the vector image.
Its not the same as using the gravity="center" but its working way of using vectors in API 21 and 22.
Been struggling with the same problem. The only way I found to fix this and avoid the drawable to scale up was to set the drawable size and using gravity to align it:
<layer-list>
<item android:drawable="#color/grid_item_activated"/>
<item
android:gravity="center"
android:width="48dp"
android:height="48dp"
android:drawable="#drawable/ic_check_white_48dp"/>
</layer-list>
Hope it helps!
Edited solution that will make your SplashScreen look great on all APIs including API21 to API23
First of all read this article and follow the GOOD way of making a splash screen.
If your logo is distorted or wont fit and you are only targeting APIs24+ you can simply scale down your vector drawable directly in its xml file like so:
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="640"
android:viewportHeight="640"
android:width="240dp"
android:height="240dp">
<path
android:pathData="M320.96 55.9L477.14 345L161.67 345L320.96 55.9Z"
android:strokeColor="#292929"
android:strokeWidth="24" />
</vector>
in the code above I am rescaling a drawable I drew on a 640x640 canvas to be 240x240. then i just put it in my splash screen drawable like so and it works great:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"
android:paddingBottom="20dp" android:paddingRight="20dp" android:paddingLeft="20dp" android:paddingTop="20dp">
<!-- The background color, preferably the same as your normal theme -->
<item>
<shape>
<size android:height="120dp" android:width="120dp"/>
<solid android:color="#android:color/white"/>
</shape>
</item>
<!-- Your product logo - 144dp color version of your app icon -->
<item
android:drawable="#drawable/logo_vect"
android:gravity="center">
</item>
</layer-list>
my code is actually only drawing the triangle in the picture at the bottom but here you see what you can achieve with this. Resolution is finally great as opposed to the pixelated edges I was getting when using bitmap. so use a vector drawable by all means (there is a site called vectr that I used to create mine without the hasle of downloading specialized software).
EDIT in order to make it work also on API21-22-23
While the solution above works for devices runing API24+ I got really disappointed after installing my app a device running API22. I noticed that the splashscreen was again trying to fill the entire view and looking like shit. After tearing my eyebrows out for half a day I finally brute-forced a solution by sheer willpower.
you need to create a second file named exactly like the splashscreen xml (lets say splash_screen.xml) and place it into 2 folders called drawable-v22 and drawable-v21 that you will create in the res/ folder (in order to see them you have to change your project view from Android to Project). This serves to tell your phone to redirect to files placed in those folders whenever the relevant device runs an API corresponding to the -vXX suffix in the drawable folder, see this link. place the following code in the Layer-list of the splash_screen.xml file that you create in these folders:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:opacity="opaque">
<!-- The background color, preferably the same as your normal theme -->
<item
android:gravity="center">
<shape android:shape="rectangle">
<solid android:color="#android:color/white"/>
</shape>
</item>
<!-- Your product logo - 144dp color version of your app icon -->
<item
android:gravity="center">
<bitmap
android:gravity="center"
android:src="#drawable/logo_vect"/>
</item>
</layer-list>
For some reason for these APIs you have to wrap your drawable in a bitmap in order to make it work and jet the final result looks the same. The issue is that you have to use the aproach with the aditional drawable folders as the second version of the splash_screen.xml file will lead to your splash screen not being shown at all on devices running APIs higher than 23. You might also have to place the first version of the splash_screen.xml into drawable-v24 as android defaults to the closest drawable-vXX folder it can find for resources.
I'm currently working on a splash screen with a vector drawable centered both horizontally and vertically. Here is what I got on API level 25:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
<!-- background color, same as theme -->
<item android:drawable="#android:color/white"/>
<!-- app logo -->
<item
android:drawable="#drawable/my_app_logo"
android:gravity="center_horizontal|center_vertical"
android:width="200dp"
android:height="200dp"
/>
</layer-list>
If you want to adjust the vector drawable's dimension, modify android:width and android:height attributes above, not necessarily modify the original drawable.
In addition, my experience is DO NOT put the vector drawable in a bitmap tag, which never works for me. Bitmap is for .png, .jpg and .gif format file, not for vector drawable.
Reference
https://developer.android.com/guide/topics/resources/drawable-resource#LayerList
https://developer.android.com/guide/topics/resources/more-resources.html#Dimension
I have many different dynamic icons in my Android app and I would like to put a rectangular frame around all of them. I tried to use LayerDrawable but I think it scales the smaller drawable to the size of the larger one so in the end the icons overlap with the frame instead of within it. (the icon drawables are 64x64 while the frame drawable is 96x96). Is there an way to enlarge the transparent background of the icon drawables to the same size as the frame drawable without scaling the actual icon?
Any help would be appreciated!
You should be able to use a LayerDrawable for this; just tested it myself and it seems to work just fine. Define the frame first, then add another item with the specified insets.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FF0000"/>
</shape>
</item>
<item android:left="20dp" android:top="20dp" android:bottom="20dp" android:right="20dp">
<bitmap android:src="#drawable/ic_launcher"/>
</item>
</layer-list>
Using the layer-list below, my scale drawable is never shown. Why is that?
menu_dialog_header.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#color/black"></solid>
</shape>
</item>
<item>
<scale
android:scaleHeight="50%"
android:scaleWidth="100%"
android:scaleGravity="top"
android:drawable="#drawable/shine" />
</item>
</layer-list>
shine.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/shine" />
</shape>
menu_dialog.xml
<!-- header -->
<LinearLayout
android:background="#drawable/menu_dialog_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|center"
android:padding="8dp"
android:orientation="horizontal" >
...
I have a workaround that may or may not work for you: instead of using <scale>
, try <inset>. You can use a combination of the <item>'s android:top / android:bottom / android:left / android:right and the <inset>'s android:insetXXX to size the image
You can do things like set the sides of each inset value relative to your source image's dimensions. For example, if you have a 64 pixel-wide image and want to cut it down by 50%, you can do (64 / 4 = 16) for each side
It's not exactly the LayerLists's fault. ScaleDrawable additionally depends on the drawable's level, as (briefly) mentioned both in the Drawable Resources and the ScaleDrawable reference.
It seems there is no documentation of how ScaleDrawable will interpret the level.
There seems to be no way to set a drawable's level in XML, which reflects the fact that the primary use case for ScaleDrawable is to animate a drawable's size. Hence, you'll have to set the drawable's level in your code.
I strongly sympathize with your usage of ScaleDrawable here, because it allows for a more powerful way of stacking drawables by being able to position them and define their size.