2017-07-02 40 views
0

我正在为用户构建自定义界面,以在我的应用中输入偏好设置。我正在使用example I found at AppCoda之后的展开式行。我重写了这个例子来使用Swift 3/4,并使用代码中的单元信息而不是从plist中读取。Swift表中的可扩展单元 - 单元重用/出队?

我遇到了一些单元格内容出现在屏幕上的问题。展开和折叠的行包含文本字段以允许用户输入。下面的示例代码中有四个这样的行。

在其中一个单元格中输入条目时,它们可能会或不会导致最后输入的值在展开时出现在所有四个单元格中。 '额外'文本甚至会覆盖那里的信息。

我试过了所有我能想到的东西来摆脱这种违规的文字,但我把头撞在墙上。我错过了什么?

FWIW,我现在正在其他地方寻找类似的解决方案。这里有一个我喜欢了不少:

https://github.com/jeantimex/ios-swift-collapsible-table-section-in-grouped-section

这一个看起来很有趣,但不是在斯威夫特:

https://github.com/singhson/Expandable-Collapsable-TableView

相同意见:

https://github.com/OliverLetterer/SLExpandableTableView

这看起来非常有趣 - 很好的支持 - 但我没有时间去调查:

https://github.com/Augustyniak/RATreeView

了类似的要求在这里:

Expand cell when tapped in Swift

这里描述的类似的问题,但我觉得我已经做了什么建议?

http://www.thomashanning.com/the-most-common-mistake-in-using-uitableview/

这里是我的表视图控制器代码。我相信问题在...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath): 

...功能,但对于我的生活我看不到它。

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 
    test = defineCellProps() // This loads my hard-coded cell properties into array "test" 
    configureTableView() 
} 

func configureTableView() { 
    loadCellDescriptors() 
    tblExpandable.delegate = self 
    tblExpandable.dataSource = self 
    tblExpandable.tableFooterView = UIView(frame: CGRect.zero) 
    tblExpandable.register(UINib(nibName: "NormalCell", bundle: nil), forCellReuseIdentifier: "idCellNormal") 
    tblExpandable.register(UINib(nibName: "TextfieldCell", bundle: nil), forCellReuseIdentifier: "idCellTextfield") // There are additional cell types that are not shown and not related to the problem 
} 

func loadCellDescriptors() { // Puts the data from the "test" array into the format used in the original example 
    for section in 0..<ACsections.count { 
     var sectionProps = findDict(matchSection: ACsections[section], dictArray: test) 
     cellDescriptors.append(sectionProps) 
    } 
    cellDescriptors.remove(at: 0) // Removes the empty row 
    getIndicesOfVisibleRows()   
    tblExpandable.reloadData() // The table 
} 

func getIndicesOfVisibleRows() { 
    visibleRowsPerSection.removeAll() 
    for currentSectionCells in cellDescriptors { // cellDescriptors is an array of sections, each containing an array of cell dictionaries 
     var visibleRows = [Int]() 
     let rowCount = (currentSectionCells as AnyObject).count as! Int 
     for row in 0..<rowCount { // Each row is a table section, and array of cell dictionaries 
      var testDict = currentSectionCells[row] 
      if testDict["isVisible"] as! Bool == true { 
       visibleRows.append(row) 
      } // Close the IF 
     } // Close row loop 
     visibleRowsPerSection.append(visibleRows) 
    } // Close section loop 
} // end the func 


func getCellDescriptorForIndexPath(_ indexPath: IndexPath) -> [String: AnyObject] { 
    let indexOfVisibleRow = visibleRowsPerSection[indexPath.section][indexPath.row] 
    let cellDescriptor = (cellDescriptors[indexPath.section])[indexOfVisibleRow] 
    return cellDescriptor as [String : AnyObject] 
} 

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

    let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath) 
    let cell = tableView.dequeueReusableCell(withIdentifier: currentCellDescriptor["cellIdentifier"] as! String, for: indexPath) as! CustomCell 
    cell.textLabel?.text = nil 
    cell.detailTextLabel?.text = nil 
    cell.textField?.placeholder = nil 
    if currentCellDescriptor["cellIdentifier"] as! String == "idCellNormal" { 
     if let primaryTitle = currentCellDescriptor["primaryTitle"] { 
      cell.textLabel?.text = primaryTitle as? String 
     } 

     if let secondaryTitle = currentCellDescriptor["secondaryTitle"] { 
      cell.detailTextLabel?.text = secondaryTitle as? String 
     } 
    } 
    else if currentCellDescriptor["cellIdentifier"] as! String == "idCellTextfield" { 
     if let primaryTitle = currentCellDescriptor["primaryTitle"] { 
      if primaryTitle as! String == "" { 
       cell.textField.placeholder = currentCellDescriptor["secondaryTitle"] as? String 
       cell.textLabel?.text = nil 

      } else { 
       cell.textField.placeholder = nil 
       cell.textLabel?.text = primaryTitle as? String 
      } 
     } 

     if let secondaryTitle = currentCellDescriptor["secondaryTitle"] { 
      cell.detailTextLabel?.text = "some text" 
     } 
     cell.detailTextLabel?.text = "some text" 
// This next line, when enabled, always puts the correct row number into each cell. 
//   cell.textLabel?.text = "cell number \(indexPath.row)." 
    } 

    cell.delegate = self 

    return cell 
} 

这里是CustomCell代码几乎没有变化由我:

import UIKit 

protocol CustomCellDelegate { 
func textfieldTextWasChanged(_ newText: String, parentCell: CustomCell) 
} 

class CustomCell: UITableViewCell, UITextFieldDelegate { 

@IBOutlet weak var textField: UITextField! 

let bigFont = UIFont(name: "Avenir-Book", size: 17.0) 
let smallFont = UIFont(name: "Avenir-Light", size: 17.0) 
let primaryColor = UIColor.black 
let secondaryColor = UIColor.lightGray 

var delegate: CustomCellDelegate! 

override func awakeFromNib() { 
    super.awakeFromNib()   // Initialization code 

    if textLabel != nil { 
     textLabel?.font = bigFont 
     textLabel?.textColor = primaryColor 
    } 

    if detailTextLabel != nil { 
     detailTextLabel?.font = smallFont 
     detailTextLabel?.textColor = secondaryColor 
    } 

    if textField != nil { 
     textField.font = bigFont 
     textField.delegate = self 
    }   
} 

override func setSelected(_ selected: Bool, animated: Bool) { 
    super.setSelected(selected, animated: animated) 
    // Configure the view for the selected state 
} 

override func prepareForReuse() { // I added this and it did not help 
    super.prepareForReuse() 
    textLabel?.text = nil 
    detailTextLabel?.text = nil 
    textField?.placeholder = nil 
} 

func textFieldShouldReturn(_ textField: UITextField) -> Bool { 
    if delegate != nil { 
     delegate.textfieldTextWasChanged(textField.text!, parentCell: self) 
    } 
    return true 
    } 
} 

回答

0

OMG,我拍着我的掌心我的额头。上面的代码中缺少一条非常重要的代码行:

override func prepareForReuse() { 
super.prepareForReuse() 
textLabel?.text = nil 
detailTextLabel?.text = nil 
textField?.placeholder = nil 
} 

你能看到缺少的东西吗?

textField?.text = nil 

这就是这一切!我正在嘲笑标签,但不是textfield文本本身。