[英]How to segue to another view controller when a subview with a gesture is tapped?
[英]How to go to another View Controller when an element inside table view is being tapped?
我在TableViewCell中有一個UIView,當用戶在此UIView中點擊時,它會轉到另一個視圖控制器並傳遞數據。
因此,在TableViewCellClass內部,我執行了以下操作:
我在用戶表UIView時設置了協議並檢測到“輕按”手勢。這部分工作正常:
protocol MyDelegate : class {
func runThisFunction(myString : String)
}
class MyTableViewCell: UITableViewCell {
weak var delegate : MyDelegate?
...other code here
//here detect the tap
let tap = UITapGestureRecognizer(target: self, action: #selector(hereTapped))
self.myUIElementInThisCell.addGestureRecognizer(tap)
}
@objc func hereTapped(sender: UITapGestureRecognizer? = nil){
self.delegate?.runThisFunction(myString: "I am a man")
}
因此,在包含此TableView的視圖控制器中,我執行了以下操作:
我將MyDelegate
擴展為子類,然后將協議函數附加到其中,如下所示
class MyViewController: UIViewController,MyDelagate{
func runThisFunction(myString : String) {
print("Tapped in view controller")
self.performSegue(withIdentifier: "MySegue",sender : self)
}
override func viewDidLoad() {
super.viewDidLoad()
let tableViewCell = MyTableViewCell()
tableViewCell.delegate = self
}
}
結果:
完成上述所有操作后,當我點擊UIView
,它沒有執行MyViewControllerClass
所述的MyViewControllerClass
,甚至print()
命令也沒有執行。
那我錯過了什么呢? 請給我一個解決方案。謝謝
問題是這兩行:
let tableViewCell = MyTableViewCell()
tableViewCell.delegate = self
與表格中顯示的單元格無關,它是即時創建的單元格,因此
在cellForRow
為實際上要等待它們的委托觸發器的單元格設置委托
cell.delegate = self
像這樣
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = areaSettTable.dequeueReusableCell(withIdentifier:cellID) as! MyTableViewCell
cell.delegate = self
}
問題是MyTableViewCell
實例的委托未定義。
當您這樣做時:
override func viewDidLoad() {
super.viewDidLoad()
let tableViewCell = MyTableViewCell()
tableViewCell.delegate = self
}
您正在為一個對象設置委托,該委托將在方法viewDidLoad()
完成時銷毀。
解決方案1
為了避免這種情況,您必須在cellForRow
方法內設置委托。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! MyTableViewCell
cell.delegate = self
// Other configurations
return cell
}
解決方案2
您還可以使用UITableViewDelegate
方法來捕獲與單元格的用戶交互。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
self.performSegue(withIdentifier: "MySegue",sender : self)
}
這樣,您可以避免所有MyDelegate protocol
。 這將是我的首選。
問題出在您的viewDidLoad
:
// you create a new cell
let tableViewCell = MyTableViewCell()
// set its delegate
tableViewCell.delegate = self
// and then the cell is not used for anything else
基本上,您不是為要顯示的單元格設置委托,而是為在viewDidLoad
創建的另一個實例設置委托。
您必須在cellForRowAt
設置一個委托,以確保正確的單元格獲得了delegate
集:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier", for: indexPath) as! MyTableViewCell
cell.delegate = self
return cell
}
這將為顯示的那些單元格設置delegate
。
另外,我建議使用UITableViewDelegate
didSelectRowAt
(如果您的MyViewController
實現了它):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 { // only if it is the first cell (I assume that MyTableViewCell is first)
runThisFunction(myString: "I am a man")
}
}
這里的委托不是很好,的確,如果您要更改未明確傳遞給單元的對象,則確實如此。
我的建議是使用閉包:
typealias CellTapHandler = (String)->()
class CustomCell: UITableViewCell {
var handler: CellTapHandler?
@objc func hereTapped(sender: UITapGestureRecognizer? = nil) {
handler?("String or whatever you want to get back from cell.")
}
//...
}
並從視圖控制器進行設置
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier", for: indexPath)
(cell as? MyTableViewCell).handler = { [weak self] string in }
return cell
}
PS:正如我所說,通常您想進一步傳遞與單元格相關的對象。 委派是很難做到的,因為您必須傳遞一些額外的令牌給單元格,以便由單元格確定對象,否則傳遞對象本身會破壞Model-View分離范式。 但這可以通過閉包輕松完成:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let object = self.myData[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier", for: indexPath)
(cell as? MyTableViewCell).handler = { [weak self] string in
self.performSegue(withIdentifier: "MySegue",sender : object)
}
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (let myObj = sender as? MyObjType, let subsequentVC = segue.destination as? NextViewController) {
subsequentVC.selectedMyObject = myObj
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.