簡體   English   中英

防止UITableViewCell子視圖上的交互

[英]Prevent interaction on subview of UITableViewCell

我有一個大的UITableViewCell,里面有2個自定義UIViews。 其中一個應該允許交互(選擇和取消選擇),其中一個視圖不應該允許交互。

我知道我可以在整個單元格或每個子視圖上啟用或禁用交互,但如果我在UIView上禁用交互,則單元格仍會被選中或取消選中。

有沒有辦法,例如,允許接觸電池的上半部而不是底部?

這是我描述的UITableViewCell的屏幕截圖

在此輸入圖像描述

我會說你的實現存在缺陷,或者你有X / Y問題。 考慮將單個單元格拆分為兩個單獨的單元格,並禁用底部單元格上的選擇。

如果您必須繼續此實現,請考慮禁用整個單元格上的選擇。 將手勢識別器放在頂部子視圖中,並在觸摸時手動調用didSelectRowAtIndexPath: .

你可以通過命中測試來轉發或取消觸摸

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        if let hitView = super.hitTest(point, withEvent: event) {
            if hitView.isKindOfClass(CustomSubviewClass) {
                return nil
            } else {
                return hitView
            }
        } else {
            return nil
        }
    }

我完全同意JAL ,你需要檢查你所有的細胞結構,但我也知道有時候,在某些情況下,重構是不可能的。

所以,我想這個,假設你有一個由兩個視圖組成的CustomTableViewCell ,例如view1和view2命名:

代碼:

class MyView1 : UIView {
    var isTouched : Bool = false
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = true
        self.nextResponder()?.touchesBegan(touches, withEvent: event)
    }
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = false
        self.nextResponder()?.touchesEnded(touches, withEvent: event)
    }
}
class MyView2 : UIView {
    var isTouched : Bool = false
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = true
        self.nextResponder()?.touchesBegan(touches, withEvent: event)
    }
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.isTouched = false
        self.nextResponder()?.touchesEnded(touches, withEvent: event)
    }
}
class CustomTableViewCell: UITableViewCell {
    @IBOutlet weak var myExampleLabel: UILabel!
    @IBOutlet weak var view1: MyView1!
    @IBOutlet weak var view2: MyView2!

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        print("situation: myView1 : \(self.view1.isTouched) myView2: \(self.view2.isTouched)")
        var responder : UIResponder! = self
        while responder.nextResponder() != nil {
           responder = responder.nextResponder()
           if responder is SimpleTableView.ViewController { // the name of your tableView delegate class
                let vc = responder as! ViewController
                let indexPath = vc.tableView.indexPathForCell(self)
                vc.tableView(vc.tableView, didSelectRowAtIndexPath: indexPath!)
            }
        }
        super.touchesBegan(touches, withEvent: event)
    }
}

另一方面,你有一個帶有UITableViewUIViewController

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet var tableView: UITableView!
    var items: [String] = ["We", "Heart", "Swift", "So", "Much"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 140.0
        self.tableView.registerNib(UINib(nibName: "CustomTableViewCell", bundle:nil), forCellReuseIdentifier: "CustomTableViewCell")
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell", forIndexPath: indexPath) as! CustomTableViewCell
        cell.myExampleLabel.text = self.items[indexPath.row]
        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomTableViewCell
        print("row = %d",indexPath.row)
        if cell.view1.isTouched { 
           print("tableView: touched view 1") 
           // do whatever you want with cell.view1
           // if you want you can disable cell.view2.userInteractionEnabled
        }
        else {
            print("tableView: touched view 2")
            // same thing for cell.view2
        }
    }
}

一些重要的事情

不要忘記為兩個視圖設置正確的自定義類,如下圖所示:

在此輸入圖像描述

實現此功能的一種方法是繞過UITableViewDelegate方法,並在單元格上使用帶有自定義回調處理程序的IBAction

  1. 將單元格的“ 選擇”類型設置為“ 無”,以防止在您點擊單元格時選擇/取消選擇單元格。
  2. 確保您的UITableViewDelegate沒有實現tableView:didSelectRowAtIndexPath
  3. 在單元格中添加一個按鈕視圖並將其定位,使其覆蓋您希望用戶與之交互的區域。
  4. UITableViewCell子類中添加@IBAction func buttonTapped(sender: UIButton)
  5. 向單元格添加閉包變量。 點擊按鈕時調用閉包。
  6. tableView:cellForRowAtIndexPath: delegate方法中設置單元格上的閉包來處理調用。

示例UITableViewCell子類:

class MyTableViewCell: UITableViewCell {

    var selectionHandler: ((Void) -> Void)?

    override func prepareForReuse() { 
        // Remove the closure when the cell is recycled.
        selectionHandler = nil
    }

    @IBAction func buttonTapped(sender: UIButton) {
        // Call the closure when the button is tapped.
        selectionHandler?()
    }
}

在你的UITableViewController

class MyTableViewController: UITableViewController {

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = ....

        // Set the closure to be called when the button is tapped.
        // Using weak self here to prevent a retain cycle.
        cell.selectionHandler = { [weak self] in
            self?.selectedCellAtIndexPath(indexPath)
        }

        return cell
    }

    // We are not using didSelectRowAtIndexPath
    // override func tableView(tableView: UITableView, didSelectRowAtIndexPath: NSIndexPath) {
    // }
}

我沒有測試過這段代碼,所以它可能無法編譯,盡管它應該用來說明這個概念。

從表視圖屬性編輯器中,將“ Selection值設置為“ No Selection或以編程方式執行。 禁用每個子視圖上的交互,但您想要操作的子視圖除外。 將indexPath行值作為標記傳遞給該子視圖,也許。 或者從UIView子類化子視圖來存儲indexPath信息。 接下來,對該子視圖實施點擊手勢,並在點擊手勢識別方法上執行您的願望操作。 希望這些應該做你想要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM