[ad_1]
I am implementing the brand new iOS 17 TipKit to indicate some tip popovers the primary time a consumer performs the sport I am growing proper now, understanding that these suggestions will solely present for customers who’ve upgraded to iOS 17.
Since my app makes use of UIKit, I’ve realized most of TipKit’s UIKit implementation from Ben Dodson’s article and I’ve up to date my code primarily based on Apple’s documentation on TipUIPopoverViewController as in any other case I’d have been left with a reminiscence leak that Apple’s code resolved.
In my essential ViewController
I wish to present the primary tip popover after which when that one will get dismissed present the second tip popover on one other sourceItem
.
If the consumer dismisses the popover by clicking the X within the nook then every thing works accurately and the second popover exhibits up. But when the consumer clicks outdoors of the popover, it can additionally dismiss, however that is not caught by my code so the 2nd tip will not present up.
So the query is, the best way to detect that the tip was dismissed when it was clicked outdoors of the popover?
With TipKit, plenty of the work is completed for you so there’s little code for creating that TipUIPopoverViewController
itself.
Here is the code I’ve and the way I attempted to unravel this challenge.
First I created 2 structs, one for every Tip, the first one is known as PauseTip
and the 2nd one is FreezeTip
. In FreezeTip
I set a rule with a boolean referred to as pauseTipDisplayed
in order that that 2nd tip will solely present if that boolean is true.
This rule is ready up contained in the 2nd struct as follows:
struct FreezeTip: Tip {
@out there(iOS 17.0, *)
@Parameter
static var pauseTipDisplayed: Bool = false
@out there(iOS 17.0, *)
var guidelines: [Rule] {
#Rule(Self.$pauseTipDisplayed) { $0 == true }
}
[...]
}
So now all I must do is ready pauseTipDisplayed
to true when the primary tip was dismissed and this 2nd tip will present up.
In my ViewController
I added the next properties:
personal var pauseTip = PauseTip()
personal var pauseTipObservationTask: Job<Void, By no means>?
personal weak var pauseTipPopoverController: UIViewController?
personal var freezeTip = FreezeTip()
personal var freezeTipObservationTask: Job<Void, By no means>?
personal weak var freezeTipPopoverController: UIViewController?
Then I wrote 2 capabilities to deal with every tip popover and I am calling them the place wanted (I did not put them in viewDidAppear
as proven within the 2 examples I realized from as a result of that will have been too early for my wants).
Here is the first perform:
@out there(iOS 17.0, *)
func handlePauseTip() {
pauseTipObservationTask = pauseTipObservationTask ?? Job { @MainActor in
for await shouldDisplay in pauseTip.shouldDisplayUpdates {
if shouldDisplay {
let pauseTipContoller = TipUIPopoverViewController(pauseTip, sourceItem: pauseButton)
pauseTipContoller.popoverPresentationController?.backgroundColor = .purple
DispatchQueue.essential.asyncAfter(deadline: .now() + 1) {
self.current(pauseTipContoller, animated: true)
}
pauseTipPopoverController = pauseTipContoller
} else {
if presentedViewController is TipUIPopoverViewController {
dismiss(animated: true)
pauseTipPopoverController = nil
FreezeMazeTip.pauseTipDisplayed = true // This can have an effect on the rule to indicate the 2nd tip popover
}
}
}
}
}
You may see that the final row within the else
assertion is altering the boolean flag to permit displaying the 2nd tip popover.
The perform for the 2nd tip is similar simply utilizing totally different names, aside from setting the boolean flag so I will not copy it once more.
As I wrote above, all of this works advantageous if the consumer dismisses the primary tip by clicking on the X on prime of the popover.
But when the consumer clicks outdoors the popover and that popover closes, the 2nd tip by no means exhibits up.
Listed below are a number of issues I attempted to resolve this challenge:
- I attempted checking
isBeingDismissed
. I added this examine within theelse
clause on the finish of the perform in order that half would then seem like this:
} else {
if pauseTipPopoverController != nil {
if pauseTipPopoverController!.isBeingDismissed {
FreezeTip.pauseTipDisplayed = true // This can have an effect on the rule to indicate the 2nd tip popover
}
}
if presentedViewController is TipUIPopoverViewController {
dismiss(animated: true)
pauseTipPopoverController = nil
FreezeTip.pauseTipDisplayed = true // This can have an effect on the rule to indicate the 2nd tip popover
}
}
However that did not assist. Checking with the debugger I discovered that when the consumer dismisses by clicking outdoors the popover, this else
assertion isn’t even reached.
Ought to I put this examine elsewhere in my code?
- I attempted utilizing the next delegate methodology:
presentationControllerDidDismiss
. For that to occur I made the next modifications.
I made myViewController
conform to the next:
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
...
Then in viewDidLoad
I set the next:
pauseTipPopoverController?.presentationController?.delegate = self
And I added the next methodology:
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
if #out there(iOS 17.0, *) {
if presentationController is UIPopoverPresentationController {
FreezeTip.pauseTipDisplayed = true
}
} else {
// Fallback on earlier variations - do nothing
}
}
Right here once more, that did not assist and it looks like this methodology isn’t referred to as when the consumer dismisses the popover by clicking outdoors of it.
Did I declare the delegate incorrectly?
I attempted many extra issues that I researched, however all of them gave me fixed errors.
I did implement a easy workaround for now. In handlePauseTip
I added the next line:
pauseTipContoller.isModalInPresentation = true
That may disable dismissing the popover when clicking outdoors of it and the one option to dismiss it’s to click on on the X. Doing so every thing works accurately and the 2nd popover exhibits up proper on time. However I believe it is a lesser consumer expertise as I would not wish to pressure the consumer to dismiss a technique solely.
So I do wish to catch it when the consumer clicks outdoors of the popup.
Any concepts can be very welcome. Thanks!
[ad_2]