100 lines
4.7 KiB
Markdown
100 lines
4.7 KiB
Markdown
+++
|
|
template = "article.html"
|
|
title = "Compat libraries incompatibilities"
|
|
date = 2017-05-06T19:52:26+02:00
|
|
description = "Navigating the challenges of Android compat libraries, particularly with vector drawables and their unexpected limitations."
|
|
|
|
[taxonomies]
|
|
tags = ["android"]
|
|
+++
|
|
|
|
Compat libraries are great. They allow us to work with the newest Android APIs,
|
|
without thinking (much) about your minimum API level. Instead of thousands
|
|
of devices, you can reach billions. With nearly no changes in your code.
|
|
|
|
But sometimes, they're not so great…
|
|
|
|
<!--more-->
|
|
|
|
Support for vector drawables (mainly SVGs files) has been added in API 21. They
|
|
come in two kinds: still and animated. They're great for many reasons: they
|
|
scale properly, you don't have to keep multiple densities of the same image
|
|
anymore, you can reference colors and dimensions from resources, you can do path
|
|
morphing… well, almost.
|
|
|
|
In order to use vector drawables on pre-21 APIs, Google released a set of two
|
|
support libraries, `com.android.support:vector-drawable` and
|
|
`com.android.support:animated-vector-drawable`. The first one works starting
|
|
with API 7, the latest with API 11. Everything is explained
|
|
[here](https://android-developers.googleblog.com/2016/02/android-support-library-232.html).
|
|
|
|
Still drawables should work exactly the same regarding the API level you're
|
|
running. On the animated version, however, there's a catch: you can't animate
|
|
all the properties you can on 21+. From the
|
|
[documentation](https://developer.android.com/reference/android/support/graphics/drawable/AnimatedVectorDrawableCompat.html):
|
|
|
|
> Note that the animation in AnimatedVectorDrawableCompat has to be valid and
|
|
> functional based on the SDK version the app will be running on. Before SDK
|
|
> version 21, the animation system didn't support the following features:
|
|
>
|
|
> * Path Morphing (PathType evaluator). This is used for morphing one path into
|
|
> another.
|
|
> * Path Interpolation. This is used to define a flexible interpolator
|
|
> (represented as a path) instead of the system defined ones like
|
|
> LinearInterpolator.
|
|
> * Animating 2 values in one ObjectAnimator according to one path's X
|
|
> value and Y value. One usage is moving one object in both X and Y
|
|
> dimensions along a path.
|
|
|
|
Let's say you want an animation using path morphing. Place your vector drawable
|
|
in the `drawable-v21` folder and add a fallback with a rotation or whatever in
|
|
the `drawable` one, and you're good to go, right? *Right?*
|
|
|
|
The same page of the documentation also mentions this:
|
|
|
|
> For API 24 and above, this class is delegating to the framework's
|
|
> AnimatedVectorDrawable. For older API version, this class uses ObjectAnimator
|
|
> and AnimatorSet to animate the properties of a VectorDrawableCompat to create an
|
|
> animated drawable.
|
|
|
|
And here come troubles. The reasoning behind this is that SDK's implementation
|
|
on APIs 21 to 23 [contains some bugs](https://issuetracker.google.com/issues/37116940#comment3).
|
|
However, using an `AnimatedVectorDrawableCompat` on an API 21 device comes with
|
|
the same limitations as running on an API 19 device: you're using the SDK's
|
|
`ObjectAnimator` and `AnimatorSet`, and they do *not* know the support libraries
|
|
symbols. More specifically, they don't know how to animate any
|
|
`android.support.graphics.drawable.PathParser$PathDataNode` (what they do know
|
|
about is the `android.util.PathParser$PathDataNode` class).
|
|
|
|
If you're looking for more technical bits, I wrote some more notes on this
|
|
[StackOverflow question](http://stackoverflow.com/q/43654496/775894) as I
|
|
stumbled upon this issue.
|
|
|
|
As a result, on APIs 21 to 23, any path-morphing animation fails silently when
|
|
using the support libraries. There's a work-around, though. You can use the
|
|
SDK's implementation to load your vector drawable:
|
|
|
|
```java
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
// Casting the drawable to an AnimatedVectorDrawable is useless here
|
|
// It's just to show that you don't get an AnimatedVectorDrawableCompat
|
|
AnimatedVectorDrawable drawable = (AnimatedVectorDrawable) getDrawable(R.drawable.ic_animated_drawable_32dp);
|
|
mBinding.imageView.setImageDrawable(drawable);
|
|
} else {
|
|
mBinding.imageView.setImageResource(R.drawable.ic_animated_drawable_32dp);
|
|
}
|
|
|
|
// Starting the animation works whatever the implementation we're using now
|
|
final Drawable animation = mBinding.imageView.getDrawable();
|
|
if (animation instanceof Animatable) {
|
|
((Animatable) animation).start();
|
|
}
|
|
```
|
|
|
|
However, using the SDK's implementation obviously means *not* making use of
|
|
the support library's bug-fixes. It will probably work for simple drawables, but
|
|
may fail on more complex ones.
|
|
|
|
As a final note: if you're using animated vector drawables, remember to test not
|
|
only on whatever your minimum SDK is and your latest shiny device, but also on
|
|
APIs 21 to 23. You might be surprised.
|