UITableView重新加载节时内容插入更改

时间:2019-01-28 06:16:34

标签: ios swift uitableview

我有一个可展开的UITableView。当用户点击标题时,相关的单元格将显示一个动画(RowAnimation.Fade),然后UITableView滚动到该标题(展开的标题)。当用户再次点击该标题时,它将折叠。

我要实现的目标:我需要具有标题和单元格的可扩展UITableView。用户点击标题时,需要使用RowAnimation.Fade打开单元格,然后滚动到该标题。

奖金:另外,如果我可以在用户点击标题时使箭头动画化,但是我认为这会引起另一个错误,因为我们在同一线程(主线程)上运行了如此多的动画

我的问题是,当用户点击标题时,tableView内容插入项发生更改,整个标题移到负Y位置。因此发生了奇怪的动画。 (例如,标题看起来在单元格的中心)但是,动画结束后,一切看起来都正确。

func toggleSection(header: DistrictTableViewHeader, section: Int) {
self.selectedHeaderIndex = section
self.cities[section].isCollapsed = !self.cities[section].isCollapsed
let contentOffset = self.tableView.contentOffset
self.tableView.reloadSections(IndexSet(integer: section), with: UITableView.RowAnimation.fade)
self.tableView.scrollToRow(at: IndexPath(row: NSNotFound, section: section) /* you can pass NSNotFound to scroll to the top of the section even if that section has 0 rows */, at: UITableView.ScrollPosition.top, animated: true)
}

另外:我像下面那样设置标题和单元格的高度。

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

    header.customInit(title: self.cities[section].name, section: section, delegate: self,isColapsed: self.cities[section].isCollapsed,isSelectedHeader: section == selectedHeaderIndex ? true : false)
    return header
}

我的自定义headerView类:

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 willAnimate: Bool = false
var isColapsed: Bool!{
    didSet{
        expandCollapseHeader()
    }
}

private func expandCollapseHeader(){
    if(willAnimate){
        if(!self.isColapsed){
            let degrees : Double = 90 //the value in degrees
            self.nameLabel.textColor = Color.Common.garantiLightGreen
            self.arrowImage.tintColor = Color.Common.garantiLightGreen
            self.arrowImage.transform = CGAffineTransform.init(rotationAngle: 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.transform = CGAffineTransform.init(rotationAngle: CGFloat(degrees * .pi/180))
            self.contentView.backgroundColor = UIColor.white
        }
    }else{
        if(!isColapsed){
            let degrees : Double = 90 //the value in degrees
            self.nameLabel.textColor = Color.Common.garantiLightGreen
            self.arrowImage.tintColor = Color.Common.garantiLightGreen
            self.arrowImage.transform = CGAffineTransform.init(rotationAngle: 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.transform = CGAffineTransform.init(rotationAngle: CGFloat(degrees * .pi/180))
            self.contentView.backgroundColor = UIColor.white
        }
        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")
}
func rotate(_ toValue: CGFloat) {
    self.transform = CGAffineTransform.init(rotationAngle: toValue)
}
@objc func selectHeaderAction(gestureRecognizer: UITapGestureRecognizer) {
    let cell = gestureRecognizer.view as! DistrictTableViewHeader
    delegate?.toggleSection(header: self, section: cell.section)
}


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

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

}
}

在下图中,可以清楚地看到错误。当“某些数据”和“另一个城市”打开时,您点击“某些数据”。发生动画错误。 “另一个城市”越过其单元格,然后上升。应该做的是,“另一个城市”应留在其位置,然后在“某些数据”单元关闭时向上移动。 enter image description here 示例项目: https://github.com/emreond/tableViewLayoutIssue

2 个答案:

答案 0 :(得分:4)

经过数天的搜索和尝试,我发现将UITableViewStyle更改为该组即可达到目的。因此,我将初始化UITableView更改为

let tableView = UITableView.init(frame: CGRect.zero, style: .grouped)

除了滚动之外,我还需要添加CATransaction来捕获补全。

CATransaction.begin()
DispatchQueue.main.async {
self.tableView.beginUpdates()
CATransaction.setCompletionBlock {
    // Code to be executed upon completion
        self.tableView.scrollToRow(at: IndexPath(row: NSNotFound, section: section) /* you can pass NSNotFound to scroll to the top of the section even if that section has 0 rows */, at: UITableView.ScrollPosition.top, animated: true)
}
    self.tableView.reloadSections(IndexSet.init(integer: section), with: UITableView.RowAnimation.fade)
    self.tableView.endUpdates()
}
CATransaction.commit()
}

答案 1 :(得分:-1)

遇到相同的问题,您可以将其用作解决方法:

UIView.performWithoutAnimation {
    self.tableView.reloadSections(IndexSet(integer: section), with: .fade)
}

当然,您会丢失动画,但也会闪烁。