Close button doesn't work in UIKit?

Hello!

I've tested/implemented TipKit in SwiftUI and UIKit but it seems that the close, i.e. X, button doesn't work in UIKit but does in SwiftUI. Not sure if this is a bug or I have to do something different about it in UIKit.

Testing with Xcode 15 Beta 8

Thanks!

Answered by haimian520 in 765807022

The tipView does not close itself when close button clicked but tells the tip by changing the value of 'shouldDisplayUpdates' property. You can observe this property to add or remove a tip.

For TipUIView, you do not need to directly add the subview after viewDidLoad, just insert the following code after viewDidLoad to observe the tip status.


private var tipObservationTask: Task<Void, Never>?

tipObservationTask = tipObservationTask ?? Task { @MainActor in
    for await shouldDisplay in catTracksFeatureTip.shouldDisplayUpdates {
        if shouldDisplay {
            // tells that a tip should display
            // add your TipUIView instance and add layout constraints
        } else {
             // tells that a tip should dismiss, e.g. the user clicked closed
            // remove your TipUIView instance

        }
    }
}

For TipUIPopoverViewController, try the same way by presenting and dismissing the TipUIPopoverViewController instance.

More reference please see https://developer.apple.com/documentation/tipkit/tipuipopoverviewcontroller

Facing the same issue. Any solutions?

Same issue.

When using TipKit with UIKit code, you have to manually remove the tip from the parent UIView. For instance, if you're using the inline tip style, you may have a line of code that does view.addSubview to add the TipUIView to the parent view. You need a corresponding removeFromSuperview, which removes the tip. If you share your code for presenting the tip, I might be able to pinpoint what's missing.

hello! thank you for your reply!

the implementation is very simple,

this is my tip object

    struct FavoriteCarTip: Tip {
        var title: Text {
            Text("Favorite This Car")
        }
        var message: Text? {
            Text("Favorite this car to receive status updates and more!")
        }
        var image: Image? {
            Image(systemName: "heart.fill")
        }
        
        var options: [TipOption] {
            [Tip.MaxDisplayCount(1)]
        }
    }

and this is how I'm presenting it

let tip = FavoriteCarTip()
let controller = TipUIPopoverViewController(tip, sourceItem: sourceView)
self.present(controller, animated: true) 

basically now the only way to remove the tip is by tapping outside of it, and while its not ideal it still works. I was wondering if there are any delegate calls or other ways to wire that close button? Thank you!

hello! thank you for your reply! the implementation is very simple, this is my tip object

    struct FavoriteCarTip: Tip {
        var title: Text {
            Text("Favorite This Car")
        }
        var message: Text? {
            Text("Favorite this car to receive status updates and more!")
        }
        var image: Image? {
            Image(systemName: "heart.fill")
        }
        
        var options: [TipOption] {
            [Tip.MaxDisplayCount(1)]
        }
    }

and this is how I'm presenting it

let tip = FavoriteCarTip()
let controller = TipUIPopoverViewController(tip, sourceItem: sourceView)
self.present(controller, animated: true) 

basically now the only way to remove the tip is by tapping outside of it, and while its not ideal it still works. I was wondering if there are any delegate calls or other ways to wire that close button?

Thank you!

I am having the same issue.

I am using UIKit and presenting it using TipUIPopoverViewController. My close button doesn't work either.

Accepted Answer

The tipView does not close itself when close button clicked but tells the tip by changing the value of 'shouldDisplayUpdates' property. You can observe this property to add or remove a tip.

For TipUIView, you do not need to directly add the subview after viewDidLoad, just insert the following code after viewDidLoad to observe the tip status.


private var tipObservationTask: Task<Void, Never>?

tipObservationTask = tipObservationTask ?? Task { @MainActor in
    for await shouldDisplay in catTracksFeatureTip.shouldDisplayUpdates {
        if shouldDisplay {
            // tells that a tip should display
            // add your TipUIView instance and add layout constraints
        } else {
             // tells that a tip should dismiss, e.g. the user clicked closed
            // remove your TipUIView instance

        }
    }
}

For TipUIPopoverViewController, try the same way by presenting and dismissing the TipUIPopoverViewController instance.

More reference please see https://developer.apple.com/documentation/tipkit/tipuipopoverviewcontroller

Yeah Tapping on the 'X' doesn't toggle the shouldDisplay variable for me. Its just a dead 'X'. My table cells behind the TipUIView are getting the touch events.

Adding a small UIView overlay in the corner with a UITapGestureRecognizer worked for me:

            let tipVC = TipUIPopoverViewController(
            tip,
            sourceItem: view,
            actionHandler: { action in
                actionHandler?(action.id)
            })

        // Create the UIView
        let tapView = UIView()
        tapView.translatesAutoresizingMaskIntoConstraints = false // Enable Auto Layout
        tapView.backgroundColor = .clear // Set background color if needed

        // Add the UITapGestureRecognizer
        let tapGesture = UITapGestureRecognizer(target: tipVC, action: #selector(dismissModal))
        tapView.addGestureRecognizer(tapGesture)

        // Add the view to the tipVC
        tipVC.view.addSubview(tapView)

        // Set up constraints
        NSLayoutConstraint.activate([
            tapView.widthAnchor.constraint(equalToConstant: 32),
            tapView.heightAnchor.constraint(equalToConstant: 32),
            tapView.topAnchor.constraint(equalTo: tipVC.view.topAnchor, constant: 8),  // Adjust if needed
            tapView.trailingAnchor.constraint(equalTo: tipVC.view.trailingAnchor, constant: -8) // Adjust if needed
        ])

You'll also need a selector, for example:

   extension UIViewController {
        @objc
         func dismissModal() {
          dismiss(animated: true)
          }
    }
Close button doesn't work in UIKit?
 
 
Q