Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> iOS

Cách phát hiện Long Press (nhấn giữ) trong iOS

Long Press (press-and-hold): Phát hiện ngón tay chạm màn hình kéo dài một khoảng thời gian. Dùng cho: context menu, drag & drop, trigger action phụ.

Apple Docs: Handling Long-Press Gestures

Ví dụ: Hiển thị Alert khi nhấn giữ button 2 giây

Bước 1: Tạo dự án

Xcode → Single View App → Tên: "LongPressGesture".

Bước 2: Storyboard

Thêm Button → Tạo @IBOutlet weak var btnLongOutlet: UIButton!

Bước 3: Code ViewController.swift


import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var btnLongOutlet: UIButton!
    private var longPressGesture: UILongPressGestureRecognizer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupLongPressGesture()
    }
    
    func setupLongPressGesture() {
        longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
        longPressGesture.minimumPressDuration = 2.0 // 2 giây
        longPressGesture.allowableMovement = 10 // Cho phép di chuyển 10pt vẫn tính là long press
        btnLongOutlet.addGestureRecognizer(longPressGesture)
    }
    
    @objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
        // Quan trọng: Kiểm tra state để chỉ trigger 1 lần
        guard gesture.state == .began else { return }
        
        let alert = UIAlertController(title: "Long Press", 
                                      message: "Long Press Gesture Detected", 
                                      preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default))
        present(alert, animated: true)
    }
}

Cách phát hiện Long Press (nhấn giữ) trong iOS

Các State của UILongPressGestureRecognizer

State Ý nghĩa Khi nào xảy ra
.possible Chưa xác định Ban đầu
.began Vừa đạt ngưỡng thời gian Trigger action chính ở đây
.changed Đang giữ, có di chuyển nhẹ Drag tracking
.ended Nhả ngón tay Cleanup, kết thúc drag
.cancelled Hủy (system interrupt, call coming...) Reset state
.failed Không đạt ngưỡng Tap quá nhanh

Cấu hình quan trọng


let gesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
gesture.minimumPressDuration = 0.5    // Mặc định 0.5s, có thể tăng (2s cho deliberate action)
gesture.allowableMovement = 10        // Mặc định 10pt, tăng nếu muốn cho di chuyển nhiều hơn
gesture.numberOfTouchesRequired = 1   // Số ngón tay (default 1)
gesture.numberOfTapsRequired = 0      // Số tap trước khi hold (default 0)

Thêm Long Press cho bất kỳ View nào (Programmatically)


extension UIView {
    func addLongPressGesture(target: Any, action: Selector, duration: TimeInterval = 0.5) {
        let gesture = UILongPressGestureRecognizer(target: target, action: action)
        gesture.minimumPressDuration = duration
        gesture.allowableMovement = 10
        self.addGestureRecognizer(gesture)
        self.isUserInteractionEnabled = true // Bắt buộc!
    }
}

// Usage
myView.addLongPressGesture(target: self, action: #selector(handleLongPress), duration: 1.0)

Long Press trên TableView/CollectionView (Cell)


// Trong cellForRowAt
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(cellLongPressed(_:)))
cell.addGestureRecognizer(longPress)

// Handler
@objc func cellLongPressed(_ gesture: UILongPressGestureRecognizer) {
    guard gesture.state == .began,
          let cell = gesture.view as? UITableViewCell,
          let indexPath = tableView.indexPath(for: cell) else { return }
    
    // Haptic feedback
    let generator = UIImpactFeedbackGenerator(style: .medium)
    generator.impactOccurred()
    
    // Show context menu hoặc action sheet
    showContextMenu(for: indexPath)
}

iOS 13+: UIContextMenuInteraction (Thay thế Long Press cho context menu)


let interaction = UIContextMenuInteraction(delegate: self)
view.addInteraction(interaction)

// Delegate
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, 
                            configurationForMenuAtLocation location: CGPoint) 
    -> UIContextMenuConfiguration? {
    return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
        let edit = UIAction(title: "Sửa", image: UIImage(systemName: "pencil")) { _ in }
        let delete = UIAction(title: "Xóa", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in }
        return UIMenu(title: "", children: [edit, delete])
    }
}

Lưu ý

  • Luôn check gesture.state == .began để tránh trigger nhiều lần
  • Thêm isUserInteractionEnabled = true cho view nếu chưa có
  • Long press delay mặc định 0.5s - tăng lên 1-2s cho action nguy hiểm (xóa, logout)
  • Kết hợp UIImpactFeedbackGenerator cho haptic feedback tốt hơn UX