UPDATE: Solution found! Scroll down for my accepted answer!
I want to animate multiple elements of one image and link the animation to ViewPagers position (so multiple elements are morphing or flying in/out depending on the current page being dragged).
So, is there a way to precisely control the current frame of the animation? For example let's assume i have this set:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="800"
android:propertyName="scaleY"
android:valueFrom="0"
android:valueTo="1" />
<objectAnimator
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="800"
android:propertyName="scaleX"
android:valueFrom="0"
android:valueTo="1" />
<objectAnimator
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="800"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360" />
</set>
Animated vector file:
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/pre_signup_1" >
<target
android:name="plus_button"
android:animation="@anim/pre_signup_1_plus_container" />
<target
android:name="plus"
android:animation="@anim/pre_signup_1_plus_sign" />
</animated-vector>
Java code to run the animation:
ImageView mImage1 = (ImageView) findViewById(R.id.image_1);
AnimatedVectorDrawableCompat animated = (AnimatedVectorDrawableCompat) mImage1.getDrawable();
animated.start();
Is there a way to control the animation like setCurrentDuration(400)
which will presumably set the current state of the animation to it's half? Maybe there is a way to split that vector drawable into layers and animate them programmatically? Thanks in advance!
Looks like it is possible to access paths and groups inside VectorDrawableCompat
and animate/morph them however you want!
After a some research I ended up duplicating the following classes from the android.support.graphics.drawable
package: AndroidResources
, PathParser
, TypedArrayUtils
, VectorDrawableCommon
and VectorDrawableCompat
.
Next we need to make the following method and classes public inside of the VectorDrawableCompat
class: getTargetByName
, VGroup
and VFullPath
.
Next in the VectorDrawableCompat
class remove the block that checks for Android version (Build.VERSION.SDK_INT >= 23
). Don't know why, but if you don't do it, the animating won't work on android API 23 and up (need more research).
I may have missed a couple of private methods, but it's just a matter of making them public if you run into problems.
So, now we have access to the layers of our VectorDrawable
! Here is a small example of scaling a vector group depending on the ViewPager
's position:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="276dp"
android:height="359dp"
android:viewportWidth="276"
android:viewportHeight="359">
<group
android:pivotX="205.5"
android:pivotY="214.5"
android:name="my_group">
<path
android:strokeColor="#4D394B"
android:strokeWidth="7"
android:strokeLineJoin="bevel"
android:fillColor="#1ED761"
android:pathData="M206.5,180 C186.9,180,171,195.9,171,215.5 S186.9,251,206.5,251
C226.1,251,242,235.1,242,215.5 S226.1,180,206.5,180 Z" />
<path
android:fillColor="#4D394B"
android:pathData="M210,211 L210,190 L202,190 L202,211 L181,211 L181,219 L202,219 L202,241 L210,241
L210,219 L232,219 L232,211 Z" />
</group>
</vector>
And this is the code used to animate the group:
ImageView myImageView;
VectorDrawableCompat.VGroup myVectorGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myImageView = (ImageView) findViewById(R.id.image_1);
VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_drawable, null);
vectorDrawable.setAllowCaching(false); // Important to allow image updates
myVectorGroup = (VectorDrawableCompat.VGroup) vectorDrawable.getTargetByName("my_group");
myImageView.setImageDrawable(vectorDrawable);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(myVectorGroup != null && position < 1) {
myVectorGroup.setScaleX(1f - positionOffset);
myVectorGroup.setScaleY(1f - positionOffset);
myImageView.invalidate();
}
}
});
}
I need some more testing to determine compatibility, but it works for now!