First things first — did you know that you can use UIImage to show frame-by-frame animations? It’s actually quite straight forward, all you need to do is:
- Prepare your frames in png format, name them using an ordering convention (for example “Frame1.png”, “Frame2.png”, …)
- Add these images to your Xamarin.iOS project, let’s say to Resources/Animation folder
- Make sure all of your images are referenced as BundleResource in your csproj:
<ItemGroup>
<BundleResource Include="Resources\Animation\*.png" />
</ItemGroup>
4. Load your images as UIImage and pass them to the UIImageView using AnimationImages property:
UIImage[] animationFrames = Enumerable.Range(1, 126)
.Select(i => $"{NSBundle.MainBundle.ResourcePath}/Animation/Frame{i}")
.Select(UIImage.FromBundle).ToArray();
var animatedImageView = new UIImageView
{
AnimationImages = animationFrames,
AnimationRepeatCount = 0, // repeats animation indefinitely
AnimationDuration = 2 // whole animation will take 2 secs
};
Add animatedImageView to your controller and here’s what you will see:
Great, it’s alive! 🧟♂️ What if you’d like to pause the animation on tap and then resume it after another tap? Sadly, there’s no API for this in the UIImageView, but there is a way to accomplish it using UIImageView’s Layer.
I’ve found it described in one of the Technical Q&As on developer.apple.com. This Objective C code may not be so easy to rewrite to C#, especially if you’re just getting started, so below is a working solution in Xamarin.iOS. You may want to polish the code a bit (extracting StopAnimation/StartAnimation extension methods may be a good start).
var animatedImageView = new UIImageView
{
AnimationImages = animationFrames,
AnimationRepeatCount = 0,
AnimationDuration = 2,
UserInteractionEnabled = true
};
animatedImageView.AddGestureRecognizer(new UITapGestureRecognizer(() =>
{
if (animatedImageView.Layer.Speed > 0.5)
{
var pausedTime = animatedImageView.Layer.ConvertTimeFromLayer(CAAnimation.CurrentMediaTime(), null);
animatedImageView.Layer.Speed = 0;
animatedImageView.Layer.TimeOffset = pausedTime;
}
else
{
var pausedTime = animatedImageView.Layer.TimeOffset;
animatedImageView.Layer.Speed = 1;
animatedImageView.Layer.TimeOffset = 0.0;
animatedImageView.Layer.BeginTime = 0.0;
animatedImageView.Layer.BeginTime = animatedImageView.Layer.ConvertTimeFromLayer(CAAnimation.CurrentMediaTime(), null) - pausedTime;
}
}));
Now you should be able to pause/resume the animation with taps:
gif source: cliply.co/clip/rocket-icon
FAQ:
Do I need to add my frames as iOS Assets? It’s kind of tedious with so many files! 😱
No, you can just drag and drop the whole folder to Resources, remember to reference files as BundleResource.
The animation is not pausing when I tap it, what’s wrong? 🤔
You might have forgotten to set UserInteractionEnabled to true on the UIImageView.
I hope that this quick tutorial was helpful to you. Let me know if something is not clear ✌🏻