So, straight to the problem:
I've created a custom UIViewControllerTransitioningDelegate that I use to animate a view from one view controller, to full-screen in another view controller. Im doing this by creating UIViewControllerAnimatedTransitioning-objects that animate the presented view's frame. And it works great! Except when I try to adjust the additionalSafeAreaInsets of the view controller owning the view during dismissal...
It looks like this property is not accounted for when I'm trying to animate the dismissal of the view controller and its view. It works fine during presentation.
So, what I want is: use additionalSafeAreaInsets to diminish the effect of the safe area during animation, by setting additionalSafeAreaInsets to the "inverted" values of the safe area. So that the effective safe area starts at 0 and "animates" to the expected value during presentation, and starts at expected value and "animates" to 0 during dismissal.
(I'm quoting "animates", since its actually the view's frame that is animated. But UIKit/Auto Layout use these properties when calculating the frames)
Any thoughts on how to battle this issue is great welcome!
The code for the custom UIViewControllerTransitioningDelegate is provided as an attachment.
FullScreenTransitionManager.swift
Post not yet marked as solved
how to add a core animation layer as it own composition track.
Post not yet marked as solved
I have a simple app that lets a user navigate a maze. A token is moved around the maze in response to input by accelerometer, digital joystick, taps, or keyboard entry, depending upon settings and device capabilities. The view to the maze may be zoomed, in which case the maze pans to center the token. The main animations are to move the token, and to recenter the maze. An additional animation occurs if the token encounters certain prizes along the way. When that happens, the prize award is displayed over the token and then animated toward the center of the board.
Randomly and rarely, the animation changes to be very slow, when running a build to the Mac. Unlike the iOS simulators, I know of no way to toggle the animation speed when building to the Mac. Is there a way to toggle this? Am I somehow toggling it accidentally? When I do a test run on the Mac, I'm almost always using keyboard input, which is the arrow keys.
Unlike the iOS simulators, where halting and restarting after the animation has been slowed results in continued slow animations, if I halt the Mac build after the animation slows down and start again, it animates at normal speed.
Post not yet marked as solved
I have MyLayer and it has a sublayer that it also holds a reference to. In that setup what is the proper way to override init(layer: Any)?
Right now I'm doing it like this ... layer.mySublayer.presentation()! is that correct? Is that always going to work, or will presentation ever be nil in this context?
Thanks for any tips!
class MyLayer: CALayer {
var mySublayer: CALayer
public override init() {
mySublayer = CALayer()
super.init()
addSublayer(mySublayer)
}
override init(layer: Any) {
let layer = layer as! MyLayer
mySublayer = layer.mySublayer.presentation()!
super.init(layer: layer)
}
required init?(coder: NSCoder) {
fatalError("has not been implemented")
}
}
Is it possible to set a CALayer as the contents of a RealityKit material? Currently this is possible with SceneKit materials. I am wondering if there is something similar for RealityKit.
https://developer.apple.com/documentation/scenekit/scnmaterialproperty/1395372-contents
Post not yet marked as solved
I have a model CALayer that I animate.
I then remove that layer from its super layer.
I then wait for a long while
After this I'm surprised to see that my model layer still has a non-nil presentation layer. Is this expected behavior?
If this is not expected behavior what might make my model layers presentation layer stick around like that?
Thanks
Post not yet marked as solved
Since iOS 15.1, I am seeing the log message
CADisplayTimingsControl too many requests.
My app is SwiftUI based and yes, I do have one location in the code that uses CADisplayLink but I am fairly sure it is not the culprit.
I am seeing this during scrolling/list reloads in a SwiftUI app with a List/ForEach construct. At the same time I have multiple WKWebViews loading remote websites. I am not sure what the problem is but the app does lock up often with a deadlock in the main thread while none of my code is executed.
Any help with where this might be coming from is appreciated. I suspect it is a regression related to Pro Motion and/or SwiftUI an filed a radar including crash report as FB9731877.
Post not yet marked as solved
What animation program do most developers or designers use for adding animations to their apps?
I am a graphic/UI designer and have been working with XCode lately to develop an app. I would like to add animations to buttons, menus, and even full blown instructional animations for the user on how to use our products. I have used CoreAnimator, Adobe Animate and struggled with both. Adobe animate has issues with sizing for different devices and I have been working with them for months now trying to resolve the issue as it doesn't seem to be the constraints in Xcode.
I am not the best at coding but I am willing to learn. Do I need to learn Core Animation code to be able to animate buttons menus etc? Or are libraries easier?
As for the full blown instructional animations I feel like that would be more a long the lines of something similar to Adobe Animate?
TIA!
Post not yet marked as solved
I want to get animation interpolation during animation running.
just like code below:
Animator(begin:100,end:200).addListener({value in
//here will be called when animation updates.
print(value)
})
But I can't find any API like the code above in iOS SDK.And I don't want to use any UIView or CALayer to get presentationLayer to get this value.
So How can I do that?🤔🤔🤔
Post not yet marked as solved
Hi, I have been getting the following crash in my app which has a Custom Metal Render Engine
CoreFoundation -[__NSSetM clumpingFactor] + 264
libobjc.A.dylib __objc_empty_cache + 888
CoreAutoLayout DA979160-E330-3C35-BF6F-D3248DCC3246 + 67536
CoreAutoLayout DA979160-E330-3C35-BF6F-D3248DCC3246 + 68272
UIKitCore __OBJC_$_INSTANCE_METHODS__UIDatePickerCalendarTimeLabel + 600
UIKitCore __OBJC_$_INSTANCE_METHODS__UINavigationBarStarkVisualStyle + 100
UIKitCore ___79+[UISwitchModernVisualElement _modernThumbImageWithColor:mask:traitCollection:]_block_invoke_2 + 204
UIKitCore -[UISwitchModernVisualElement _switchTrackPositionAnimationWithFromValue:toValue:on:] + 388
UIKitCore -[UISwitchModernVisualElement _effectiveGradientImage] + 128
UIKitCore __OBJC_$_INSTANCE_METHODS__UISearchBarVisualProviderLegacy + 1924
QuartzCore CA::Layer::add_animation(CAAnimation*, __CFString const*) + 72
QuartzCore CA::Layer::remove_sublayer(CA::Transaction*, CALayer*) + 272
QuartzCore CA::OGL::Context::draw_elements(CA::OGL::PrimitiveMode, unsigned int, unsigned short const*, CA::OGL::Vertex const*, unsigned int, unsigned int, CA::OGL::ClipPlane const*) + 60
QuartzCore CAML::cgcolor_end(CAML::Context*, CAML::State*, char*, unsigned long) + 1252
QuartzCore native_window_swap(_EAGLNativeWindowObject*, unsigned int, double) + 712
QuartzCore -[CAStateControllerAnimation initWithLayer:key:] + 52
CoreFoundation ___CFSocketSetSocketReadBufferAttrs + 444
CoreFoundation __CFNonObjCEqual + 8
CoreFoundation __CFRelease + 952
Foundation 4E7D1FF6-6B64-3833-9E60-CC662AFE2647 + 36236
danmu -[DMEngineBase runMetalThread] (in DMEngineBase.mm:148)
Foundation 4E7D1FF6-6B64-3833-9E60-CC662AFE2647 + 1549068
libsystem_pthread.dylib _pthread_rwlock_unlock$VARIANT$armv81 + 160
libsystem_pthread.dylib __pthread_create + 1196
this crash seems caused by the Metal Thread Rendering which triggered a CoreAnimation drawing and finally crashed at CoreAutoLayout internal method :
Crashed View : appEnterForeground
Exception Name : NSInternalInconsistencyException
Exception Reason :
Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.
In the latest Version I have been trying solved this crash by add some protected like this :
- (void)runMetalThread
{
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[_displayLink addToRunLoop:runLoop forMode:DMMetalRunLoopModelFrame];
BOOL continueRunLoop = YES;
while (continueRunLoop)
{
@autoreleasepool
{
[runLoop runMode:DMMetalRunLoopModelFrame beforeDate:[NSDate distantFuture]];
}
continueRunLoop = _continueRunLoop;
}
}
- (void)onBulletDraw:(CADisplayLink*)displayLink
{
self.renderer.stoped = !_isActive || _stoped;
self.renderer.paused = _isPaused;
[self.renderer onDanmuDraw:displayLink];
}
#pragma mark - Notification
- (void)willResignActive
{
self.isActive = NO;
MTLog(@"metal# engine %@ resign active", self);
}
- (void)didBecomeActive
{
//Protected by delay active the metal engine after app state didBecomeActive
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (UIApplication.sharedApplication.applicationState == UIApplicationStateActive) {
self.isActive = YES;
MTLog(@"metal# engine %@ become active", self);
}else{
MTLog(@"metal# engine still inactive after 0.7s");
}
});
}
this protected has make sure to STOPed the Metal Render after the app resign active, and
seems has some effect which reduced 84% crashes on my released app . but it did not completely solve this problem still has 16% crashes in some unknown scene .
I have been checked all my Metal Rendering thread code , I can be guaranteed that no method will trigger CoreAnimation drawing in this metal thread. So is there has an Perfective Solution of this bug ?
Code to draw a graph of data. Each abscissa has an ordinate range to be displayed as a line segment.
All data, i.e., scaled points are verified to be within the declared analysisView.bounds. strokeColors are verified within the range 0..1
BTW, no I don't need animation for this static data, but CALayer seemed to require more coding, and I found fewer code examples for it.
The code below has two problems:
1) it doesn't draw into the window
the weird behavior of min/max
The first is why I am posting. What am I missing?
import AppKit
class AnalysisViewController: NSViewController {
@IBOutlet var analysisView: NSView!
var ranges = [ClosedRange<Double>]()
var ordinateMinimum = CGFloat()
var ordinateMaximum = CGFloat()
var ordinateScale = CGFloat()
let abscissaMinimum:CGFloat = 1
let abscissaMaximum:CGFloat = 92
let abscissaScale :CGFloat = 800/92
let shapeLayer = CAShapeLayer()
var points = [CGPoint]() // created just to verify (in debugger area) that points are within analysisView.bounds
func genrateGraph() {
// ranges.append(0...0) // inexplicably FAILS! @ ordinateMinimum/ordinateMaximum if replaces "if N == 1" below
// ranges.append(0.1...0.1) // non-zero range does not fail but becomes the min or max, therefore, not useful
for N in 1...92 {
if let element = loadFromJSON(N) {
if N == 1 { ranges.append( element.someFunction() ) } // ranges[0] is an unused placeholder
// if N == 1 { ranges.append(0...0) } // inexplicably FAILS! @ ordinateMinimum/ordinateMaximum if replacing above line
ranges.append( element.someFunction() )
}
else { ranges.append(0...0) } // some elements have no range data
}
ordinateMinimum = CGFloat(ranges.min(by: {$0 != 0...0 && $1 != 0...0 && $0.lowerBound < $1.lowerBound})!.lowerBound)
ordinateMaximum = CGFloat(ranges.max(by: {$0 != 0...0 && $1 != 0...0 && $0.upperBound < $1.upperBound})!.upperBound)
ordinateScale = analysisView.frame.height/(ordinateMaximum - ordinateMinimum)
for range in 1..<ranges.count {
shapeLayer.addSublayer(CALayer()) // sublayer each abscissa range so that .strokeColor can be assigned to each
// shapeLayer.frame = CGRect(x: 0, y: 0, width: analysisView.frame.width, height: analysisView.frame.height) // might be unneccessary
let path = CGMutablePath() // a new path for every sublayer, i.e., range that is displayed as line segment
points.append(CGPoint(x: CGFloat(range)*abscissaScale, y: CGFloat(ranges[range].lowerBound)*ordinateScale))
path.move(to: points.last! )
points.append(CGPoint(x: CGFloat(range)*abscissaScale, y: CGFloat(ranges[range].upperBound)*ordinateScale))
path.addLine(to: points.last! )
path.closeSubpath()
shapeLayer.path = path
// shapeLayer.strokeColor = CGColor.white
let r:CGFloat = 1.0/CGFloat(range)
let g:CGFloat = 0.3/CGFloat(range)
let b:CGFloat = 0.7/CGFloat(range)
// print("range: \(range)\tr: \(r)\tg: \(g)\tb: \(b)") // just to verify 0...1 values
shapeLayer.strokeColor = CGColor(srgbRed: r, green: g, blue: b, alpha: 1.0)
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.wantsLayer = true // one of these (view or analysisView) must be unneccessary
view.frame = CGRect(x: 0, y: 0, width: 840, height: 640)
analysisView.wantsLayer = true
analysisView.frame = CGRect(x: 0, y: 0, width: 840, height: 640)
genrateGraph()
}
}
Post not yet marked as solved
Hello all!
In my project, I have created a swipeable carousel view that changes a published property (currentHoleIdx) in my ViewModel that I use to programmatically change a TabView.
I want the TabView to animate when the index changes, and it does, but only with the deprecated .animated(.easeInOut).
I have tried .animation(.easeInOut, value:model.currentHoleIdx) and also tried withAnimation when I change the currentHoleIdx property.
I will do my best to post the code to show what I have done. Thanks in advance for any help!
TabView with animation
VStack {
ZStack(alignment: .top) {
// Mini Scorecard
MiniScorecard(scorecard:model.scorecards[model.currentScorecardIdx!], teams: model.scorecards[model.currentScorecardIdx!].teams)
.coordinateSpace(name: "mini")
// .opacity(showScore ? 1 : 0)
.background(Color("card"))
.background(
GeometryReader { geo in
Color.clear.onAppear {
showScoreOffset = geo.size.height
// print(geo.size.height)
}
}
)
// Scorecard TabView
TabView(selection: $model.currentHoleIdx,
content: {
ForEach(0..<model.scorecards[model.currentScorecardIdx!].holes.count) {idx in
let scorecard = model.scorecards[model.currentScorecardIdx!]
if scorecard.formatType == "individual" {
if scorecard.gameID == "Standard" {
IndivStandardScoreScrollview(idx:idx)
.tag(idx)
.animation(.easeInOut, value: model.currentHoleIdx) // // does not work does not work with idx or model.currentHoleIdx
}
} else {
if scorecard.gameID == "Standard" {
TeamStandardScoreScrollview(holeIdx:idx)
.tag(idx)
.animation(.easeInOut, value: idx) // does not work does not work with idx or model.currentHoleIdx
}
}
}
Color.clear
.tag(model.scorecards[model.currentScorecardIdx!].holes.count)
}).tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.background(Color("card"))
.offset(y:showScore ? showScoreOffset : 0)
.animation(.easeInOut, value: showScore)
.animation(.easeInOut, value: scorecardOffset)
// .animation(.easeInOut, value: model.currentHoleIdx) // does not work
}.frame(width:UIScreen.main.bounds.width - 30)
}
.offset(y: scorecardOffset)
.offset(y: model.currentHoleIdx < model.scorecards[model.currentScorecardIdx!].holes.count ? 0 : scorecardHeight)
.padding(.top)
.padding(.horizontal, 15)
.animation(.easeInOut, value: scorecardOffset)
.animation(.easeInOut, value: model.currentHoleIdx) // does not work!!!
// .animation(.easeInOut) // Only thing that works! when model.currentHoleIdx changes from drag gesture
.overlay(
GeometryReader { geo in
Color.clear.onAppear {
scorecardHeight = geo.size.height
}
}
)
Swipeable carousel drag gesture - withAnimation when interacting with model.currentHoleIdx
return HStack(alignment: .center, spacing: spacing) {
items
}
.offset(x: CGFloat(calcOffset), y: 0)
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .named("canvas")).updating($screenDrag) { dragValue, gestureState, transaction in
// self.model.screenDrag = Float(currentState.translation.width)
// gestureState == screenDrag
gestureState = dragValue.translation
}.onEnded { value in
// screenDrag = 0 - Don't need this, bc GestureState automatically resets back to initial value
// Swipe to next hole
if (value.translation.width < -15) && self.model.currentHoleIdx < Int(numberOfItems) - 1 {
// calculate currentholeidx based on swipe width and cardwidth
let calculatedHoleIdx = self.model.currentHoleIdx - Int(floor(value.translation.width/(cardWidth + spacing + 10)))
withAnimation { // withAnimation Here
self.model.currentHoleIdx = calculatedHoleIdx > Int(numberOfItems - 1) ? Int(numberOfItems - 1) : calculatedHoleIdx
}
let impactMed = UIImpactFeedbackGenerator(style: .medium)
impactMed.impactOccurred()
}
// Swipe to previous hole
if (value.translation.width > 15) && self.model.currentHoleIdx > 0 {
let calculatedHoleIdx = self.model.currentHoleIdx - Int(ceil((value.translation.width/(cardWidth + spacing + 10))))
withAnimation { // withAnimation Here
self.model.currentHoleIdx = calculatedHoleIdx < 0 ? 0 : calculatedHoleIdx
}
self.model.currentHoleIdx = calculatedHoleIdx < 0 ? 0 : calculatedHoleIdx
let impactMed = UIImpactFeedbackGenerator(style: .medium)
impactMed.impactOccurred()
}
I feel like i've tried every possible iteration of .animation and withAnimation. The only one that works is using the deprecated .animation() modifier. Hope to hear from someone soon. thanks again!
Post not yet marked as solved
I have a CALayer with many sublayers. Those sublayers have multiple CABasicAnimation added to them.
Now, I'd like to render the whole layer subtree to the UIImage at a specific point of animation time. How could I achieve that?
The only thing I found is a CALayer.render(in:) method but the docs say that this method ignores Core Animations :<
Post not yet marked as solved
I'm trying to add an animated CALayer over my video and export it with AVAssetExportSession.
I'm animating the layer using CABasicAnimation set to my custom property.
However, it seems that func draw(in ctx: CGContext) is never called during an export for my custom layer, and no animation is played.
I found out that animating standard properties like borderWidth works fine, but custom properties are ignored.
Can someone help with that?
func export(standard: Bool) {
print("Exporting...")
let composition = AVMutableComposition()
//composition.naturalSize = CGSize(width: 300, height: 300)
// Video track
let videoTrack = composition.addMutableTrack(withMediaType: .video,
preferredTrackID: CMPersistentTrackID(1))!
let _videoAssetURL = Bundle.main.url(forResource: "emptyVideo", withExtension: "mov")!
let _emptyVideoAsset = AVURLAsset(url: _videoAssetURL)
let _emptyVideoTrack = _emptyVideoAsset.tracks(withMediaType: .video)[0]
try! videoTrack.insertTimeRange(CMTimeRange(start: .zero, duration: _emptyVideoAsset.duration),
of: _emptyVideoTrack, at: .zero)
// Root Layer
let rootLayer = CALayer()
rootLayer.frame = CGRect(origin: .zero, size: composition.naturalSize)
// Video layer
let video = CALayer()
video.frame = CGRect(origin: .zero, size: composition.naturalSize)
rootLayer.addSublayer(video)
// Animated layer
let animLayer = CustomLayer()
animLayer.progress = 0.0
animLayer.frame = CGRect(origin: .zero, size: composition.naturalSize)
rootLayer.addSublayer(animLayer)
animLayer.borderColor = UIColor.green.cgColor
animLayer.borderWidth = 0.0
let key = standard ? "borderWidth" : "progress"
let anim = CABasicAnimation(keyPath: key)
anim.fromValue = 0.0
anim.toValue = 50.0
anim.duration = 6.0
anim.beginTime = AVCoreAnimationBeginTimeAtZero
anim.isRemovedOnCompletion = false
animLayer.add(anim, forKey: nil)
// Video Composition
let videoComposition = AVMutableVideoComposition(propertiesOf: composition)
videoComposition.renderSize = composition.naturalSize
videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
// Animation tool
let animTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: video,
in: rootLayer)
videoComposition.animationTool = animTool
// Video instruction > Basic
let videoInstruction = AVMutableVideoCompositionInstruction()
videoInstruction.timeRange = CMTimeRange(start: .zero, duration: composition.duration)
videoComposition.instructions = [videoInstruction]
// Video-instruction > Layer instructions
let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
videoInstruction.layerInstructions = [layerInstruction]
// Session
let exportSession = AVAssetExportSession(asset: composition,
presetName: AVAssetExportPresetHighestQuality)!
exportSession.videoComposition = videoComposition
exportSession.shouldOptimizeForNetworkUse = true
var url = FileManager.default.temporaryDirectory.appendingPathComponent("\(arc4random()).mov")
url = URL(fileURLWithPath: url.path)
exportSession.outputURL = url
exportSession.outputFileType = .mov
_session = exportSession
exportSession.exportAsynchronously {
if let error = exportSession.error {
print("Fail. \(error)")
} else {
print("Ok")
print(url)
DispatchQueue.main.async {
let vc = AVPlayerViewController()
vc.player = AVPlayer(url: url)
self.present(vc, animated: true) {
vc.player?.play()
}
}
}
}
}
CustomLayer:
class CustomLayer: CALayer {
@NSManaged var progress: CGFloat
override init() {
super.init()
}
override init(layer: Any) {
let l = layer as! CustomLayer
super.init(layer: layer)
print("Copy. \(progress) \(l.progress)")
self.progress = l.progress
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override class func needsDisplay(forKey key: String) -> Bool {
let needsDisplayKeys = ["progress"]
if needsDisplayKeys.contains(key) {
return true
}
return super.needsDisplay(forKey: key)
}
override func display() {
print("Display. \(progress) | \(presentation()?.progress)")
super.display()
}
override func draw(in ctx: CGContext) {
// Save / restore ctx
ctx.saveGState()
defer { ctx.restoreGState() }
print("Draw. \(progress)")
ctx.move(to: .zero)
ctx.addLine(to: CGPoint(x: bounds.size.width * progress,
y: bounds.size.height * progress))
ctx.setStrokeColor(UIColor.red.cgColor)
ctx.setLineWidth(40)
ctx.strokePath()
}
}
Here's a full sample project if someone is interested:
https://www.dropbox.com/s/evkm60wkeb2xrzh/BrokenAnimation.zip?dl=0
Post not yet marked as solved
Hi there,
I was wondering whether its possible, in Reality Composer, to add a mesh object into the scene with an animated texture onto it? Whether it's a sprite sheet or a simple tiling offset animation?
If not, is there a way to switch textures that are on an object? Either immediately on tap, or gradually fade from one to the other.
Post not yet marked as solved
Hi Expert,
When I launched my App, just saw the following crash once:
crash log
Looks like there is something dead loop in the system libraries? related to NSNotificationCenter? any clue on this? Thanks a lot.
Reposting for better tags. Please see the details for the original post:
https://developer.apple.com/forums/thread/688268
I tried to pair the CATransaction.begin() and CATransaction.commit() but it does not work. Maybe I am doing it wrong.
Post not yet marked as solved
I have a keyframe animation that animates an indicator in a control. Picture something like a speedometer in an arc where a pointer animates along the top.
I set rotationMode on the animation to kCAAnimationRotateAuto and the animation itself works perfectly. When the animation completes, the pointer blinks back to a zero angle rotation. I want it to stay in the rotation it was in at the end of the animation.
I tried using animationDidStop:finished: to set my layer's transform to the desired angle with layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1) at the end of the animation which does set the correct rotation angle at the end of the animation, but then the animation itself has an incorrect rotation.
I tried setting the layer's transform before the animation starts thinking the animation would animate to that value, but the animation was even more bonkers.
Not sure what else to try. The rotationMode works beautifully, except for the end state.
Post not yet marked as solved
I am playing around with the keystoneCorrection filters. The properties that one can change are inputTopLeft, inputTopRight, inputBottomLeft, inputBottomRight, and inputFocalLength, The problem is that I cannot find any documentation as to how this filter works or any sample code. Would anyone have insights as to how this all works?
Post not yet marked as solved
Hi,
My UICollectionViewCell has a subview UIImageView, which has a mask CALayer that I control and that I add animations to.
Recently, I noticed that the animation wasn't working and I was wondering why. I finally figured out that it depends on whether I apply my NSDIffableDataSourceSnapshot animated or not.
The animation would only work as expected, if the snapshot is applied animated.
This raised a question: What happens if the snapshot is applied without animation? And why is it affecting CABasicAnimation on a CALayer?
I haven't found a solution for it yet, so I wanted to ask here in case anybody knows what's up.
imageView.layer.mask = animationLayer
animationLayer.removeAllAnimations()
let animation = CABasicAnimation(keyPath: "locations")
/// ...
animationLayer.add(animation, forKey: "shimmer")
This code runs when the cell is gathered from the collection view for an index path.
dataSource.apply(snapshot, animatingDifferences: false)
Is there any way to apply a snapshot without animation while keeping animations within the cell working correctly?
Thanks