2017-01-21 10 views
0

Я создал расширяемый класс UITableViewCell, который модифицирует константу для достижения эффекта.Расширяемый TableViewCells - повторное использование ячеек вызывает

import UIKit 

class ExpandableCell: UITableViewCell { 

@IBOutlet weak var img: UIImageView! 


@IBOutlet weak var imgHeightConstraint: NSLayoutConstraint! 


var isExpanded:Bool = false 
    { 
    didSet 
    { 
     if !isExpanded { 
      self.imgHeightConstraint.constant = 0.0 

     } else { 
      self.imgHeightConstraint.constant = 128.0 
     } 
    } 
} 

} 

View Controller

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return 21 
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell:ExpandableCell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell") as! ExpandableCell 
    cell.img.image = UIImage(named: imgs[indexPath.row]) 
    cell.isExpanded = false 
    return cell 
} 

// TableView Delegate methods 
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
    print(indexPath.row) 
    guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell 
     else { return } 

     UIView.animate(withDuration: 0.3, animations: { 
      let offset: CGPoint = self.tableView.contentOffset 

      tableView.beginUpdates() 
      cell.isExpanded = !cell.isExpanded 

      self.tableView.layer.removeAllAnimations() 
      self.tableView.setContentOffset(offset, animated: false) 
      tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.top, animated: true) 
      tableView.endUpdates() 



     }) 

    } 

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { 
    guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell 
     else { return } 
    UIView.animate(withDuration: 0.3, animations: { 
     tableView.beginUpdates() 
     cell.isExpanded = false 
     tableView.endUpdates() 
    }) 
} 

Все отлично работает для нескольких первых строк, после прокрутки вниз, клетки не ведут себя должным образом, кажется, что она прокручивается в верхней части, то пропадает изображение.

Я знаю, что это может иметь какое-то отношение к тому, чтобы не хранить значение boolean isExpanded в каком-то массиве, чтобы отслеживать его, но, тем не менее, я думаю, что это неправильно с обновлением TableView.

enter image description here

EDIT

Sulthan ответ помог мне много, но проблема с прокруткой к вершине, особенно при касании самые низкие клетки продолжает упорно.

Пробовал этот UITableView scrolls to top when reloading cells with changing cell heights

с estimatedRowHeight до ближайшего значения, но это не решает мою проблему в случае вспененных клеток.

У кого-нибудь есть идея, как его исправить?

+0

Клетки повторно. Вы должны сохранить 'isExpanded' вне своих представлений, в свою модель. Например. создайте 'Set' с расширенными строками. – Sulthan

+0

создайте модель ячейки (struct или class) для каждой ячейки таблицы и сохраните имя изображения, и если она будет расширена в этой модели, а затем в массиве. то он находится в одном месте. – muescha

ответ

1

Start, сохраняя расширенные клетки в контроллере:

var expandedRows = Set<Int>() 

, которые их используют:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell:ExpandableCell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell") as! ExpandableCell 
    cell.img.image = UIImage(named: imgs[indexPath.row]) 

    // this! 
    cell.isExpanded = self.expandedRows.contains(indexPath.row) 
    return cell 
} 

И при изменении расширенного состояния:

if self.expandedRows.contains(indexPath.row) { 
    self.expandedRows.remove(indexPath.row) 
    cell.isExpanded = false 
} else { 
    self.expandedRows.add(indexPath.row) 
    cell.isExpanded = true 
} 

Конечно, есть это еще одна возможность. Так как ваши клетки расширяются, когда они выбраны, вы можете просто реагировать на это событие в камере:

class ExpandableCell : UITableViewCell { 
    override func setSelected(_ selected: Bool, animated: Bool) { 
     super.setSelected(selected, animated: animated) 

     self.imgHeightConstraint.constant = selected ? 128.0 : 0.0 
    } 
} 

Полный пример кода:

class ExpandableCell : UITableViewCell { 
    var label: UILabel? 
    var expandableView: UIView? 
    var heightConstraint: NSLayoutConstraint? 

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

     self.initViews() 
    } 

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
     super.init(style: style, reuseIdentifier: reuseIdentifier) 

     self.initViews() 
    } 

    private func initViews() { 
     self.contentView.clipsToBounds = true 

     let label = UILabel() 
     label.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin] 
     label.frame = CGRect(x: 0, y: 0, width: self.contentView.frame.size.width, height: 44) 

     self.label = label 
     self.contentView.addSubview(label) 

     let expandableView = UIView() 
     expandableView.translatesAutoresizingMaskIntoConstraints = false 
     self.contentView.addSubview(expandableView) 

     let horizontalConstraints = NSLayoutConstraint.constraints(
      withVisualFormat: "H:|-0-[view]-0-|", options: [], metrics: nil, views: ["view": expandableView] 
     ) 
     NSLayoutConstraint.activate(horizontalConstraints) 

     let verticalConstraints = NSLayoutConstraint.constraints(
      withVisualFormat: "V:|-44-[view][email protected]|", options: [], metrics: nil, views: ["view": expandableView] 
     ) 
     NSLayoutConstraint.activate(verticalConstraints) 

     let heightConstraint = NSLayoutConstraint(
      item: expandableView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0 
     ) 
     NSLayoutConstraint.activate([heightConstraint]) 

     self.expandableView = expandableView 
     self.heightConstraint = heightConstraint 
    } 

    var isExpanded:Bool = false { 
     didSet { 
      self.heightConstraint?.constant = self.isExpanded ? 128 : 0 
     } 
    } 
} 

class ViewController: UITableViewController { 
    var expandedRows: Set<Int> = Set() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     self.tableView.register(ExpandableCell.self, forCellReuseIdentifier: "ExpandableCell") 
     self.tableView.rowHeight = UITableViewAutomaticDimension 
     self.tableView.allowsMultipleSelection = false 
    } 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return 21 
    } 

    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { 
     return 44.0 
    } 

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell", for: indexPath) as! ExpandableCell 

     cell.label!.text = "Cell at row: \(indexPath.row)" 
     cell.isExpanded = expandedRows.contains(indexPath.row) 
     return cell 
    } 

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
     print("Selecting: \(indexPath.row)") 
     self.expandedRows.insert(indexPath.row) 

     if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell { 
      cell.isExpanded = true 
     } 

     self.tableView.beginUpdates() 
     self.tableView.endUpdates() 
    } 

    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { 
     print("Deselecting: \(indexPath.row)") 
     self.expandedRows.remove(indexPath.row) 

     if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell { 
      cell.isExpanded = false 
     } 

     self.tableView.beginUpdates() 
     self.tableView.endUpdates() 
    } 
} 
+0

Первый подход не анимируется правильно, вы могли бы попробовать его и сказать, работает ли он для вас? Второй подход вообще не оживляет. В любом случае спасибо за вашу помощь, все еще можно попробовать и, возможно, решить проблемы? – DCDC

+0

@DCDC Как вы начинаете анимацию? Достаточно вызвать 'tableView.beginUpdates()', за которым следует 'tableView.endUpdates()'. – Sulthan

+0

Это почти работает, но в любое время я нажимаю на ячейку, которая находится под экраном (нужно прокручивать ее вниз), она возвращается к вершине tableView, может быть, это что-то не так с reshreshing tableView, не могли бы вы попробовать? – DCDC

Смежные вопросы