Here is how to add a mouse hover effect / UIPointer Interaction to your UITableViewCell, UICollectionViewCell, UIButton, UIView using Swift

As Apple describes Pointer Interactions in its support document:

Pointer Interactions: Support pointer interactions in your custom controls and views.

iPadOS 13.4 introduces dynamic pointer effects and behaviors that enhance the experience of using an external input device, like a trackpad or mouse, with iPad. As people use an input device, iPadOS automatically adapts the pointer to the current context, providing rich visual feedback and just the right level of precision needed to enhance productivity and simplify common tasks.

Note: UIPointer Interaction is only related to iPad / iPadOS app

Initial Step: Add ‘UIPointerInteractionDelegate’ in your View Controller’s Class Declaration

For UIButton:

Out-of-Box Implementation:

button.isPointerInteractionEnabled = true

UIView and Custom Implementation for UIButton:

if #available(iOS 13.4, *) {
  customPointerInteraction(on: myButton, pointerInteractionDelegate: self)
}
// MARK: - UIPointerInteractionDelegate 
@available(iOS 13.4, *)
func customPointerInteraction(on view: UIView, pointerInteractionDelegate:  
UIPointerInteractionDelegate){ 
  let pointerInteraction = UIPointerInteraction(delegate:  
pointerInteractionDelegate) 
  view.addInteraction(pointerInteraction) 
}

@available(iOS 13.4, *) 
func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: 
UIPointerRegion) -> UIPointerStyle {
  var pointerStyle: UIPointerStyle? 
 
  if let interactionView = interaction.view {
      let targetedPreview = UITargetedPreview(view: interactionView)
      pointerStyle = UIPointerStyle(effect:
UIPointerEffect.highlight(targetedPreview))
  }
  return pointerStyle
}

For UITableViewCell:

Add the following code to your UITableViewController’s File

// MARK: - UIPointerInteractionDelegate

    @available(iOS 13.4, *)
    func customPointerInteraction(on view: UITableViewCell, pointerInteractionDelegate: UIPointerInteractionDelegate){
        let pointerInteraction = UIPointerInteraction(delegate: pointerInteractionDelegate)
        view.addInteraction(pointerInteraction)
    }
     
    @available(iOS 13.4, *)
    func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle? {
        var pointerStyle: UIPointerStyle?
        print("pointerInteraction view", interaction.view!)
        if let interactionView = interaction.view {
            let targetedPreview = UITargetedPreview(view: interactionView)
            pointerStyle = UIPointerStyle(effect: UIPointerEffect.hover(targetedPreview, preferredTintMode: .overlay, prefersShadow: true, prefersScaledContent: true))
        }
        return pointerStyle
    }
    
    @available(iOS 13.4, *)
        func pointerInteraction(_ interaction: UIPointerInteraction, willEnter region: UIPointerRegion, animator: UIPointerInteractionAnimating) {
        if let interactionView = interaction.view {
            animator.addAnimations {
                interactionView.alpha = 0.5
            }
        }
    }

    @available(iOS 13.4, *)
    func pointerInteraction(_ interaction: UIPointerInteraction, willExit region: UIPointerRegion, animator: UIPointerInteractionAnimating) {
        if let interactionView = interaction.view {
            animator.addAnimations {
                interactionView.alpha = 1.0
            }
        }
    }

Now Add this code to the ‘UITableView cellForRowAt indexPath’ Code Block:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)

        // Configure the cell...
        
        if #available(iOS 13.4, *) {
            customPointerInteraction(on: cell.self, pointerInteractionDelegate: self)
        }

    return cell

    }

For UICollectionView:

Add the following code to your UICollectionViewController’s File

// MARK: - UIPointerInteractionDelegate

    @available(iOS 13.4, *)
    func customPointerInteraction(on view: UICollectionViewCell, pointerInteractionDelegate: UIPointerInteractionDelegate){
        let pointerInteraction = UIPointerInteraction(delegate: pointerInteractionDelegate)
        view.addInteraction(pointerInteraction)
    }
     
    @available(iOS 13.4, *)
    func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle? {
        var pointerStyle: UIPointerStyle?
        print("pointerInteraction view", interaction.view!)
        if let interactionView = interaction.view {
            let targetedPreview = UITargetedPreview(view: interactionView)
            pointerStyle = UIPointerStyle(effect: UIPointerEffect.hover(targetedPreview, preferredTintMode: .overlay, prefersShadow: true, prefersScaledContent: true))
        }
        return pointerStyle
    }
    
    @available(iOS 13.4, *)
        func pointerInteraction(_ interaction: UIPointerInteraction, willEnter region: UIPointerRegion, animator: UIPointerInteractionAnimating) {
        if let interactionView = interaction.view {
            animator.addAnimations {
                interactionView.alpha = 0.5
            }
        }
    }

    @available(iOS 13.4, *)
    func pointerInteraction(_ interaction: UIPointerInteraction, willExit region: UIPointerRegion, animator: UIPointerInteractionAnimating) {
        if let interactionView = interaction.view {
            animator.addAnimations {
                interactionView.alpha = 1.0
            }
        }
    }

Now Add this code to the ‘UICollectionView cellForItemAt indexPath’ Code Block:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = appIconCollectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! yourCollectionViewCell
        
        if #available(iOS 13.4, *) {
            customPointerInteraction(on: cell.self, pointerInteractionDelegate: self)
        }

    return cell

    }

I hope this information helps you get the desired effect…

Thanks & Regards
Mandar Apte

Mandar Apte

This website contains a design articles blog by Mandar Apte. He writes and shares his iOS development, graphic, web, & animation film design experience through articles. Mandar is Mumbai based multi-disciplinary designer with expertise in UI, UX, Logo, Symbol, and Brand Identity design. He is an alumnus of Sir J. J. Institute of Applied Art, Mumbai. He currently runs his studio in the heart of the city of Mumbai.

Leave a Reply

Your email address will not be published. Required fields are marked *