Core Animation

RSS for tag

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

Posts under Core Animation tag

43 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

How to Stop macOS Menu Bar Animation on a Secondary Screen
Hello everyone, I'm working on a macOS application and encountering an issue related to multi-screen setups. My application includes an animation in the menu bar, and it works perfectly on the primary screen. However, I want this animation to stop or not appear when the app is being used on a secondary monitor(non-focused monitor). (for cpu related problem, when it's 3 monitor -> x3 cpu with x3 animation objects) I've tried a few approaches to detect when the application is being used on a secondary screen and then stop the animation, but so far, I haven't had any success. The main challenge seems to be accurately determining the screen where the app is actively being used and controlling the animation accordingly. Has anyone faced a similar issue or have suggestions on how to effectively stop or prevent the menu bar animation from running on a secondary screen? Any guidance or insights would be greatly appreciated. Thank you in advance for your help!
1
0
567
Jan ’24
EXC_BREAKPOINT - libobjc.A.dylib object_getClass Crash on the main thread
Having an issue with crashes on iOS 16 and iOS 17 devices. App works and will appear to operate normally. However after a while the app will crash with a EXC_BREAKPOINT on libobjc.A.dylib object_getClass. The root cause seems to be something related to UIViews/Core Animation, I think. However the root crash trigger seems to be a half a dozen different triggers from the UI on main thread. It also only triggers on release builds, or the dev builds take a lot longer to trigger to the point it's very difficult to reproduce. Here are some examples of the crashes occurring. Crashed: com.apple.main-thread 0 libobjc.A.dylib 0xe838 object_getClass + 48 1 Foundation 0x1c854 _NSKeyValueObservationInfoGetObservances + 264 2 Foundation 0x1bd1c NSKeyValueWillChangeWithPerThreadPendingNotifications + 232 3 QuartzCore 0x59408 CAAnimation_setter(CAAnimation*, unsigned int, _CAValueType, void const*) + 128 4 QuartzCore 0x749b4 -[CAAnimation setBeginTime:] + 52 5 QuartzCore 0x728b4 CA::Layer::commit_animations(CA::Transaction*, double (*)(CA::Layer*, double, void*), void (*)(CA::Layer*, CA::Render::Animation*, void*), void (*)(CA::Layer*, __CFString const*, void*), CA::Render::TimingList* (*)(CA::Layer*, void*), void*) + 740 6 QuartzCore 0x2aeac invocation function for block in CA::Context::commit_transaction(CA::Transaction*, double, double*) + 148 7 QuartzCore 0x2adb4 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 368 8 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 9 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 10 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 11 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 12 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 13 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 14 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 15 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 16 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 17 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 18 QuartzCore 0x6f548 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 11192 19 QuartzCore 0x65e3c CA::Transaction::commit() + 648 20 UIKitCore 0x924cc _afterCACommitHandler + 84 21 CoreFoundation 0x3583c __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36 22 CoreFoundation 0x34244 __CFRunLoopDoObservers + 548 23 CoreFoundation 0x33960 __CFRunLoopRun + 1028 24 CoreFoundation 0x33478 CFRunLoopRunSpecific + 608 25 GraphicsServices 0x34f8 GSEventRunModal + 164 26 UIKitCore 0x22c62c -[UIApplication _run] + 888 27 UIKitCore 0x22bc68 UIApplicationMain + 340 0 libobjc.A.dylib 0x5d94 object_getClass + 48 1 Foundation 0xadb8 _NSKeyValueObservationInfoGetObservances + 248 2 Foundation 0x3f670 NSKeyValueWillChangeWithPerThreadPendingNotifications + 232 3 QuartzCore 0xbb18 CAAnimation_setter(CAAnimation*, unsigned int, _CAValueType, void const*) + 128 4 QuartzCore 0xcc14 -[CAPropertyAnimation setKeyPath:] + 52 5 QuartzCore 0xcbc0 +[CAPropertyAnimation animationWithKeyPath:] + 36 6 UIKitCore 0xc89fb0 -[UIMorphingLabel animateGlyph:toScale:delay:] + 308 7 UIKitCore 0xc8a1fc -[UIMorphingLabel animateShowGlyph:alpha:alphaDuration:delay:] + 196 8 UIKitCore 0xc8b3f0 -[UIMorphingLabel animateSubstitutionAlignmentHunkAtIndex:] + 1068 9 UIKitCore 0x42cd84 -[UIMorphingLabel animateGlyphs] + 276 10 UIKitCore 0xa374 -[UIMorphingLabel layoutSubviews] + 368 11 UIKitCore 0x4420 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1992 12 QuartzCore 0x9f30 CA::Layer::layout_if_needed(CA::Transaction*) + 500 13 QuartzCore 0x1d4ac CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 148 14 QuartzCore 0x2e8d8 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 444 15 QuartzCore 0x5de80 CA::Transaction::commit() + 648 16 QuartzCore 0x47df0 CA::Transaction::flush_as_runloop_observer(bool) + 88 17 CoreFoundation 0x90234 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36 18 CoreFoundation 0x1a410 __CFRunLoopDoObservers + 532 19 CoreFoundation 0x7a19c __CFRunLoopRun + 1028 20 CoreFoundation 0x7f3ec CFRunLoopRunSpecific + 612 21 GraphicsServices 0x135c GSEventRunModal + 164 22 UIKitCore 0x39cf58 -[UIApplication _run] + 888 23 UIKitCore 0x39cbbc UIApplicationMain + 340 I'm at a loss, I'm clearly doing something wrong in the UIView/Core Animation side of things. Would be very grateful for anyone who can point me in the right direction.
6
1
1.3k
Jan ’24
Modifications to the layout engine must not be performed from a background thread on iOS 17 and above
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread. I have been experiencing frequent crashes on iOS 17 and above recently, and I'm having trouble pinpointing the source of the crashes. The crash logs provide no information about the specific location of the crashes. Is there any workaround or solution to identify and resolve this issue? Please find attached the crash logs below
2
0
774
Dec ’23
App crashes: CA::Render::InterpolatedFunction::encode(CA::Render::Encoder*)
I've started seeing several users getting an app crash that I've been unable to find the root cause for so far. I've tried running the app in release build with address sanitizer and zombie objects checks enabled but have been unable to reproduce it. It only occurs for iOS 17 users. Any ideas on how I can troubleshoot this? Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000000 Crashed: com.apple.main-thread 0 libsystem_platform.dylib 0xed4 _platform_memmove + 52 1 QuartzCore 0x137120 CA::Render::InterpolatedFunction::encode(CA::Render::Encoder*) const + 248 2 QuartzCore 0x136f40 CA::Render::GradientLayer::encode(CA::Render::Encoder*) const + 44 3 QuartzCore 0x2e384 CA::Render::Layer::encode(CA::Render::Encoder*) const + 284 4 QuartzCore 0x2e224 CA::Render::encode_set_object(CA::Render::Encoder*, unsigned long, unsigned int, CA::Render::Object*, unsigned int) + 196 5 QuartzCore 0x2b654 invocation function for block in CA::Context::commit_transaction(CA::Transaction*, double, double*) + 244 6 QuartzCore 0x2b4fc CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 368 7 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 8 QuartzCore 0x2b4bc CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 304 9 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 10 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 11 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 12 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 13 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 14 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 15 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 16 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 17 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 18 QuartzCore 0x2b488 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 19 QuartzCore 0x6fc60 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 11192 20 QuartzCore 0x66574 CA::Transaction::commit() + 648 21 UIKitCore 0x31b5ec __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 36 22 CoreFoundation 0x373a8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 23 CoreFoundation 0x35b9c __CFRunLoopDoBlocks + 356 24 CoreFoundation 0x33a9c __CFRunLoopRun + 848 25 CoreFoundation 0x33668 CFRunLoopRunSpecific + 608 26 GraphicsServices 0x35ec GSEventRunModal + 164 27 UIKitCore 0x22c2b4 -[UIApplication _run] + 888 28 UIKitCore 0x22b8f0 UIApplicationMain + 340 29 Coach 0x799d8 main + 14 (main.m:14) 30 ??? 0x1abefadcc (Missing)
11
8
2.5k
Feb ’24
SwiftUI Sheet Animation Issue with Non-Default Background Colors
I'm working on a SwiftUI project where I use a .sheet modifier to present a bottom drawer with two detent sizes: .medium and .large. The drawer contains a button that toggles its size between these two states. This part works as expected. However, I'm facing an animation issue when I set a non-default background color to the sheet. Here's the simplified code for context: struct ContentView: View { @State private var selectedDetent: PresentationDetent = .medium var body: some View { VStack {} .sheet(isPresented: .constant(true)) { Button("Press Me") { selectedDetent = selectedDetent == .medium ? .large : .medium } .presentationBackground(.gray) .presentationDetents([.medium, .large], selection: $selectedDetent) } } } The issue arises when I try to set a background color using .presentationBackground(.gray) (or any color, even white). Instead of the expected behavior when pressing the button (where the upper part of the sheet closes, and the bottom part stays attached to the screen bottom), the sheet momentarily turns into a square in the middle of the screen before moving down to the .medium position. As soon as I remove the.presentationBackground(.gray) line, it works as expected: I tried several approaches, such as: Using a custom background view. Explicitly specifying animations. Adjusting view hierarchy and layering. Unfortunately, none of these solutions worked. The issue persists with any color. It seems like a bug or limitation in SwiftUI's handling of sheet animations with custom backgrounds. Has anyone else encountered this issue, or does anyone have a workaround or solution?
1
0
1.2k
Dec ’23
Display jitter with "ProMotion"
Our DJ application Mixxx renders scrolling waveforms with 60 Hz. This looks perfectly smooth on an older 2015 MacBook Pro. However it looks jittery on a new M1 device with "ProMotion" enabled. Selecting 60 Hz fixes the issue. We are looking for a way to tell macOS that it can expect 60 Hz renderings from Mixxx and must not display them early (at 120 Hz) even if the pictures are ready. The alternative would be to read out the display settings and ask the user to select 60 Hz. Is there an API to: hint the display diver that we render with 60 Hz read out the refresh rate settings?
0
1
524
Dec ’23
SwiftUI ForEach Animation inside border
I'm having issues animating views inside a ForEach list that's inside a border. Here's my code: struct ContentView: View { @State var showNewMethodOptions = false var body: some View { VStack { Button { showNewMethodOptions.toggle() } label: { HStack { Image(systemName: showNewMethodOptions ? "chevron.up" : "plus") .resizable() .scaledToFit() .frame(width: 32) .foregroundColor(.blue) Text("Add new payment method") .foregroundColor(.gray) .padding(.leading, 6) Spacer() } .padding(.horizontal) .padding(.top, 20) .padding(.bottom, showNewMethodOptions ? 10 : 20) } if showNewMethodOptions { ForEach(PaymentMethodType.allCases) { method in NavigationLink { } label: { ZStack(alignment: .center) { RoundedRectangle(cornerRadius: 5) .stroke(.blue) Text(method.rawValue) .font(.title3) .foregroundColor(.gray) } .frame(height: 45.0) .background() .padding(.horizontal) .padding(.vertical, 5) .transition(.slide) } } } } .animation(.spring, value: showNewMethodOptions) .padding(.bottom, showNewMethodOptions ? 16 : 0) .padding(.horizontal) .overlay( RoundedRectangle(cornerRadius: 4) .stroke(.gray, lineWidth: 1) .padding(.vertical, 4) .padding(.horizontal) ) } } enum PaymentMethodType: String, CaseIterable, Identifiable { var id: Self { return self } case checking = "Checking" case savings = "Savings" case creditOrDebitCard = "Card" } When the animation happens, the "add a new payment method" HStack animates nicely enough, but the payment method options fade in while it's still sliding up, which doesn't look great because it looks like everything's on top of each other. The options also don't seem to follow the transition animation I apply to them - it's always just a fade. Is there a way to get these elements to animate together?
1
0
884
Nov ’23
How to animate arbitrary changes to a SwiftUI Path?
In UIKit/Core Animation, I can create a CABasicAnimation that lets me animate changes to the Path in a CAShapeLayer. As long as the new path has the same number of control points as the previous path, Core Animation creates a smooth animation of the changes. It's also possible to animate things like the start and end of the stroke, but I'm talking about arbitrary changes to the path. In SwiftUI, it's pretty easy to animate the stroke so that it looks like it's being drawn by a pen. I'm not talking about that. Say I have a closed path with N vertexes and some of the vertexes are connected with straight lines, while others are connected by quadratic or cubic Bézier curves. I want to move the control points around in arbitrary ways, and change the control points of the Bézier curves. I have a simple Storyboard based project on Github that creates closed N-sided polygons with either rounded or sharp corners, it manages an array of PolygonPoint structs that look like this: public struct PolygonPoint { let point: CGPoint let isRounded: Bool let customCornerRadius: CGFloat? init(point: CGPoint, isRounded: Bool, customCornerRadius: CGFloat? = nil) { self.point = point self.isRounded = isRounded self.customCornerRadius = customCornerRadius } init(previousPoint: PolygonPoint, isRounded: Bool) { self.init(point: previousPoint.point, isRounded: isRounded, customCornerRadius: previousPoint.customCornerRadius) } } The sample app builds a square out of an array of PolygonPoints, and then presents 4 swtiches that controls whether each vertex is rounded or not. It builds a polygon using the CGPath addArc(tangent1End:tangent2End:radius:transform:) function, with a 0 radius for sharp corners and a non-zero corner radius for rounded corners. It wraps changes to the path in a CABasicAnimation, and the result is a simple animation. The project can be found on Github here: RoundedConerPolygon project As a learning exercise, I'd like to convert this project to SwiftUI. The Swift/UIKit project creates CGPaths, and there is an initializer for the Swift Path object that takes a CGPath, so that part is easy. However, SwiftUI wants to observe changes to a simple scalar, or to some sort of animatableData. I've tried to make my PolygonPoint struct conform to VectorArithmetic, but no joy. My attempt is here: RoundedCornerPolygonSwiftUI This seems like it should be easy, but I can't figure out how to make it work. Is there a way to have SwiftUI animate changes to a Path's underlying CGPath like you can in UIKit? I could probably wrap a UIKIt custom view in SwiftUI and do it that way, but I'm trying to learn how to do it "The SwifTUI way."
0
0
661
Oct ’23
How do I work around a Mac Catalyst framework bug where no Core Animation output is shown in an export session?
This is verified to be a framework bug (occurs on Mac Catalyst but not iOS or iPadOS), and it seems the culprit is AVVideoCompositionCoreAnimationTool? /// Exports a video with the target animating. func exportVideo() { let destinationURL = createExportFileURL(from: Date()) guard let videoURL = Bundle.main.url(forResource: "black_video", withExtension: "mp4") else { delegate?.exporterDidFailExporting(exporter: self) print("Can't find video") return } // Initialize the video asset let asset = AVURLAsset(url: videoURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true]) guard let assetVideoTrack: AVAssetTrack = asset.tracks(withMediaType: AVMediaType.video).first, let assetAudioTrack: AVAssetTrack = asset.tracks(withMediaType: AVMediaType.audio).first else { return } let composition = AVMutableComposition() guard let videoCompTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)), let audioCompTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { return } videoCompTrack.preferredTransform = assetVideoTrack.preferredTransform // Get the duration let videoDuration = asset.duration.seconds // Get the video rect let videoSize = assetVideoTrack.naturalSize.applying(assetVideoTrack.preferredTransform) let videoRect = CGRect(origin: .zero, size: videoSize) // Initialize the target layers and animations animationLayers = TargetView.initTargetViewAndAnimations(atPoint: CGPoint(x: videoRect.midX, y: videoRect.midY), atSecondsIntoVideo: 2, videoRect: videoRect) // Set the playback speed let duration = CMTime(seconds: videoDuration, preferredTimescale: CMTimeScale(600)) let appliedRange = CMTimeRange(start: .zero, end: duration) videoCompTrack.scaleTimeRange(appliedRange, toDuration: duration) audioCompTrack.scaleTimeRange(appliedRange, toDuration: duration) // Create the video layer. let videolayer = CALayer() videolayer.frame = CGRect(origin: .zero, size: videoSize) // Create the parent layer. let parentlayer = CALayer() parentlayer.frame = CGRect(origin: .zero, size: videoSize) parentlayer.addSublayer(videolayer) let times = timesForEvent(startTime: 0.1, endTime: duration.seconds - 0.01) let timeRangeForCurrentSlice = times.timeRange // Insert the relevant video track segment do { try videoCompTrack.insertTimeRange(timeRangeForCurrentSlice, of: assetVideoTrack, at: .zero) try audioCompTrack.insertTimeRange(timeRangeForCurrentSlice, of: assetAudioTrack, at: .zero) } catch let compError { print("TrimVideo: error during composition: \(compError)") delegate?.exporterDidFailExporting(exporter: self) return } // Add all the non-nil animation layers to be exported. for layer in animationLayers.compactMap({ $0 }) { parentlayer.addSublayer(layer) } // Configure the layer composition. let layerComposition = AVMutableVideoComposition() layerComposition.frameDuration = CMTimeMake(value: 1, timescale: 30) layerComposition.renderSize = videoSize layerComposition.animationTool = AVVideoCompositionCoreAnimationTool( postProcessingAsVideoLayer: videolayer, in: parentlayer) let instructions = initVideoCompositionInstructions( videoCompositionTrack: videoCompTrack, assetVideoTrack: assetVideoTrack) layerComposition.instructions = instructions // Creates the export session and exports the video asynchronously. guard let exportSession = initExportSession( composition: composition, destinationURL: destinationURL, layerComposition: layerComposition) else { delegate?.exporterDidFailExporting(exporter: self) return } // Execute the exporting exportSession.exportAsynchronously(completionHandler: { if let error = exportSession.error { print("Export error: \(error), \(error.localizedDescription)") } self.delegate?.exporterDidFinishExporting(exporter: self, with: destinationURL) }) } Not sure how to implement a custom compositor that performs the same animations as this reproducible case: class AnimationCreator: NSObject { // MARK: - Target Animations /// Creates the target animations. static func addAnimationsToTargetView(_ targetView: TargetView, startTime: Double) { // Add the appearance animation AnimationCreator.addAppearanceAnimation(on: targetView, defaultBeginTime: AVCoreAnimationBeginTimeAtZero, startTime: startTime) // Add the pulse animation. AnimationCreator.addTargetPulseAnimation(on: targetView, defaultBeginTime: AVCoreAnimationBeginTimeAtZero, startTime: startTime) } /// Adds the appearance animation to the target private static func addAppearanceAnimation(on targetView: TargetView, defaultBeginTime: Double = 0, startTime: Double = 0) { // Starts the target transparent and then turns it opaque at the specified time targetView.targetImageView.layer.opacity = 0 let appear = CABasicAnimation(keyPath: "opacity") appear.duration = .greatestFiniteMagnitude // stay on screen forever appear.fromValue = 1.0 // Opaque appear.toValue = 1.0 // Opaque appear.beginTime = defaultBeginTime + startTime targetView.targetImageView.layer.add(appear, forKey: "appear") } /// Adds a pulsing animation to the target. private static func addTargetPulseAnimation(on targetView: TargetView, defaultBeginTime: Double = 0, startTime: Double = 0) { let targetPulse = CABasicAnimation(keyPath: "transform.scale") targetPulse.fromValue = 1 // Regular size targetPulse.toValue = 1.1 // Slightly larger size targetPulse.duration = 0.4 targetPulse.beginTime = defaultBeginTime + startTime targetPulse.autoreverses = true targetPulse.repeatCount = .greatestFiniteMagnitude targetView.targetImageView.layer.add(targetPulse, forKey: "pulse_animation") } }
1
0
672
Oct ’23
CATextLayer not updating foreground color property on appearance change
I have an issue with my macOS objC app that uses CATextLayer instances that adapt to the app appearance (dark, light). I had no problem with Ventura, so I suppose this is a Sonoma bug. But maybe I'm not doing the right things. Within -updateLayer , I call stringLayer.foregroundColor = NSColor.textColor.CGColor. (stringLayer is an instance of CATextLayer.) NSColor.textColor should adapt to the app appearance. But the color doesn't always change when the app appearance changes. So the text would turn black in dark mode (hence illegible) and white in light mode when I toggle the mode in the system preferences. To investigate wether the issues was specific to the system text color, I tried (again, within -updateLayer): NSColor *color = [NSApp.effectiveAppearance.name isEqualToString:NSAppearanceNameDarkAqua]? NSColor.redColor : NSColor.greenColor; stringLayer.foregroundColor = color.CGColor; I basically get the same issue. The correct color shows when the app launches, but doesn't change the first time I toggle the mode (dark/light). So the wrong color associates with the app appearance (red with light mode and green with dark mode). The code below works : NSColor *color = [NSApp.effectiveAppearance.name isEqualToString:NSAppearanceNameDarkAqua]? NSColor.redColor : NSColor.greenColor; NSDictionary *dic = @{NSFontAttributeName: [NSFont labelFontOfSize:10.0], NSForegroundColorAttributeName:color}; NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"test" attributes: dic]; stringLayer.string = string; But the code below doesn't. The layer text color doesn't change when the app appearance changes. NSDictionary *dic = @{NSFontAttributeName: [NSFont labelFontOfSize:10.0], NSForegroundColorAttributeName:NSColor.textColor}; NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"test" attributes: dic]; stringLayer.string = string; Note that the issue appears to be specific to the foreground color. The background color (which I update in the same method) is always set properly.
0
0
603
Oct ’23
Performance issues when resizing MapView
I’m trying to achieve vertical split view in SwiftUI. There are two views, top one is Map (MKMapView actually, wrapped with UIViewRepresentable) and bottom one for this example could be Color.red. Between them there’s a handle to resize the proportions. Initial proportions are 0.3 of height for bottom, 0.7 for map. When resizing map frame, it feels choppy and slow. Replacing MapView with any other view does not produce the same issue. Issue appears only on my real device (iPhone 11 Pro Max) simulator works fine.
0
0
700
Sep ’23
App Crashes On Launch in some iphone(iOS 17)
My app keeps getting crashed for the same reason in some iphone(iOS 17) and I need help. Here is the lastExceptionBacktrace. "lastExceptionBacktrace" : [ {"imageOffset":972256,"symbol":"__exceptionPreprocess","symbolLocation":164,"imageIndex":10}, {"imageOffset":179200,"symbol":"objc_exception_throw","symbolLocation":60,"imageIndex":7}, {"imageOffset":1516452,"symbol":"-[NSException initWithCoder:]","symbolLocation":0,"imageIndex":10}, {"imageOffset":195548,"symbol":"CA::Layer::set_position(CA::Vec2 const&, bool)","symbolLocation":168,"imageIndex":19}, {"imageOffset":195340,"symbol":"-[CALayer setPosition:]","symbolLocation":52,"imageIndex":19}, {"imageOffset":195204,"symbol":"-[CALayer setFrame:]","symbolLocation":396,"imageIndex":19}, {"imageOffset":409656,"symbol":"__26-[_UILabelLayer setFrame:]_block_invoke","symbolLocation":56,"imageIndex":12}, {"imageOffset":409388,"symbol":"-[_UILabelLayer _setFrameOrBounds:settingAction:]","symbolLocation":60,"imageIndex":12}, {"imageOffset":426392,"symbol":"-[_UILabelLayer setFrame:]","symbolLocation":104,"imageIndex":12}, {"imageOffset":104744,"symbol":"-[UIView _backing_setFrame:]","symbolLocation":240,"imageIndex":12}, {"imageOffset":97808,"symbol":"-[UIView(Geometry) setFrame:]","symbolLocation":296,"imageIndex":12}, {"imageOffset":106944,"symbol":"-[UILabel setFrame:]","symbolLocation":112,"imageIndex":12}, {"imageOffset":16705216,"symbol":"-[UITableViewHeaderFooterView layoutSubviews]","symbolLocation":220,"imageIndex":12}, {"imageOffset":209368,"symbol":"-[UIView(CALayerDelegate) layoutSublayersOfLayer:]","symbolLocation":1528,"imageIndex":12}, {"imageOffset":424072,"symbol":"CA::Layer::layout_if_needed(CA::Transaction*)","symbolLocation":500,"imageIndex":19}, {"imageOffset":221860,"symbol":"-[UIView(Hierarchy) layoutBelowIfNeeded]","symbolLocation":308,"imageIndex":12}, {"imageOffset":16700796,"symbol":"-[UITableViewHeaderFooterView _sizeThatFits:stripPaddingForAbuttingView:isTopHeader:]","symbolLocation":192,"imageIndex":12}, {"imageOffset":16733416,"symbol":"-[UISectionRowData _headerFooterSizeForSection:inTable:withTitle:detailText:isHeader:stripPaddingForAbuttingView:isTopHeader:]","symbolLocation":680,"imageIndex":12}, {"imageOffset":2595124,"symbol":"-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]","symbolLocation":464,"imageIndex":12}, {"imageOffset":2604748,"symbol":"-[UITableViewRowData rectForFooterInSection:heightCanBeGuessed:]","symbolLocation":104,"imageIndex":12}, {"imageOffset":2604572,"symbol":"-[UITableViewRowData heightForTable]","symbolLocation":52,"imageIndex":12}, {"imageOffset":2599644,"symbol":"-[UITableView _updateContentSizeSkippingContentOffsetAdjustment:]","symbolLocation":168,"imageIndex":12}, {"imageOffset":16599748,"symbol":"-[UITableView _rebuildGeometryForcingRowDataUpdate:skipContentOffsetAdjustment:updateImmediatelyIfPossible:]","symbolLocation":140,"imageIndex":12}, {"imageOffset":16595412,"symbol":"-[UITableView setLayoutMargins:]","symbolLocation":204,"imageIndex":12}, {"imageOffset":16595180,"symbol":"-[UITableView _setDefaultLayoutMargins:]","symbolLocation":52,"imageIndex":12}, {"imageOffset":16595032,"symbol":"-[UITableView didMoveToWindow]","symbolLocation":288,"imageIndex":12}, {"imageOffset":74184,"symbol":"-[UIView(Internal) _didMoveFromWindow:toWindow:]","symbolLocation":1716,"imageIndex":12}, {"imageOffset":1969584,"symbol":"-[UIScrollView _didMoveFromWindow:toWindow:]","symbolLocation":88,"imageIndex":12}, {"imageOffset":73152,"symbol":"-[UIView(Internal) _didMoveFromWindow:toWindow:]","symbolLocation":684,"imageIndex":12}, {"imageOffset":71756,"symbol":"__45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke","symbolLocation":124,"imageIndex":12}, {"imageOffset":71520,"symbol":"-[UIView _postMovedFromSuperview:]","symbolLocation":484,"imageIndex":12}, {"imageOffset":66468,"symbol":"-[UIView(Internal) _addSubview:positioned:relativeTo:]","symbolLocation":2180,"imageIndex":12}, {"imageOffset":555240,"symbol":"-[UIWindow addRootViewControllerViewIfPossible]","symbolLocation":728,"imageIndex":12}, {"imageOffset":1651088,"symbol":"-[UIWindow setRootViewController:]","symbolLocation":364,"imageIndex":12}, {"imageOffset":27056,"imageIndex":2}, {"imageOffset":26016,"imageIndex":2}, {"imageOffset":2179544,"symbol":"-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:]","symbolLocation":320,"imageIndex":12}, ...... {"imageOffset":2433472,"symbol":"-[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:]","symbolLocation":288,"imageIndex":12}, {"imageOffset":60072,"symbol":"-[FBSScene _callOutQueue_didCreateWithTransitionContext:completion:]","symbolLocation":324,"imageIndex":9}, {"imageOffset":59716,"symbol":"__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke.108","symbolLocation":280,"imageIndex":9}, {"imageOffset":54696,"symbol":"-[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]","symbolLocation":168,"imageIndex":9}, {"imageOffset":103264,"symbol":"__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke","symbolLocation":352,"imageIndex":9}, {"imageOffset":17152,"symbol":"_dispatch_client_callout","symbolLocation":20,"imageIndex":8}, {"imageOffset":32072,"symbol":"_dispatch_block_invoke_direct","symbolLocation":284,"imageIndex":8}, {"imageOffset":39404,"symbol":"FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK","symbolLocation":52,"imageIndex":9}, {"imageOffset":39276,"symbol":"-[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible]","symbolLocation":240,"imageIndex":9}, {"imageOffset":38980,"symbol":"-[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource]","symbolLocation":28,"imageIndex":9}, {"imageOffset":228044,"symbol":"CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION","symbolLocation":28,"imageIndex":10}, {"imageOffset":224584,"symbol":"__CFRunLoopDoSource0","symbolLocation":176,"imageIndex":10}, {"imageOffset":218460,"symbol":"__CFRunLoopDoSources0","symbolLocation":340,"imageIndex":10}, {"imageOffset":213560,"symbol":"__CFRunLoopRun","symbolLocation":828,"imageIndex":10}, {"imageOffset":212504,"symbol":"CFRunLoopRunSpecific","symbolLocation":608,"imageIndex":10}, {"imageOffset":13804,"symbol":"GSEventRunModal","symbolLocation":164,"imageIndex":11}, {"imageOffset":2290512,"symbol":"-[UIApplication _run]","symbolLocation":888,"imageIndex":12}, {"imageOffset":2288012,"symbol":"UIApplicationMain","symbolLocation":340,"imageIndex":12}, {"imageOffset":24608,"imageIndex":2}, {"imageOffset":23876,"symbol":"start","symbolLocation":2104,"imageIndex":13} ],
6
0
1.9k
Oct ’23
Different methods of animating shape along custom path?
I'm trying to animate a shape (e.g. a circle) to follow a custom path, and struggling to find the best way of doing this. I've had a look at the animation options from SwiftUI, UIKit and SpriteKit and all seem very limited in what paths you can provide. Given the complexity of my path, I was hoping there'd be a way of providing a set of coordinates in some input file and have the shape follow that, but maybe that's too ambitious. I was wondering if this were even possible, and assuming not, if there were other options I could consider.
1
0
897
Jan ’24
SwiftUI Chart Text Animation Glitch with AxisMarks and AxisLabels
I've encountered an animation glitch affecting the text for AxisMarks and AxisLabels in the SwiftUI Chart framework. Below are the sample project code and animated gif for reference: (I'm not being able to attach the gif for some reason. Here's my StackOverflow post with a the gift: https://stackoverflow.com/questions/77007744/swiftui-chart-text-animation-glitch-with-axismarks-and-axislabels) struct ContentView: View { @State var isDisplayingAge = true var body: some View { ChartView(data: ChartDataSample, isDisplayingAge: isDisplayingAge) .onTapGesture { withAnimation { isDisplayingAge.toggle() } } } } struct ChartData: Identifiable { let age: Int let presence: Int let grade: Int let id = UUID() } struct ChartView: View { let data: [ChartData] let isDisplayingAge: Bool let xAxis = [0, 50, 100] var body: some View { VStack { Chart { ForEach(data) { chartData in BarMark(x: .value("X Axis", isDisplayingAge ? chartData.age : chartData.presence), y: .value("Y Axis", chartData.grade)) } } .chartXAxis(content: { AxisMarks(position: .bottom, values: xAxis.map{$0}) { data in AxisValueLabel(String(xAxis[data.index]) + (isDisplayingAge ? " years" : " days")) } }) .chartXAxisLabel(content: { Text(isDisplayingAge ? "Data: age" : "Data: presence") }) } .padding(.horizontal, 13) } } As you can observe, when I tap the chart to trigger a content change with animation, the text for AxisMarks (e.g., x years / x days) and AxisLabels (e.g., Data: age / Data: presence) animates unusually. A portion of the text is temporarily replaced by an ellipsis ("...") during the animation. Interestingly, this issue occurs only in one direction of the animation. When transitioning from "year" to "day" or from "presence" to "age," the text simply gets replaced without any noticeable animation. Can anyone explain what's happening here? Ideally, I'd like the texts to either fade into each other or be replaced without any animation. Thank you.
1
0
915
Aug ’23
How to generate video with animation using swift
Wrote a transition code for some images. It can show image one by one. But I want to create a video with this kind of animations (Zoom in, Zoom out etc). How can I achieve this. UIView.transition(with: self.imageView, duration: 2.0, options: .transitionCrossDissolve, animations: { self.imageView.image = UIImage(imageLiteralResourceName: "image2") }, completion: nil)
0
0
643
Aug ’23
CADisplayLink and UITouch events
Hi. I'm currently working on a project, where I try to achieve the best possible UX when rendering an interactive scene using custom Metal renderer. The problem I'm facing right now is that from what I've observed, the timing of how touch events (in touchesBegan/Moved/Ended/Cancelled) arrive with regards to DisplayLink callbacks is different on different devices using latest stable iOS. Disregarding special cases (fast touches movement causing two touchesMoved along with a single touchedEnded arriving during a frame interval and having awkward timing), the general picture is this: on 14 Pro: vsync - (8 ms of nothing) - touches - vsync on 11 Pro Max: vsync - touches - (16 ms of nothing) - vsync In order to minimize input-to-presentation latency and fit CPU + GPU work into one frame, I'd like to schedule drawing right when CADisplayLink callback arrives. The problem is that at this point on 11 Pro Max I have no knowledge about whether touches arrive or not, so the best we could do is to process those touches and schedule redraw on next vsync, which causes almost two frames latency between input and draw that reflects changes caused by this input (33 ms) On 14 Pro, touches are dispatched just before next vsync, so the actual latency is just one 120hz frame (8ms). What are possible workarounds to achieve the same UX on iPhone 11 Pro Max?
0
1
636
Aug ’23
Change MapKit region update animation duration on macOS
I'm writing a multiplatform app that uses MapKit with custom tiles via MKTileOverlay. The map should have buttons for zooming in and out. Those buttons set the region of the MKMapView with animation parameter. I want to make this animation faster. While good for generic change of a region, it feels too slow when changing the region for the zooming purposes. In general, I'm working with SwiftUI. But because MKTileOverlay is not available there, the MKMapView is being accessed via the UIViewRepresentable and NSViewRepresentable respectively. On iOS, to make animation faster (reduce animation time), I'm using UIView.animate(withDuration: 0.2) { mapView.setRegion(region, animated: true) } and it achieves the goal. On macOS, I tried: NSAnimationContext.runAnimationGroup { context in context.duration = 0.2 mapView.setRegion(region, animated: true) } and: CATransaction.begin() CATransaction.setAnimationDuration(0.2) mapView.setRegion(region, animated: true) CATransaction.commit() but without success. The default animation duration is not overridden. I appreciate any input you could give me. Alexey
0
0
762
Aug ’23