AnimateVectorDrawable - Creating an animation in code, rather than pure XML

Hi.
I have been really struggling to find any good information on how to create an animation with a vector drawable in code in Xamarin.Android.
I have successfully got an animation working purely in with using XMLs.
with a animatehand.xml
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:name="needle"
android:propertyName="rotation"
android:duration="2000"
android:valueFrom="0"
android:valueTo="1080"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>
</set>
this is the clockanimation.xml
<?xml version="1.0" encoding="utf-8" ?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/fullclock">
<target android:name="needle" android:animation="@anim/animatehand"/>
</animated-vector>
and the fullclock.xml
<?xml version="1.0" encoding="utf-8" ?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="99.99845dp"
android:height="99.99489dp"
android:viewportWidth="26.457922"
android:viewportHeight="26.456982">
<group android:name="face"
android:pivotX="13.22"
android:pivotY="13.22">
<path
android:pathData="M13.229,13.2285m-13.2274,0a13.2269,13.2274 90.0155,1 1,26.4548 0a13.2269,13.2274 90.0155,1 1,-26.4548 0"
android:strokeWidth="0.1"
android:fillColor="#808080"
android:strokeColor="#000000"/>
<path
android:pathData="M13.229,13.2285m-11.9513,0a11.9509,11.9513 90.0765,1 1,23.9026 0a11.9509,11.9513 90.0765,1 1,-23.9026 0"
android:strokeAlpha="0.309237"
android:strokeWidth="0.1"
android:fillColor="#f2f2f2"
android:strokeColor="#808080"/>
<path
android:pathData="m13.229,22.2148l0.9717,1.3374L13.229,24.8897l-0.9717,-1.3374z"
android:strokeAlpha="0.309237"
android:strokeWidth="0.0918885"
android:fillColor="#f2f2f2"
android:strokeColor="#000000"/>
</group>
<group
android:name="needle"
android:pivotX="13"
android:pivotY="13">
<path
android:pathData="m13.229,23.5523 l1.1186,-10.7632h-2.2372zM13.232,13.4289a0.2073,0.2209 0,0 1,-0.003 0,0.2073 0.2209,0 0,1 -0.2073,-0.2209 0.2073,0.2209 0,0 1,0.2073 -0.2209,0.2073 0.2209,0 0,1 0.2073,0.2209 0.2073,0.2209 0,0 1,-0.2038 0.2209z"
android:strokeWidth="0.0151836"
android:fillColor="#333333"
android:strokeColor="#000000"/>
</group>
</vector>
This is all well and good for static animations, I need to be able to set the stopping point of the hand to a particular angle, so I need to be able to define the animation in the code.
I found a tutorial in Kotlin on doing this, which is what I have tried to implement in Xamarin (https://blog.jakelee.co.uk/programmatically-creating-and-scheduling-animations-for-android-drawable-layers-with-objectanimator/)
this is my layerlist.xml
<?xml version="1.0" encoding="utf-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/face"
android:drawable="@drawable/clockface">
</item>
<item android:id="@+id/hand">
<rotate android:drawable="@drawable/hand" />
</item>
</layer-list>
I broke up the fullclock.xml in to two clockface.xml and hand.xml
clockface.xml
<?xml version="1.0" encoding="utf-8" ?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="99.99845dp"
android:height="99.99489dp"
android:viewportWidth="26.457922"
android:viewportHeight="26.456982">
<group android:name="face"
android:pivotX="13.22"
android:pivotY="13.22">
<path
android:pathData="M13.229,13.2285m-13.2274,0a13.2269,13.2274 90.0155,1 1,26.4548 0a13.2269,13.2274 90.0155,1 1,-26.4548 0"
android:strokeWidth="0.1"
android:fillColor="#808080"
android:strokeColor="#000000"/>
<path
android:pathData="M13.229,13.2285m-11.9513,0a11.9509,11.9513 90.0765,1 1,23.9026 0a11.9509,11.9513 90.0765,1 1,-23.9026 0"
android:strokeAlpha="0.309237"
android:strokeWidth="0.1"
android:fillColor="#f2f2f2"
android:strokeColor="#808080"/>
<path
android:pathData="m13.229,22.2148l0.9717,1.3374L13.229,24.8897l-0.9717,-1.3374z"
android:strokeAlpha="0.309237"
android:strokeWidth="0.0918885"
android:fillColor="#f2f2f2"
android:strokeColor="#000000"/>
</group>
</vector>
hand.xml
<?xml version="1.0" encoding="utf-8" ?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="99.99845dp"
android:height="99.99489dp"
android:viewportWidth="26.457922"
android:viewportHeight="26.456982">
<group
android:name="needle"
android:pivotX="13"
android:pivotY="13">
<path
android:pathData="m13.229,23.5523 l1.1186,-10.7632h-2.2372zM13.232,13.4289a0.2073,0.2209 0,0 1,-0.003 0,0.2073 0.2209,0 0,1 -0.2073,-0.2209 0.2073,0.2209 0,0 1,0.2073 -0.2209,0.2073 0.2209,0 0,1 0.2073,0.2209 0.2073,0.2209 0,0 1,-0.2038 0.2209z"
android:strokeWidth="0.0151836"
android:fillColor="#333333"
android:strokeColor="#000000"/>
</group>
</vector>
in my activity_main.xml I have the following ImageView
<ImageView
android:id="@+id/ClockTest"
android:layout_width="100sp"
android:layout_height="100sp"
android:layout_column="0"
android:gravity="center"
android:scaleType="center"
android:src="@drawable/layerlist"
/>
this is the code that I thought would create the animation, which is in my MainActivity.cs
AnimatorSet animset; // class field
This is all in OnCreate
ImageView iva = FindViewById<ImageView>(Resource.Id.ClockTest);
var animationlayer = iva.Drawable as LayerDrawable;
var _ned = animationlayer?.FindDrawableByLayerId(Resource.Id.hand);
var rotate = ObjectAnimator.OfFloat(_ned, "rotation", 0f, 360f).SetDuration(3000);
animset = new AnimatorSet();
animset.SetInterpolator(new AccelerateDecelerateInterpolator());
animset.Play(rotate).With(ObjectAnimator.OfFloat(_ned, "pivotX", 13.22f)).With(ObjectAnimator.OfFloat(_ned, "pivotY", 13.22f));
In a Button Click event handler.
animset.Start()
The animation does not play. I cannot see what I'm missing.
Can anyone offer any assistance or advice on this please. The subject of Animated Vector Drawables seems to be one people only do in XML for tutorial purposes.
Thanks
Andy
I have tried that and it doesn't play.
If I have the following XMLS it will play
One for the ObjectAnimator, an XML for the AnimatedVector, which sets the drawable and the targets the ObjectAnimator. then it will play.
I need to be able to set the Object Animator not as an XML as the start and end angles of the rotation are different each time. They define the outcome of the program.
This document may help you on creating the animiaton on Android.
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/graphics-and-animation
This document may help you on creating the animiaton on Android.
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/graphics-and-animation
Thanks, That was one of the 1st pages I read on the subject. It still doesn't answer my question on Animating in Code a Vector Drawable without having to Animate a view. Since a Vector Drawable can be Animated if it setup purely in XMLs then how do you it code?
I have uploaded a test program to github here
https://github.com/BoardinCode/VectorAnimationTest
It has 3 views, two are animated by Animating the view. The 1st uses an AnimatorSet and an Object Animator, the 2nd is using a Spring Animator as suggested by @JarvanZhang and the 3rd is trying to Animate directly a VectorDrawable.
The floating button is used to start the animations playing. The 1st two play, the last does not.
What am I missing please or is it not possible to do what I am trying the 3rd view?
Thanks
Andy.
Hi, I tested your sample project, the first parameter of the
ObjectAnimator.OfFloat
command in the third solution should be the imageView instance.Is it not possible to Animate a VectorDrawable in this way without animating the container that it is in?
Ideally I don't want to move the ImageView (I have gone with this as a solution, as all I need at present is rotation. Though my solution needs two stacked ImageViews one for the hand and one for the backing image),
I want to animate the VectorDrawable by specifying the parameters at run time.
Cheers
Andy.
We cannot perform the animiation using VectorDrawable directly, the VectorDrawable class doesn't provide the related method.
So it always has to be on a ImageView or other user control object?
Thanks
Andy.
According to the document, the answer is yes. Please use the first two solutions in your sample to add the animiation.
Sign in to comment
1 answer
Sort by: Most helpful
Hi,
I have just tried that and the cast isn't valid. It throws a runtime exception, as does using AnimatedVectorDrawableCompat
(Edit: the exceptions were due to the Resource.Drawable.Needle isn't an <animated-vector> but a <vector-drawable>. if I set up an XML with an <animated-vector> then it does load ok)
If I set the animation purely in XML so an <animated-vector> which references a <vector-drawable> and targets a <set> with <objectanimator> then that will play.
What I cannot get working is getting the Animation to play when I create an AnimatorSet in C# and assign it to a vector drawable. I need to be able to do this as the start and end angles are different each time.
I have managed to get a partially working solution by animating the ImageView (and rotating that) rather than the vector-drawable.
Is it not possible to animate the vector drawable directly in C# code?
)
This is the code I have, the set.Start() function is in a button click event handler
It does not when the button is pressed, the animation does not start.
I cannot see why it does not play (unless it is not intended to work this way.) I have got an animation working by animating the ImageView rather than the drawable. Though it seem to me that the your should be able to animate the drawable.
Hi, what exception occured? Please post the related details about the error log.
That the cast to AnimatedVectorDrawableCompat wasn't valid.
I realised though (I forgot to update the post) that it was a vector drawable i was casting from rather than an Animated-Vector.
So in the couple of lines of code you posted
The resource GetDrawable was opening was a Vector-Drawable XML not an Animated Vector XML
I have changed it and if in the Animated Vector XML, I target an XML with Object Animator then the animation plays, I do not want to do that. I need to be able to specify the parameters for the Animation while the program is running. The Rotation of needle has different start and stop points. this is what I cannot seem to get right.
Thanks
Andy
To achieve the dynamic animiation, try using the Xamarin.Android.Support.Dynamic.Animation package. You could google with the keyword as Dynamic Animation (Material Design) – Quick Tutorial to check the realted tutoiral.
Thanks. I had missed this.
The Spring Animation does let me Animate a View (similar to the ObjectAnimator). This does work as I can rotate a view to the desired position.
Am I correct in thinking that you can create an animation with vector drawable that plays with pre-set parameters in just XMLS.
If you want to create a dynamic animation then you have to animate the view that the vector drawable is in? This may require several stacked image views depending on what you want to animate. In my case it is two. One for the dial face and one for the needle that the view it is in. It is the view that is rotate to the desired angle?
Thanks
Andy.
Sign in to comment
Activity