skip to Main Content

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

2

Answers


  1. 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:

    UICollectionView with Custom UICollectionViewCell to show UIMenu UIContextMenuConfiguration UIContextMenuInteraction interaction triggered from a UIButton

    Login or Signup to reply.
  2. For adding context menu to UIButton (working in Xcode 14.0)

    let favorite = UIAction(title: "Favorite",
          image: UIImage(systemName: "heart.fill")) { _ in
          // Perform action
        }
        
    let share = UIAction(title: "Share",
          image: UIImage(systemName: "square.and.arrow.up.fill")) { _ in
          // Perform action
        }
        
        
        let button = UIButton()
        button.showsMenuAsPrimaryAction = true
        button.menu = UIMenu(title: "", children: [favorite, share])
        
          
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search