Core Animation

RSS for tag

Render, compose, and animate visual elements using Core Animation.

Core Animation Documentation

Posts under Core Animation tag

42 Posts
Sort by:
Post marked as solved
2 Replies
449 Views
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
Posted
by
Post not yet marked as solved
4 Replies
434 Views
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.
Posted
by
Post not yet marked as solved
1 Replies
321 Views
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")     } }
Posted
by
Post marked as solved
1 Replies
356 Views
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
Posted
by
Post not yet marked as solved
0 Replies
255 Views
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
Posted
by
Post not yet marked as solved
1 Replies
511 Views
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.
Posted
by
Post not yet marked as solved
1 Replies
601 Views
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!
Posted
by
Post not yet marked as solved
2 Replies
393 Views
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?🤔🤔🤔
Posted
by
Post not yet marked as solved
0 Replies
424 Views
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 ?
Posted
by
Post marked as solved
7 Replies
486 Views
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() } }
Posted
by
Post not yet marked as solved
0 Replies
339 Views
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!
Posted
by
Post not yet marked as solved
0 Replies
290 Views
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 :<
Posted
by
Post not yet marked as solved
0 Replies
341 Views
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
Posted
by
Post not yet marked as solved
1 Replies
448 Views
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.
Posted
by
Post marked as solved
1 Replies
423 Views
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.
Posted
by
Post not yet marked as solved
0 Replies
314 Views
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.
Posted
by
Post not yet marked as solved
0 Replies
397 Views
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?
Posted
by
Post not yet marked as solved
0 Replies
413 Views
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
Posted
by