简体   繁体   English

按下tableView部分时如何在UITableViewHeaderFooterView中触发UIImageView animation?

[英]How to trigger UIImageView animation in a UITableViewHeaderFooterView when pressing on a tableView section?

I want to create an expandable/collapsable tableView cells behaviour with a custom header view from xib using UITableViewHeaderFooterView .我想使用UITableViewHeaderFooterView使用来自 xib 的自定义 header 视图创建可扩展/可折叠的tableView单元格行为。

I have the following CustomHeaderView xib setup: UILabel, UIButton (to press on the header and trigger expandable/collapsable behaviour and chevron as UIImageView to represent a current section state: I have the following CustomHeaderView xib setup: UILabel, UIButton (to press on the header and trigger expandable/collapsable behaviour and chevron as UIImageView to represent a current section state:

Here is how a CustomHeaderView class looks.这是CustomHeaderView class 的外观。 It has some outlets, method for rotating the chevron and simple protocol to tell my ViewController that certain section was tapped (button's tag == section)它有一些出口、旋转chevron的方法和简单的protocol来告诉我的ViewController某个section被点击(按钮的标签 == 部分)

import UIKit

 protocol HeaderViewDelegate: AnyObject {
    func expandedSection(button: UIButton)
 }

class CustomHeaderView: UITableViewHeaderFooterView {

weak var delegate: HeaderViewDelegate?

@IBOutlet weak var lable: UILabel!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var headerButton: UIButton!

func configure(title: String, section: Int) {
    lable.text = title
    headerButton.tag = section
}

func rotateImage(_ expanded: Bool) {
    if expanded {
        UIView.animate(withDuration: 0.3) {
            self.imageView.transform = CGAffineTransform(rotationAngle: .pi / 2)
        }
    } else {
        UIView.animate(withDuration: 0.3) {
            self.imageView.transform = .identity
        }
    }
}

@IBAction func tapHeader(_ sender: UIButton) {
    delegate?.expandedSection(button: sender)
}
}

Here is how my ViewController looks like:这是我的 ViewController 的样子:

import UIKit

struct ExpandedModel {
   var isExpanded: Bool
   let title: String
   let array: [String]
}

class TableViewController: UITableViewController {

   let headerID = String(describing: CustomHeaderView.self)
   var arrayOfData = [ExpandedModel]()

override func viewDidLoad() {
    super.viewDidLoad()
    
    arrayOfData = [
        ExpandedModel(isExpanded: true, title: "Words", array: ["One", "Two", "Three", "Four", "Five"]),
        ExpandedModel(isExpanded: true, title: "Numbers", array: ["6", "7", "8", "9", "10"])
    ]
    tableViewConfig()
}

private func tableViewConfig() {
    let nib = UINib(nibName: headerID, bundle: nil)
    tableView.register(nib, forHeaderFooterViewReuseIdentifier: headerID)
}

override func numberOfSections(in tableView: UITableView) -> Int {
    arrayOfData.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if !arrayOfData[section].isExpanded {
        return 0
    } else {
        return arrayOfData[section].array.count
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell", for: indexPath) as! DataTableViewCell
    cell.label.text = arrayOfData[indexPath.section].array[indexPath.row]
    return cell
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID) as! CustomHeaderView
    
    header.configure(title: arrayOfData[section].title, section: section)
    header.rotateImage(arrayOfData[section].isExpanded)
    header.delegate = self
    return header
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return tableView.estimatedSectionHeaderHeight
}

override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return tableView.estimatedSectionFooterHeight
}
}

 extension TableViewController: HeaderViewDelegate {
    func expandedSection(button: UIButton) {
       let section = button.tag
       let indexPaths = (0..<(arrayOfData[section].array.count)).map { IndexPath(row: $0, section: section)}
    
    arrayOfData[section].isExpanded.toggle()
    
    if !arrayOfData[section].isExpanded {
        tableView.beginUpdates()
        tableView.deleteRows(at: indexPaths, with: .fade)
        tableView.endUpdates()
    } else {
        tableView.beginUpdates()
        tableView.insertRows(at: indexPaths, with: .fade)
        tableView.endUpdates()
    }
}
}

The main goal is ok - I can collapse and expand cells.主要目标是好的 - 我可以折叠和展开单元格。 But the problem is how to animate the chevron in CustomHeaderView ?但问题是如何为CustomHeaderView中的chevron设置动画?

If I'll use a reloading section method, then the chevron animation will be skipped:如果我将使用重新加载部分方法,则将跳过chevron animation:

tableView.reloadSections(IndexSet(integer: section), with: .none)

If I will add a delay with DispatchQueue.main.asyncAfter , it will be animated in, but skipped when out:如果我将使用DispatchQueue.main.asyncAfter添加延迟,它将被动画化,但在退出时会被跳过:

        func rotateImage(_ expanded: Bool) {
        if expanded {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                UIView.animate(withDuration: 0.2) {
                self.imageView.transform = CGAffineTransform(rotationAngle: .pi / 2)
                }
            }
        } else {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                UIView.animate(withDuration: 0.2) {
                self.imageView.transform = .identity
                }
            }
        }
    }

What is a most sufficient way to achieve a proper chevron animation?什么是获得适当chevron animation 的最充分方法?

Using your first block of code, do you get the animation you want if you change your expandedSection(button: UIButton) func to this:使用你的第一个代码块,如果你改变你的expandedSection(button: UIButton)函数,你得到你想要的animation:

extension TableViewController: HeaderViewDelegate {
    func expandedSection(button: UIButton) {
        let section = button.tag
        let indexPaths = (0..<(arrayOfData[section].array.count)).map { IndexPath(row: $0, section: section)}
        
        arrayOfData[section].isExpanded.toggle()

        // get a reference to the section's header view    
        if let v = tableView.headerView(forSection: section) as? SomeCustomHeaderView {
            v.rotateImage(arrayOfData[section].isExpanded)
        }

        if !arrayOfData[section].isExpanded {
            tableView.beginUpdates()
            tableView.deleteRows(at: indexPaths, with: .fade)
            tableView.endUpdates()
        } else {
            tableView.beginUpdates()
            tableView.insertRows(at: indexPaths, with: .fade)
            tableView.endUpdates()
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM