iOS 14 UIMenu replacingChildren does not work - ios14

I want to add an UIMenu with conditional menu children to a UIButton's menu on iOS14, but the replacingChildren does not work.
self.button.menu = UIMenu( options: .displayInline, children:[
UIAction(title:"Action 1"){_ in},
UIAction(title:"Action 2"){_ in}
])
//Try to update menu's children but it does not work
self.button.menu = self.button.menu?.replacingChildren([
UIAction(title:"Action 3"){_ in},
UIAction(title:"Action 4"){_ in}
])
The menu does not change. I need to create a completely new instance of UIMenu with new children and assign it to self.button.menu. How to use replacingChildren or any mistake?

I stumbled upon this as well. For some reason using replacingChildren resulted in the unaltered children array on iOS 14. For iOS 15 the behavior is as expected.
However, I was able to go around this by just setting a newly instantiated UIMenu instead.
In your case by calling:
self.button.menu = UIMenu(options: .displayInline, children:[
UIAction(title:"Action 3"){_ in},
UIAction(title:"Action 4"){_ in}
])
Since this isn't the greatest solution and (for me) it was only needed for iOS 14 you might want to only use this when needed:
if #available(iOS 15.0, *) {
self.button.menu = self.button.menu?.replacingChildren([
UIAction(title:"Action 3"){_ in},
UIAction(title:"Action 4"){_ in}
])
} else {
self.button.menu = UIMenu(options: .displayInline, children:[
UIAction(title:"Action 3"){_ in},
UIAction(title:"Action 4"){_ in}
])
}
I hope this might help whoever needs it.

Related

Change UIMenu title with multiple line (UIMenu with UIButton)

I added UIMenu to the UIButton.menu with long title, but menu show not full text. Is there anyway to change it to show full text ? thanks for help
let _: [()] = (0...100).map {
childdrens.append(UIAction(title: "This is a very very very very very very very very very long title \($0)", handler: { _ in
}))
}
longCapMenuButton = UIMenu(title: "", options: .displayInline, children: childdrens )
longCapMenuButton.showsMenuAsPrimaryAction = true
Screenshot Attached below-

CarPlay CPNowPlayingTemplate player buttons doesn't work

However I implement the proper MPRemoteCommandCenter functions, the playback buttons are not responsive at all in carplay app.
(It works correctly with CarPlay before iOS 14, using MPPlayableContentManager)
Non of the MPRemoteCommandCenter callbacks are being called.
What could be the reason?
The code where I set up remote command center:
func setupRemoteCommandCenterTargets() {
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.playCommand.addTarget {event in
//myPlayer.play()
return .success
}
commandCenter.pauseCommand.isEnabled = true
commandCenter.pauseCommand.addTarget {event in
//myPlayer.pause()
return .success
}
commandCenter.nextTrackCommand.isEnabled = true
commandCenter.nextTrackCommand.addTarget {event in
//myPlayer.next()
return .success
}
commandCenter.previousTrackCommand.isEnabled = true
commandCenter.previousTrackCommand.addTarget {event in
//myPlayer.prev()
return .success
}
}
I know this question is old but I came across the same problem recently. What I deduced is that when MPNowPlayingInfoPropertyIsLiveStream is set to true, then the audio is considered a live stream and, in that case, you shouldn't use the pause button from the control center but the stop button instead.
In fact, if you implement the stop command:
commandCenter.stopCommand.addTarget { [unowned self] event in
// myPlayer.pause()
return .success
}
The control center changes on the iPhone too, not just on CarPlay, and the button for live streams become "stop".
I have no idea why on CarPlay the button is "stop" by default instead of pause, but this will fix your issue.

How to make a deprecated PKToolPicker method work for iOS 14

I am initialising my PKToolPicker on viewWillAppear and have the following code:
private func initialiseToolPicker() {
guard let window = UIApplication.shared.delegate?.window! else {
return
}
guard let toolPicker = PKToolPicker.shared(for: window) else {
return
}
toolPicker.addObserver(canvasView)
toolPicker.addObserver(self)
toolPicker.setVisible(true, forFirstResponder: canvasView)
updateLayout(for: toolPicker)
canvasView.becomeFirstResponder()
}
This works on all devices except iOS 14. What happens is that the first time the view appears it never reaches the becomeFirstResponder() line. Then if I close and reopen the view, it works.
I can't tell which line it fails at but I know that the line let toolPicker = PKToolPicker.shared(for: window) is deprecated in favour of let toolPicker = PKToolPicker(). However, my computer is too outdated to be able to run Xcode 12, so I can't build and submit that! Does anyone have a hack that would make this work (until I can get a better computer)?

UIContextMenuActionProvider puts unwanted checkmark icons on items

The problem
I was implementing UIContextMenuInteraction, and ended up with the behavior I can't explain or find fixes too. The issue as seen from the screen shot that menu items have checkmarks. This is not intended and those checkmarks added automatically. Ideally I'd like use SF Symbols, but any image I add ends up being this checkmark. Even if I set image to nil, it still adds this weird checkmark.
Additional steps taken: Reinstall SF Symbols and SF Pro, Clean build, Restart xCode / Simulator
Reproduced: Simulator iOS 13.3, iPhone 7 iOS 13.3
System: Catalina 10.15.1, xCode 11.3.1
Code:
import UIKit
class ViewController: UIViewController {
let sampleView = UIView(frame: CGRect(x: 50, y: 300, width: 300, height: 200))
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(sampleView)
sampleView.backgroundColor = .systemIndigo
let interaction = UIContextMenuInteraction(delegate: self)
sampleView.addInteraction(interaction)
}
}
extension ViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint
) -> UIContextMenuConfiguration? {
let actionProvider: UIContextMenuActionProvider = { [weak self] _ in
let like = UIAction(
title: "Like",
image: UIImage(systemName: "heart"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .on
) { _ in
}
let copy = UIAction(
title: "Copy",
image: nil,
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .on
) { _ in
}
let delete = UIAction(
title: "Delete",
image: UIImage(systemName: "trash"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [.destructive],
state: .on
) { _ in
}
return UIMenu(
title: "",
image: nil,
identifier: nil,
options: [],
children: [
like, copy, delete
]
)
}
let config = UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: actionProvider)
return config
}
}
You need to change UIAction.state from .on to .off to get rid of the checkmark.

Dynamic App Icons iOS

Is there any way to customize "You have changed the icon for AppName" message after UIApplication.shared.setAlternateIconName("image") call or get rid of it at all?
Sadly you can't because it is provided by the system, according to Apple's official guidelines.
Note that your app icon can only be changed at the user’s request and
the system always provides the user with confirmation of such a
change.
https://developer.apple.com/ios/human-interface-guidelines/icons-and-images/app-icon/
Well, there's a solution to customize the text, but not sure whether Apple would approve it. We need to get the label:
func findTheLabel(in view: UIView)
{
for item in view.subviews {
if let view = item as? UILabel, view.text == "You have changed the icon for “myApp”." {
view.text = "Hi, \n kind greetings from “myApp”."
view.textAlignment = .justified
}
guard item.subviews.count > 0 else { continue }
findTheLabel(in: item)
}
}
And simply call it right after:
UIApplication.shared.setAlternateIconName(iconName) { (error) in
print(error)
}
with small dispatch
Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false) {_ in
if let view = UIApplication.topViewController()?.view {
self.findTheLabel(in: view)
}
}
Maybe someone would find it useful.

Resources