Does iOS 13 - UIMenu have a bug that doesn't show its image?
Asked Answered
A

3

1

Paste the following code into a project:

No image shows next to 'Device Honey' ie the UIMenu However the image shows up next to 'Copy' ie the UIACtion.

Am I doing something wrong? If this is a bug? Is there a workaround?

class ViewController: UIViewController {
    let tableview: UITableView = {
        let tv = UITableView()
        tv.frame = UIScreen.main.bounds

        return tv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(tableview)
        tableview.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableview.delegate = self
        tableview.dataSource = self
    }
}

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        if cell.detailTextLabel == nil {
            cell = UITableViewCell(style: .value1, reuseIdentifier: "cell")
        }
        cell.textLabel?.text = "Honey"
        cell.detailTextLabel?.text = "iOS developer"

        return cell
    }

    @available(iOS 13.0, *)
    func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {

        return UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: { suggestedActions in

            return self.makeContextMenu(for: indexPath)
        })
    }

    @available(iOS 13.0, *)
    func makeContextMenu(for indexPath: IndexPath) -> UIMenu? {

        let copyAction = UIAction(title: "Copy", image: UIImage(systemName: "square.and.arrow.up")) { [weak self] _ in
            guard let self = self else { return }
            let cell = self.tableview.cellForRow(at: indexPath)
            let pasteboard = UIPasteboard.general
            pasteboard.string = cell?.detailTextLabel?.text
        }

        guard let cell = self.tableview.cellForRow(at: indexPath), let title = cell.textLabel?.text else { return nil}
        return UIMenu(title: "Device \(title) ", image: UIImage(systemName: "square.and.arrow.up"), children: [copyAction])
    }
}

enter image description here

In Apple's WWDC demo they're able to do it as shown below:

enter image description here

Anisaanise answered 16/10, 2019 at 21:55 Comment(0)
P
2

A context menu has two parts: the preview and the menu. Both are optional. The "groceries" thing in the Apple screenshot is the preview, not the menu. By default, the cell is snapshotted and the snapshot is displayed as the preview. The menu itself in the Apple screenshot has no image and no title. And that's what you should do too! The last line

return UIMenu(...

...should have no title and no image. This menu, the one that wraps everything else and is returned, is the top-level menu, and it is displayed differently (as your own screenshot shows). It looks best without a title, and it cannot display an image at all. Its job is to wrap everything else and to provide an identifier, and that's all.

You will then get something like this:

enter image description here

Plumbaginaceous answered 16/10, 2019 at 22:13 Comment(12)
Then how is Apple doing the ‘groceries’ title and the image? Obviously my title is showing....Anisaanise
"The top level" that was key. Is that mentioned anywhere in the API? Can you include that in your answer?Anisaanise
and I suppose there's no built-in class that I can just assign a title and image. Right?Anisaanise
I do not know what that means. You mean you want to create the preview yourself? Of course you can do that.Plumbaginaceous
I was asking if just like tableviewcell where you just dump the image and text and the layout is done, is there anything similar for the PreviewProvider? I rather not create it myself :)Anisaanise
I still don't know what you mean. The table view cell is the preview by default.Plumbaginaceous
I don't know what you mean either!Anisaanise
Oh. Well, your Apple snapshot shows it. The table cell that you long pressed has been snapshotted and the snapshot is used as the preview. And that is the default behavior. So there is nothing to "create".Plumbaginaceous
And your own screenshot is doing the same thing. Your cell is the preview.Plumbaginaceous
🤦‍♂️I get it now. Thanks. Problem was that my cell itself didn't have an image, but I wanted to add the image to the previews. I wasn't thinking straightAnisaanise
I added a screencast.Plumbaginaceous
Can you take a look How can I use suggestedActions given from UIContextMenuConfiguration??Anisaanise
A
0

This is more of an important comment

The preview that you're showing in your question is terribly misleading. It looks like the other items in the menu. Yet that Groceries section in your screenshot is a Preview. A much more distinctive preview would be something like this:

enter image description here

Image source

Anisaanise answered 20/10, 2020 at 20:23 Comment(0)
E
0

I have the same question, documentation on UIMenu init(title:image:identifier:options:children:) indicates an image parameter:

image: The image to display next to the menu's title.

It looks like is intended to be used in submenus, as shown in this blog: UIMenu Comprehensive Guide

Excavate answered 26/12, 2021 at 19:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.