【问题标题】:Reusable UITableHeaderFooterView Loose ImageView Orientation State可重用的 UITableHeaderFooterView 松散的 ImageView 方向状态
【发布时间】:2019-01-31 11:52:54
【问题描述】:

我有一个可扩展的UITableView,具有特定的单元格、页眉和页脚高度。当用户点击标题时,单元格开始显示在其下方(部分展开)。当用户再次点击时,部分会折叠。

我的问题是当用户点击标题时,标题变为绿色,箭头 (UIImageView) 的方向发生变化。当我不使用 dequeueReusableHeaderFooterView 时,一切正常,但是当我重用标题时,绿色标题和箭头方向在点击或滚动时看起来不像预期的那样。

在下图中,纽约的标题颜色看起来不错,但箭头方向错误。同样是曼哈顿,标题已展开,但未显示为绿色且未显示正确的UIImageView 方向。

P.S:我知道这已经被问过很多次了,但我不知道哪个是正确的方法。

标题视图类:

protocol ExpandableHeaderViewDelegate {
func toggleSection(header: DistrictTableViewHeader, section: Int)
}

class DistrictTableViewHeader: UITableViewHeaderFooterView {
var delegate: ExpandableHeaderViewDelegate?
var section: Int!

let nameLabel: UILabel = {
   let l = UILabel()
    l.textColor = Color.DistrictsPage.headerTextColor
    return l
}()

private let arrowImage: UIImageView = {
  let i = UIImageView()
    let image = UIImage(named: "ileri")?.withRenderingMode(UIImage.RenderingMode.alwaysTemplate)
    i.image = image
    i.contentMode = .scaleAspectFit
    return i
}()
var isColapsed: Bool!{
    didSet{
        layoutSubviews()
    }
}

override init(reuseIdentifier: String?) {

    super.init(reuseIdentifier: reuseIdentifier)
    self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(selectHeaderAction)))
    nameLabel.translatesAutoresizingMaskIntoConstraints = false
    nameLabel.font = UIFont.systemFont(ofSize: 22)
    nameLabel.textColor = Color.DistrictsPage.headerTextColor
    contentView.addSubview(nameLabel)
    nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
    nameLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 15).isActive = true

    arrowImage.tintColor =  UIColor(red:0.32, green:0.36, blue:0.36, alpha:1.0)
    arrowImage.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(arrowImage)
    arrowImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
    arrowImage.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20).isActive = true
    arrowImage.widthAnchor.constraint(equalToConstant: 20).isActive = true

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

@objc func selectHeaderAction(gestureRecognizer: UITapGestureRecognizer) {
    let cell = gestureRecognizer.view as! DistrictTableViewHeader
    self.isColapsed = !isColapsed
    if(!isColapsed){
        let degrees : Double = 90 //the value in degrees
        UIView.animate(withDuration: 0.5) { [weak self] in
            self?.nameLabel.textColor = Color.Common.garantiLightGreen
            self?.arrowImage.tintColor = Color.Common.garantiLightGreen
            self?.arrowImage.rotate(CGFloat(degrees * .pi/180))
            self?.contentView.backgroundColor = UIColor(red:0.97, green:0.97, blue:0.97, alpha:1.0)
        }
    }else{
        let degrees : Double = 0 //the value in degrees
        UIView.animate(withDuration: 0.5) { [weak self] in
            self?.nameLabel.textColor = Color.DistrictsPage.headerTextColor
            self?.arrowImage.tintColor = UIColor.black
            self?.arrowImage.rotate(CGFloat(degrees * .pi/180))
            self?.contentView.backgroundColor = UIColor.white
        }
    }
    delegate?.toggleSection(header: self, section: cell.section)
}

func customInit(title: String, section: Int, delegate: ExpandableHeaderViewDelegate) {
    self.nameLabel.text = title
    self.nameLabel.accessibilityIdentifier = title
    self.section = section
    self.delegate = delegate
}

override func layoutSubviews() {
    super.layoutSubviews()
    self.contentView.backgroundColor = UIColor.white

}

}

