2017-09-21 73 views
0

我是Swift的新手。我在tableview中創建了一個簡單的列表。當用戶長按一行時,該行將被檢查。它工作得很好。但是當我向下滾動時,複選標記會改變它的位置。我也嘗試在NSMutableSet中存儲位置。但仍然無法正常工作。也許我做錯了什麼。滾動時表格視圖單元格複選標記更改位置

這是我的代碼:

這個方法被長時間調用。

func longpress(gestureRecognizer: UIGestureRecognizer) 
{ 
    let longpress = gestureRecognizer as! UILongPressGestureRecognizer 
    let state = longpress.state 
    let locationInview = longpress.location(in: tableview1) 
    var indexpath=tableview1.indexPathForRow(at: locationInview) 

    if(gestureRecognizer.state == UIGestureRecognizerState.began) 
    { 
     if(tableview1.cellForRow(at: indexpath!)?.accessoryType == 
     UITableViewCellAccessoryType.checkmark) 
     { 
      tableview1.cellForRow(at: indexpath!)?.accessoryType = 
       UITableViewCellAccessoryType.none 
     } 
     else{ 
      tableview1.cellForRow(at: indexpath!)?.accessoryType = 
       UITableViewCellAccessoryType.checkmark 
     } 
    } 
} 
+0

你想讓我幫你格式化嗎?如果你長時間沒有牢房,這也會崩潰,我也可以爲你解決這個問題。 –

回答

1

的問題是,細胞被重用,當您更新一個對號,您要更新單元,但不更新模型。因此,當一個單元格滾動出視圖並且單元格被重用時,您的cellForRowAt顯然不會重置表格新行的複選標記。

同樣,如果您將單元格滾回到視圖中,cellForRowAt無法知道是否應該檢查單元格。您必須

  • 當您在單元格上檢測到您的手勢時,您必須更新模型以知道該行的單元格應該檢查;和

  • 您的cellForRowAt必須在配置單元時查看此屬性。

因此,首先確保您的模型具有一些值來指示它是否被選中或未選中。在這個例子中,我將使用「項目」,但你會使用一個更有意義的類型名稱:

struct Item { 
    let name: String 
    var checked: Bool 
} 

然後您的視圖控制器可適當cellForRowAt填充細胞:

class ViewController: UITableViewController { 

    var items: [Item]! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     addItems() 
    } 

    /// Create a lot of sample data so I have enough for a scrolling view 

    private func addItems() { 
     let formatter = NumberFormatter() 
     formatter.numberStyle = .spellOut 
     items = (0 ..< 1000).map { Item(name: formatter.string(from: NSNumber(value: $0))!, checked: false) } 
    } 
} 

extension ViewController { 
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return items.count 
    } 

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell 
     cell.delegate = self 
     cell.textLabel?.text = items[indexPath.row].name 
     cell.accessoryType = items[indexPath.row].checked ? .checkmark : .none 
     return cell 
    } 
} 

現在,我通常讓單元格處理諸如識別手勢之類的東西,並相應地通知視圖控制器。因此,創建一個UITableViewCell子類,並將其指定爲故事板上單元格原型的基類。但細胞需要一些協議,用於向一個長按發生的視圖控制器:

protocol ItemCellDelegate: class { 
    func didLongPressCell(_ cell: UITableViewCell) 
} 

而且表視圖控制器可以處理此委託方法,切換它的型號和相應重裝電池:

extension ViewController: ItemCellDelegate { 
    func didLongPressCell(_ cell: UITableViewCell) { 
     guard let indexPath = tableView.indexPath(for: cell) else { return } 

     items[indexPath.row].checked = !items[indexPath.row].checked 
     tableView.reloadRows(at: [indexPath], with: .fade) 
    } 
} 

然後,UITableViewCell子類只需要一個長按手勢識別,並且在該手勢被識別,通知視圖控制器:

class ItemCell: UITableViewCell { 

    weak var delegate: CellDelegate? 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) 
     addGestureRecognizer(longPress) 
    } 

    @IBAction func handleLongPress(_ gesture: UILongPressGestureRecognizer) { 
     if gesture.state == .began { 
      delegate?.didLongPressCell(self) 
     } 
    } 
} 

順便說一下,通過在手機上設置手勢,它可以避免由於「如果我長時間按在不是手機的東西上會發生什麼」的混淆。單元格是手勢識別器的正確位置。

0

您不在任何地方存儲更改。

爲避免使用太多內存,手機會重複使用單元格,並要求您在TableViewdataSource中配置它們。

假設你有一個名爲data的數組,它有一些存儲你想要顯示爲單元格的結構。你需要更新這個數組並告訴tableView重新加載你的單元格。

func userDidLongPress(gestureRecognizer: UILongPressGestureRecognizer) { 

    // We only care if the user began the longPress 
    guard gestureRecognizer.state == UIGestureRecognizerState.began else { 
     return 
    } 

    let locationInView = gestureRecognizer.location(in: tableView) 

    // Nothing to do here if user didn't longPress on a cell 
    guard let indexPath = tableView.indexPathForRow(at: locationInView) else { 
     return 
    } 

    // Flip the associated value and reload the row 
    data[indexPath.row].isChecked = !data[indexPath.row].isChecked 
    tableView.reloadRows(at: [indexPath], with: .automatic) 
} 

而且始終將附件在配置單元:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) 
    -> UITableViewCell { 

    let cell = tableView.dequeueReusableCell(
     withIdentifier: "someIdentifier", 
     for: indexPath 
    ) 

    cell.accessoryType = data[indexPath.row].isChecked ? .checkmark : .none 
} 
相關問題