Instructions
Instructions copied to clipboard
Cant handle frame changes for the current coachmark
Describe the bug
I have a coachmark on top of the keyboard, so I want to change the coachmark position based on the keyboard size. The issue is that the readme says that we should use the CoachMarkController.prepareForChange() and CoachMarkController.restoreAfterChangeDidComplete(), but those functions don't do anything on iOS 13 or later.
I found a possible workaround, which is to run flow.pause()
. helper.updateCurrentCoachMark()
, flow.resume()
, but the resume function creates a new coachmark in the screen, so every frame change a new coachmark appears, and keeps the old ones visible.
To Reproduce
- Create coachmark using some view that will change the frame
- Call the
prepareForChange
function before changing the frame - Update the highlight view frame
- Call
restoreAfterChangeDidComplete
function
Expected behavior
The coachmark should move to the new frame position.
Screenshots
The result of the workaround usage.
Environment
- Device: iPhone 13 Pro
- iOS version: 16.3.1
- Instructions version: 2.2.0
- Dependency Manager: SPM
Hey @diegodossantos95, thanks for reporting the issue! I think the README hasn't been updated, let me have a look.
@ephread What is the right approach to update the Coachmark?
@diegodossantos95 your current approach sounds correct, but I need to know more about your flow.
- When is the keyboard displayed? Does it appear in between two coach marks?
- When do you call
flow.pause()
, is it inwillShow
?
@ephread , the keyboard is always visible because the coach mark appears on the keyboard's toolbar. The keyboard's size changes when the user changes the keyboard layout, and I listen to this event to update the coachmark's highlight frame.
I call the flow.pause()
in the listener of keyboardDidShowNotification
and keyboardDidHideNotification
@diegodossantos95 alright, thanks for the clarification, IIRC flow.pause()
has undocumented limitations, can you try calling it in willShow
instead?
@ephread do you mean keyboardWillShowNotification
? I tried and I got the same result: multiple coachmarks.
@diegodossantos95 I meant in the delegate's method (see here and there). Sorry, I should I been clearer.
I tried, but it crashed because of simultaneous access of FlowManager.currentCoachMark
on L221 FlowManager.coachMarksViewController.show(coachMark: ¤tCoachMark!, at: currentIndex)
.
Simultaneous accesses to 0x600001496da0, but modification requires exclusive access. Previous access (a modification) started at Project
FlowManager.currentCoachMark.modify + 41 (0x10c2c6419).
Current access (a modification) started at:
0 libswiftCore.dylib 0x00007ff80d9fc540 swift::runtime::AccessSet::insert(swift::runtime::Access*, void*, void*, swift::ExclusivityFlags) + 442
1 libswiftCore.dylib 0x00007ff80d9fc7a0 swift_beginAccess + 66
2 Project 0x000000010c2c63f0 FlowManager.currentCoachMark.modify + 41
3 Project 0x000000010c2c8850 FlowManager.createAndShowCoachMark(afterResuming:changing:) + 2103
4 Project 0x000000010c2c9900 closure #1 in FlowManager.resume() + 65
5 Project 0x000000010c2c9420 FlowManager.resume() + 1211
6 Project 0x000000010ba92bd0 InstructionCoachMarkComponent.coachMarksController(:willShow:beforeChanging:at:) + 164
7 Project 0x000000010ba92cc0 protocol witness for CoachMarksControllerDelegate.coachMarksController(:willShow:beforeChanging:at:) in conformance InstructionCoachMarkComponent + 14
8 Project 0x000000010c297d30 CoachMarksController.willShow(coachMark:beforeChanging:at:) + 224
9 Project 0x000000010c2983c0 protocol witness for CoachMarksControllerProxyDelegate.willShow(coachMark:beforeChanging:at:) in conformance CoachMarksController + 15
10 Project 0x000000010c2c8850 FlowManager.createAndShowCoachMark(afterResuming:changing:) + 1255
11 Project 0x000000010c2c7920 FlowManager.showNextCoachMark(hidePrevious:) + 661
12 Project 0x000000010c2c6c20 closure #1 in FlowManager.startFlow(withNumberOfCoachMarks:) + 45
13 Project 0x000000010c28ef30 closure #1 in CoachMarksViewController.prepareToShowCoachMarks(:) + 646
14 Project 0x000000010c2c11b0 closure #2 in TranslucentOverlayStyleManager.showOverlay(:withDuration:completion:) + 1002
15 Project 0x000000010ba56cd0 thunk for @escaping @callee_guaranteed (@unowned Bool) -> () + 52
16 UIKitCore 0x000000012233da36 UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK + 15
17 UIKitCore 0x000000012233da47 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 797
18 UIKitCore 0x000000012230d920 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 190
19 UIKitCore 0x000000012230def2 -[UIViewAnimationState animationDidStop:finished:] + 263
20 UIKit 0x0000000127b5e0dd -[UIViewAnimationStateAccessibility animationDidStop:finished:] + 195
21 QuartzCore 0x00007ff808948634 CA::Layer::run_animation_callbacks(void*) + 318
22 libdispatch.dylib 0x000000010b95cf53 _dispatch_client_callout + 8
23 libdispatch.dylib 0x000000010b96d79e _dispatch_main_queue_drain + 1463
24 libdispatch.dylib 0x000000010b96d771 _dispatch_main_queue_callback_4CF + 31
25 CoreFoundation 0x00007ff800386b66 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 9
26 CoreFoundation 0x00007ff800380ad4 __CFRunLoopRun + 2482
27 CoreFoundation 0x00007ff8003804c7 CFRunLoopRunSpecific + 560
28 GraphicsServices 0x00007ff809c5c1ff GSEventRunModal + 139
29 UIKitCore 0x0000000121d1c249 -[UIApplication _run] + 994
30 UIKitCore 0x0000000121d214cc UIApplicationMain + 123`