我如何初始化标头:

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 60
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let header: DistrictTableViewHeader = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerId) as! DistrictTableViewHeader
    //let header = DistrictTableViewHeader()

    header.isColapsed = !self.cities[section].isExpanded
    header.customInit(title: self.cities[section].name, section: section, delegate: self)
    return header
}

我如何展开/折叠:

func toggleSection(header: DistrictTableViewHeader, section: Int) {
    self.cities[section].isExpanded = !self.cities[section].isExpanded
    let contentOffset = self.tableView.contentOffset
    self.tableView.reloadData()

}

编辑: 对于 UITableView 大师,我还添加了一个示例项目 :) 示例项目链接:

https://github.com/emreond/tableViewLayoutIssue

【问题讨论】:

    标签: ios swift uitableview


    【解决方案1】:

    将可重用视图出列后,您必须重置所有可能发生的更改。

    在这种情况下,您正在设置header.isColapsed,但这不会重置它需要的所有视图状态。 selectHeaderAction 中的视图状态更改代码也需要在视图重用时调用。

    做正确的事需要一点重构。更改 isColapse 设置器以执行更多操作:

    var isColapsed: Bool!{
      didSet{
         if(!isColapsed){
            let degrees : Double = 90 //the value in degrees
            self?.nameLabel.textColor = Color.Common.garantiLightGreen
            self?.arrowImage.tintColor = Color.Common.garantiLightGreen
            self?.arrowImage.rotate(CGFloat(degrees * .pi/180))
            self?.contentView.backgroundColor = UIColor(red:0.97, green:0.97, blue:0.97, alpha:1.0)
         }else{
            let degrees : Double = 0 //the value in degrees
            self?.nameLabel.textColor = Color.DistrictsPage.headerTextColor
            self?.arrowImage.tintColor = UIColor.black
            self?.arrowImage.rotate(CGFloat(degrees * .pi/180))
            self?.contentView.backgroundColor = UIColor.white
          }
          layoutSubviews()
      }
    }
    

    并让轻敲手势少做:

    @objc func selectHeaderAction(gestureRecognizer: UITapGestureRecognizer) {
        let cell = gestureRecognizer.view as! DistrictTableViewHeader
        UIView.animate(withDuration: 0.5) { [weak self] in
            self.isColapsed = !isColapsed
        }
        delegate?.toggleSection(header: self, section: cell.section)
    }
    

    我认为应该可以解决它。告诉我它是否有效。


    你做错了旋转。添加一个 CAAnimation 很酷,但是当视图被重用时你不能轻易取消它。相反,只需更改 transform 属性,让 UIView.animate 块处理更高级别的动画。

    func rotate(_ toValue: CGFloat) {
      self.transform = CGAffineTransform.init(rotationAngle: toValue)
    }
    

    接下来,您将重新加载表格,该表格正在取消您想要执行的所有动画。

     func toggleSection(header: DistrictTableViewHeader, section: Int) {
        self.cities[section].isExpanded = !self.cities[section].isExpanded
      let count = self.cities[section].districts.count
      let indexPaths:[IndexPath] = (0..<count).map{ IndexPath.init(row: $0, section: section) }
      if self.cities[section].isExpanded {
        self.tableView.insertRows(at: indexPaths, with: .automatic);
      }else{
        self.tableView.deleteRows(at: indexPaths, with: .automatic);
      }
    }
    

    【讨论】:

    • 当我点击标题时,有时它会旋转箭头,但通常不会旋转箭头。
    • 手势是否被触发。苹果建议您不要将手势附加到单个视图 - developer.apple.com/library/archive/documentation/WindowsViews/…
    • 你问是否触发了 selectHeaderAction?是的,它被触发了。
    • 我添加了一个示例项目。
    • 实际上,我尝试过插入、删除行而不是重新加载数据,但这会导致一些错误。现在,当我滚动时,我有重复的标题,而且我需要滚动到扩展的石南花,但是插入,删除行它有一些 UI 错误(内容插入问题)。如果它对你有用,你能分享我一个示例项目吗?我来检查一下。感谢您的努力。
    猜你喜欢
    • 1970-01-01
    • 2011-03-15
    • 1970-01-01
    • 2012-03-07
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 1970-01-01
    相关资源
    最近更新 更多