Frequently Asked Questions
Rendering issues
- My SVG doesn't render if I try to do canvas.drawPicture() on the Picture returned by SVG.renderToPicture()
- The <clipPath> element doesn't work on some versions of Android
Scaling issues
- My SVG won't scale to fit the canvas or my ImageView
- My document has a viewBox, but it is still not scaling
- Dealing with Inkscape files
- My document used to scale okay prior to version 1.2.0, but doesn't now
- ScaleType.CENTER and ScaleType.FIT_XY do not work when using an ImageView or SVGImageView
My SVG doesn't render if I try to do Canvas.drawPicture() on the Picture returned by SVG.renderToPicture()
If the device you are testing on has Ice Cream Sandwich or later (API 14+), then hardware acceleration of the 2D rendering pipeline is enabled by default.
Unfortunately the hardware accelerated graphics pipeline does not support all of the drawing methods provided by Canvas
. One of the methods that
is not supported is drawPicture()
.
For more information on which methods are not supported, see the Unsupported Drawing Operations section of the Hardware Acceleration page on the Android developers site.
Solution
The solution is to disable hardware acceleration for the View into which you are drawing the SVG. If you are using the
supplied SVGImageView
class in your layouts, then this is done for you. You don't need to do anything.
To switch the view back to software rendering, use the View.setLayerType()
method.
setLayerType(LAYER_TYPE_SOFTWARE, null); Picture p = svg.renderToPicture(canvas.getWidth(), canvas.getHeight()); canvas.drawPicture(p);
Unfortunately there is one little problem with this solution. The setLayerType()
method was only added in API 11 (Honeycomb).
This means that you cannot call it directly if you want to support earlier versions of Android.
The way around this is to only call the method on Honeycomb or later. We list three possible approaches below:
(1) The support library approach
If you are using the v4 support library in your project (which is also included with the latest v7 appcompat library), you can simply use:
import android.support.v4.view.ViewCompat;
ViewCompat.setLayerType(view, ViewCompat.LAYER_TYPE_SOFTWARE, null);
This method will perform all the necessary version checking for you.
(2) The normal recommended approach
If you are targetting API 11 or later, you can use the constants in the android.os.Build
class to prevent setLayerType()
being
invoked when it is not available on the user's device.
import android.os.Build.*; @TargetApi(VERSION_CODES.HONEYCOMB) public static void setSoftwareLayerType(View view) { if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } // else: no layer support, so no hardware support to disable }
The @TargetApi
suppresses warnings about setLayerType()
not being available if your minSdkVersion
is set
lower than 11. However @TargetApi
is only available from API 16 on. So if your targetSdkVersion
is lower than that,
you will need to remove it (and live with any lint warnings).
(3) The old-style reflection approach
In almost all cases you will be able to use one of the first two approaches. We recommend you use one of them if you can. However
some people may be forced for some reason to use an old build environment (before API 11). If that is your situation, you can use Java
reflection to check whether the setLayerType()
method exists before calling it.
Add the following method to your View class and call it instead of the built-in setLayerType()
method.
/* * Use reflection to call setLayerType(). */ private void setSoftwareLayerType() { try { Method setLayerTypeMethod = View.class.getMethod("setLayerType", Integer.TYPE, Paint.class); int LAYER_TYPE_SOFTWARE = View.class.getField("LAYER_TYPE_SOFTWARE").getInt(null); setLayerTypeMethod.invoke(this, LAYER_TYPE_SOFTWARE, null); } catch (NoSuchMethodException e) { // Android platform too old. No setLayerType. } catch (Exception e) { Log.w("MySVGView", "Unexpected failure calling setLayerType", e); } }
setSoftwareLayerType(); Picture p = svg.renderToPicture(canvas.getWidth(), canvas.getHeight()); canvas.drawPicture(p);
Thanks to Robert Papp for contributing to this answer.
The clipPath
element doesn't work on some versions of Android
There are several reasons that this might be happening:
- On earlier versions of Android, the hardware accelerated rendering pipeline did not support the
Canvas.clipPath()
method, which is used by AndroidSVG.Solution: Upgrade to AndroidSVG 1.3.
For versions of the library before 1.3, try disabling hardware acceleration. See the answer above for instructions.
- On Android 4.3 there is a bug which stops clip paths working.
Solution: Unfortunately, there is no workaround.
- On Android 9 Pie, a
Canvas
method that AndroidSVG relied on, was completely removed from the API.Solution: Upgrade to AndroidSVG 1.3. It implements clip paths in a new and better way.
My SVG won't scale to fit the canvas or my ImageView
In order for SVG documents to be scaled, the document must have a viewBox
attribute in the root (outermost) <svg>
element.
See http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
For example:
<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="50" fill="red" /> </svg>
The purpose of the viewBox attribute is to describe the bounding box of the content. Without it, the renderer has no idea how much the document needs to be scaled to fit the viewport. The viewport is usually the rectangular extent of your canvas.
Most SVG editors will automatically add the correct viewBox for your file.
Solution
Add a viewBox manually to the file, or use the setDocumentViewBox()
method to add one at run-time.
So, for example if the interesting part of your SVG file is in the area (0,0) to (300,200), the viewBox attribute should be:
<svg viewBox="0 0 300 200" ...etc...>
or to set that in code, use:
svg.setDocumentViewBox(0, 0, 300, 300);
My document has a viewBox, but it is still not scaling
If your document specifies a width and height, then those will determine the size of your viewport. The document will be scaled to those dimensions, not your canvas.
Solution
In your SVG file, set the width
and height
attributes to "100%"
, or remove them entirely (if width
or height
are
not specified, they default to 100%
).
So your document should look like this:
<svg width="100%" height="100%" ...etc...>
or to set that in code, use:
svg.setDocumentWidth("100%"); svg.setDocumentHeight("100%");
Dealing with Inkscape files
Inkscape files have hard-coded width and height values but no viewBox. So they will not automatically scale to your canvas. To fix this, you need to do a combination of the above two solutions.
Solution
The following solution should work for most Inkscape files.
// Set the viewBox attribute using the document's width and height svg.setDocumentViewBox(0, 0, svg.getDocumentWidth(), svg.getDocumentHeight()); // Now set width and height to 100% so it will scale to fit the canvas svg.setDocumentWidth("100%"); svg.setDocumentHeight("100%");
You may also want to use setDocumentPreserveAspectRatio()
to tell AndroidSVG what type of scaling to use. However the default will usually be what you want.
My document used to scale okay prior to version 1.2.0, but doesn't now
In early versions of the library, I was being a bit over-enthusiastic and auto-scaling documents that didn't have a viewBox. That code worked in some situations, but not others, and made some assumptions that meant that the scaling wouldn't necessarily be correct anyway.
I decided to remove that code and instead provide some API methods that would allow users to have better control over how scaling happens.
My apologies if this change broke your code, but I felt it was important that I brought AndroidSVG into line with other renderers. These files would not scale if rendered in other renderers either.
Solution
Ensure you have appropriate values for viewBox
, width
and height
. See previous questions for more information.
ScaleType.CENTER and ScaleType.FIT_XY do not work when using an ImageView or SVGImageView
The ImageView
class has a bug which prevents ScaleType.CENTER
and ScaleType.FIT_XY
from working. Use another scale type instead. For example: ScaleType.CENTER_INSIDE
.
SVGImageView iv = new SVGImageView(this); iv.setImageAsset("test.svg"); lv.setScaleType(ImageView.ScaleType.CENTER_INSIDE); layout.addView(iv);