简体   繁体   中英

Manually invoke context menu in collectionView for cell

I implemented methods for context menu with delegate methods like this:

func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
    configureContextMenu(index: indexPath.row)
}

func configureContextMenu(index: Int) -> UIContextMenuConfiguration {
    let context = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { (action) -> UIMenu? in
        
        let edit = UIAction(title: "Edit", image: UIImage(systemName: "square.and.pencil"), identifier: nil, discoverabilityTitle: nil, state: .off) { (_) in
            print("edit button clicked")
        }
        let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash"), identifier: nil, discoverabilityTitle: nil,attributes: .destructive, state: .off) { (_) in
            print("delete button clicked")
        }
        
        return UIMenu(title: "Options", image: nil, identifier: nil, options: UIMenu.Options.displayInline, children: [edit,delete])
        
    }
    return context
}

It's working fine and as I wanted. But I am targeting like older audience and I am not sure if they would know that they can hold cells for context menu. So I want to add three dots to right corner and after they tap that it shows same context menu for cell. Is is possible to do this? How can I manually invoke it?

Thanks for help

I believe it is not possible to manually invoke UIContextMenus as their interaction trigger and event management is handled internally as per the docs

A context menu interaction object tracks Force Touch gestures on devices that support 3D Touch, and long-press gestures on devices that don't support it.

The only work around I can think of is to use UIMenu with a UIButton on your collection view cell.

I call it a work around rather than a solution because you will gain with the one tap user experience but you will lose the blurry background and focus of the user interaction that UIContextMenu gives you with collection view and table views.

Nonetheless, here is my implementation of the custom UICollectionViewCell where the button pins to the edges of the cell, however you can size it as you wish. You can check if this is feasible for your use case:

class ButtonCollectionViewCell: UICollectionViewCell
{
    static let reuseIdentifier = "ButtonCollectionViewCell"
    
    let titleLabel = UILabel()
    let hiddenButton = UIButton()
    
    override init(frame: CGRect)
    {
        super.init(frame: frame)
        contentView.backgroundColor = .yellow
        configureLabel()
        configureButton()
        layoutIfNeeded()
    }
    
    required init?(coder: NSCoder)
    {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func configureLabel()
    {
        contentView.addSubview(titleLabel)
        
        // Auto layout config to pin label to the edges of the content view
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    }
    
    private func configureButton()
    {
        addSubview(hiddenButton)
        
        // I add this red color so you can see the button takes up the whole cell
        hiddenButton.backgroundColor = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.75)
        
        // Auto layout config to pin button to the edges of the content view
        hiddenButton.translatesAutoresizingMaskIntoConstraints = false
        hiddenButton.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        hiddenButton.topAnchor.constraint(equalTo: topAnchor).isActive = true
        hiddenButton.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        hiddenButton.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        
        // Configure menu
        hiddenButton.showsMenuAsPrimaryAction = true
        hiddenButton.menu = UIMenu(title: "Select an option", children: [
            
            UIAction(title: "Option 1") { action in
                // do your work
            },
            
            UIAction(title: "Option 2") { action in
                // do your work
            },
        ])
    }
}

The result is the following on single tap:

带有自定义 UICollectionViewCell 的 UICollectionView 以显示从 UIButton 触发的 UIMenu UIContextMenuConfiguration UIContextMenuInteraction 交互

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM