On newer Android versions, the following code:
<?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="#bdbdbd" />
<size
android:width="60dp"
android:height="60dp" />
</shape>
</item>
<item
android:drawable="#drawable/ic_library_books_black_24dp"
android:gravity="center"
android:width="40dp"
android:height="40dp"
>
</item>
</layer-list>
produces this flawlessly:
However, earlier Android versions (API 16 and 19, from what I've tested) do not like this at all and I get
E/AndroidRuntime: FATAL EXCEPTION: main
Process: package.app, PID: 11490
android.view.InflateException: Binary XML file line #26: Error inflating class ImageView
upon inflation. I have used app:srcCompat for all my ImageViews so there is no problem there.
Standard Vector Drawables also work fine, but when placed in a layer-list they cause mayhem. Are there any workarounds?
The width/height attributes for the vector drawable in your layer-list are only supported in API 23 (Marshmallow) and higher. If you look at your layer-list drawable in the Android Studio editor, these attributes should have yellow blocks around them along with a warning that this won't work reliably on older devices.
But I think you can get rid of the warning and achieve the same centering effect like this:
<?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="#bdbdbd" />
<size
android:width="60dp"
android:height="60dp" />
</shape>
</item>
<item
android:drawable="#drawable/ic_library_books_black_24dp"
android:top="10dp"
android:bottom="10dp"
android:left="10dp"
android:right="10dp">
</item>
</layer-list>
I tested this on an old API 15 phone and it worked fine. I hope this works for you too.
Update:
In a previous version of this answer, I'd advised against using vectorDrawables.useSupportLibrary = true with layer lists, because it caused crashes. However, I've recently learned about a workaround that seems to fix the crash (while avoiding the fat auto-generated png files that #android developer correctly mentioned). Here's a summary of what needs to be done for it to work correctly:
Be sure to use srcCompat in your xml.
<android.support.v7.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/layer_list_with_svg" />
Add 'vectorDrawables.useSupportLibrary' to app/build.gradle
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
Add 'setCompatVectorFromResourcesEnabled(true)' to onCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
setContentView(R.layout.activity_main);
}
Why is all of this necessary?
As a more knowledgable person explained it to me, this has to do with how Android loads up the compat vector drawables. If you're using vectorDrawables.useSupportLibrary = true then image views will load up VectorDrawableCompat drawables when you use app:srcCompat. When your layer list drawable is inflated, there's no way for it to figure out how to create those referenced vector drawables. But if you turn on setCompatVectorFromResourcesEnabled it will try to hook the vector drawable loading in at a much lower level than image views and their app:srcCompat attribute, so it's then able to figure out how to load the vector drawables referenced in the layer list.
This answer draws on the article AppCompat - Age of the Vectors by Chris Banes(who works on the Support Library). For this question we're looking specifically at the section titled The 'magic' way.
The crash you're experiencing is because the Support Library only allows some ways of using VectorDrawables by default, and layer-list is not one of them.
There is a specific code block you can add to the top of your Activity to enable other VectorDrawable use such as <layer-list>:
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Note: the linked article contains a typo in this method name, using "FromSources", it should be "FromResources" as shown above.
You would need to add this to each Activity where you want to use such drawables, or perhaps include it in a BaseActivity class that your other Activities extend from.
Per the article, this should mean the following will now work:
DrawableContainers which reference other drawables resources which contain only a vector resource.
...StateListDrawable...InsetDrawable, LayerDrawable, LevelListDrawable and RotateDrawable.
It should be noted though, this method is heavily couched with the word 'may', this may work, and it is not enabled by default, so be aware and check it's really working for you!
Now there's actually another dimension to this question, credit to other users Selim Ajimi and Rapunzel Van Winkle for addressing this in their answers. <layer-list> has some different behaviour between the API's, in particular the width and height attributes of your <item> only being supported in API 23+. This is not the cause of your crash, nor will it cause your app to crash, but will mean that your image will not look as intended once you have it functioning in earlier APIs.
The suggestion from Rapunzel Van Winkle does indeed seem to be a good way to position the drawable correctly across APIs (tested on API 16 and 24):
<?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="#bdbdbd" />
<size
android:width="60dp"
android:height="60dp" />
</shape>
</item>
<item
android:drawable="#drawable/ic_library_books_black_24dp"
android:top="10dp"
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
>
</item>
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#[package:]drawable/drawable_resource"
android:id="#[+][package:]id/resource_name"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension" />
</layer-list>
As you can see here doesn't have width/height attributes...
You can append Bitmap to item I think this is the best solution
The support for VectorDrawble on old Android versions is quite limited, assuming you use vectorDrawables.useSupportLibrary = true :
You can use VectorDrawableCompat back to API level 7 and
AnimatedVectorDrawableCompat on all devices running Android 5.0 (API
level 11) and higher. The way Android loads drawables, not every place
that accepts a drawable ID, such as in an XML file, supports loading
vector drawables. The android.support.v7.appcompat package has added a
number of features to make it easy to use vector drawables. Firstly,
when you use android.support.v7.appcompat package with ImageView or
with subclasses such as ImageButton and FloatingActionButton, you can
use the new app:srcCompat attribute to reference vector drawables as
well as any other drawable available to android:src
Even in code, you are limited:
To change drawables at runtime, you can use the setImageResource()
method as before. Using AppCompat and app:srcCompat is the most
foolproof method of integrating vector drawables into your app.
What can you do?
Few possible solutions:
have alternative drawable for the VectorDrawable that you use in the LayerDrawable. Put it in res/drawable-xxhdpi, for example, and the VectorDrawable into res/drawable-anydpi .
don't use vectorDrawables.useSupportLibrary = true till you have the app have a minSdk that is capable of using VectorDrawable. This will work because the IDE will generate PNG files for you.
create the layerList programmatically (example here), and in order to put the VectorDrawable, use AppCompatResources.getDrawable . You might also be able to do it with XML, except the part of putting the VectorDrawable.
BTW, the reason that it's limited, is that Google failed to make it efficient and without issues. You can get to their original attempt of having full support, by using AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) , but as the docs say, you are taking a risk here:
This feature defaults to disabled, since enabling it can cause issues
with memory usage, and problems updating Configuration instances. If
you update the configuration manually, then you probably do not want
to enable this. You have been warned.
Related
what is the essence of the question:
Why is the color that I write in solid in the shape not taken into account
Why do I have a white background on the back of the button now (attached a photo)? I don't understand where I can fix it
I found a video on YouTube and there was the following solution: Create an xml file in drawable and there I specified the following:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="#color/teal_700"></solid>
</shape>
</item>
</selector>
The problem is that when the videos came out, there were no themes and everything worked out perfectly right away, and I tried to figure out why I didn't apply color to the button if I set it in the shape, but I never figured it out and it doesn't take into account my color that I set in solid :) I decided to change the primaryColor in the theme to the color I needed and then it applied.
And can you also throw, please, useful modern resources to the latest versions of android studio? I'm just learning, so I haven't found much yet and it would be interesting to see some examples for new updates, because all the videos are from earlier versions and some of them don't converge, as, for example, now in the question
If there are not enough details to solve the problem, then write to me
To make A Button Round Use MaterialButton
<com.google.android.material.button.MaterialButton
android:layout_width="100dp"
android:layout_height="50dp"
android:text="1"
app:cornerRadius="18dp" />
I was surfing the web to find a new style for the android layout and I find a pretty interesting one. Here is the Image.
I know more than basics about layout, but what I wanna is how can I give a 3d style look like in the above image? Especially that #7881 Code Box.
Here is Something that I have tried.
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:bottom="-25dp"
android:top="-25dp"
android:left="25dp"
android:right="25dp">
<rotate android:fromDegrees="20">
<shape android:shape="rectangle">
<size
android:width="50dp"
android:height="100dp"/>
<solid android:color="#E30B3E"/>
</shape>
</rotate>
</item>
</layer-list>
The output is this
Overall it gives the textview a 3d look but I want something like that in the image.
Any Suggestions?
Its pretty much simple just use android:rotationX property on the CardView
like this
<com.google.android.material.card.MaterialCardView
...
android:rotationX="20"
...
That's easy as long as the box should not be animated in its shape.
Go to https://www.figma.com/ and start a new project (it's free)
Export any shape you create there as svg
Import this svg into Android Studio using the Resource Manager
add your new drawable as background of the box.
Additional input, so your 50 points aren't wasted ;) :
You find several Android Presets for figma. Like UI Elements or buttons. For example here. For more just google for "Figma Android UI kit"
You can edit the generated SVG to your likes. Since it is only a text file, you can customize its colors (also using backgroundTint in xml), etc.
I'm having a very similar problem as to what was described in this question, but the answer is hacky and not really a proper answer, although it works.
Android Studio 1.4: drawable-v21 ignored when using "File/New/Vector Asset" option
I have a button, that I want to apply a pressed color to on pre21 devices, and use the ripple on v21+ devices.
In the drawable folder I have button_primary_theme
<?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="#color/themePimaryrOnePressed" />
</shape>
</item>
<item>
<shape>
<solid android:color="#color/themePrimaryOne" />
</shape>
</item>
</selector>
In the drawable-v21 folder I have
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="?attr/colorPrimary"/>
</ripple>
No matter what I do, I can't get my layout to use the ripple effect from the v21 folder on my Lollipop device. It keeps using the pre lollipop drawable.
<Button
android:id="#+id/getting_started"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/button_primary_theme" />
In the other answer, he made a separately named file for v21 effect, but that means I need a new copy of the layout in addition to the new drawable, and that shouldn't be necessary to get this to work.
I've tried cleaning the project, but it still uses the non v21 drawable.
How do I get this to work without making copies of everything?
Looks like this was my fault. Hopefully this might help someone else.
My normal drawable was actually in the drawable-nodpi folder, not drawable. I guess that was somehow overriding the v21 folder version.
So, I created shape using shape.xml like:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http//schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#ffffffff" />
<size android:width="60dp"
android:height="40dp" />
</shape>
But its not rendering the preview, in Preview pane.
I don't remember the last version on which it use to work properly.
Even, layout.xml 's preview is also not rendering when selected Android version is api22 : (Android 5.1.1).
I dont know why the last patch for update for 1.2 didn't actually fix this problem..
Any suggestions ??
I didn't found the actual problem, why it was not showing in preview pane. I had to, finally, create a new project where this problem was gone, and copied files from my old project to this new one.
I must say, ANDROID STUDIO really needs some serious bug fixes, with some memory optimizations, as, not all configurations are capable to carry this heavy load on memory and CPU processing. Anyways, thanks to GOOGLE...
Creating a Drawable that is completely empty seems like a common need, as a place holder, initial state, etc., but there doesn't seem to be a good way to do this... at least in XML. Several places refer to the system resource #android:drawable/empty but as far as I can tell (i.e., it's not in the reference docs, and aapt chokes saying that it can't find the resource) this doesn't exist.
Is there a general way of referencing an empty Drawable, or do you end up creating a fake empty PNG for each project?
For me it didn't work when I tried to use #android:id/empty when making an empty drawable. For me, #android:color/transparent was the one.
I use an empty ShapeDrawable, i.e. create my own drawable/empty.xml containing just <shape/>
<shape />
creates an empty shape and does the trick for me. Or create a file empty_drawable.xml containing:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" />
so you can use it elsewhere.
You can also make a shape disappear when the view it is used in is not enabled by creating my_disablable_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape android:shape="oval">
<size android:height="10dp" android:width="10dp" />
<solid android:color="#android:color/white" />
</shape>
</item>
<item android:state_enabled="false">
<shape />
</item>
</selector>
Use #android:color/transparent and don't forgot add android:constantSize="true" on <selector>
For me, using #android:drawable/empty would show an error and prevent compiling. Using #android:id/empty fixed the error and let me compile, but showed "NullPointerException: null" in the Eclipse Layout editor. I changed it to #android:color/transparent and now everything is fine.
I can't vote up yet or I would have up'ed Emil's answer.
#null in XML has the same effect as using a null as a Drawable in Java.
Kai, I don't know why this is the case, but I've gotten the same issue. I think it might be related to the version of Android you're compiling for? In any case, I found that simply using #android:id/empty where you would use #android:drawable/empty does the trick.
I had the same problem. My App crashed with an empty vector image. I solved it by adding a transparent/invisible path element. I tested it with API 22 and 30.
ic_empty.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:strokeAlpha="0" android:pathData="M0,12h24"/>
</vector>
To create an empty Drawable image, you may use ShapeDrawable with transparent color:
val shapeDrawable = ShapeDrawable(OvalShape())
shapeDrawable.paint.color = context.getColor(android.R.color.transparent)
If the image size is important, use:
shapeDrawable.intrinsicWidth = 100
shapeDrawable.intrinsicHeight = 100