ios - UITableView 单元格中的旋转动画不起作用
问题描述
我正在尝试使其可扩展并制作一个简单的UITableView
旋转动画,UIImage
当我单击图像顺时针旋转 180° 时,当我再次单击单元格时,它将旋转 -180° 回到其正常状态,但动画不起作用并且第一次单击箭头不旋转时出现错误,我必须单击两次才能使其旋转为 gif。UITableViewCell
didSelectRowAt
cell
cell
测试模型:
struct Titles {
var opened = Bool()
var title = String()
var sectionData = [String]()
}
视图控制器视图:
class ViewControllerView: UIView {
var data = [Titles]()
override init(frame: CGRect) {
super.init(frame: frame)
layoutUI()
data = [
Titles(opened: false, title: "Title1", sectionData: ["Cell1", "Cell2", "Cell3"]),
Titles(opened: false, title: "Title2", sectionData: ["Cell1", "Cell2", "Cell3"]),
Titles(opened: false, title: "Title3", sectionData: ["Cell1", "Cell2", "Cell3"])
]
}
lazy var recipesTableView: UITableView = {
let recipesTableView = UITableView()
recipesTableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
recipesTableView.register(TableViewCellTwo.self, forCellReuseIdentifier: "TableViewCellTwo")
return recipesTableView
}()
}
extension ViewControllerView: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if data[section].opened == true {
return data[section].sectionData.count + 1
} else {
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.title.text = data[indexPath.section].title
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCellTwo", for: indexPath) as! TableViewCellTwo
cell.title.text = data[indexPath.section].sectionData[indexPath.row - 1]
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if data[indexPath.section].opened == true {
data[indexPath.section].opened = false
let section = IndexSet.init(integer: indexPath.section)
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
UIView.animate(withDuration: 1, animations: {
cell.arrowImage.transform = CGAffineTransform.init(rotationAngle: CGFloat.pi)
})
tableView.reloadSections(section, with: .none)
} else {
data[indexPath.section].opened = true
let section = IndexSet.init(integer: indexPath.section)
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
UIView.animate(withDuration: 1, animations: {
cell.arrowImage.transform = CGAffineTransform.identity
})
tableView.reloadSections(section, with: .none)
}
}
}
表视图单元:
class TableViewCell: UITableViewCell {
lazy var arrowImage: UIImageView = {
var arrow = UIImageView(image: UIImage(systemName: "arrowtriangle.down.fill"))
arrow.tintColor = .black
arrow.translatesAutoresizingMaskIntoConstraints = false
return arrow
}()
}
解决方案
首先,我们声明一个带有可用人字形方向的枚举。
enum ChevronDirection: Double {
case up = -180
case down = 0
}
我们还可以添加一个扩展来使处理弧度更容易
extension Double {
var degreesToRadians: CGFloat {
return CGFloat(self) * (CGFloat(Double.pi) / 180.0)
}
}
然后你应该创建一个 UITableViewHeaderFooterView 标题
class AnyNameHeader: UITableViewHeaderFooterView {
@IBOutlet weak var imgChevron: UIImageView!
var tapDelegate: DelegateToGetNotified?
var currentSection: Int!
func configure(_ text: String, section: Int, isExpanded: Bool) {
currentSection = section
self.set(isExpanded: isExpanded, animated: false)
}
func set(isExpanded: Bool, animated: Bool) {
if isExpanded {
setChevronDirection(ChevronDirection.up, animated: animated)
} else {
setChevronDirection(ChevronDirection.down, animated: animated)
}
}
func setChevronDirection(_ direction: ChevronDirection, animated: Bool) {
if animated {
UIView.animate(withDuration: 0.4, delay: 0.0, options: UIViewAnimationOptions(), animations: { [weak self] in
self?.imgChevron.transform = CGAffineTransform(rotationAngle: direction.rawValue.degreesToRadians)
}, completion: nil)
} else {
self.imgChevron.transform = CGAffineTransform(rotationAngle: direction.rawValue.degreesToRadians)
}
}
//Note: You can add your way to detect user tap over header for me i add a button over the header
@IBAction func headerAction() {
tapDelegate?.didTapHeader(sectionIndex: currentSection)
}
} // End of header
然后我们进入 View 控制器的 Final 部分
class MyViewController: UIViewController {
var expandedSectionIndex : Int? = nil {
didSet{
tableView.beginUpdates()
// Collapse previously expanded section
if let oldValue = oldValue {
tableView.deleteRows(at: indexPathsFor(section: oldValue), with: UITableViewRowAnimation.top)
if let header = tableView.headerView(forSection: oldValue) as? AnyNameHeader {
header.set(isExpanded: false, animated: true)
}
}
// Don't continue to Expand new section if already collapsing opened section
if let oldValue = oldValue, let sectionIndex = expandedSectionIndex, sectionIndex == oldValue {
expandedSectionIndex = nil
tableView.endUpdates()
return
}
// Expand new section
if let expandedSectionIndex = expandedSectionIndex {
tableView.insertRows(at: indexPathsFor(section: expandedSectionIndex), with: UITableViewRowAnimation.top)
if let header = tableView.headerView(forSection: expandedSectionIndex) as? AnyNameHeader {
header.set(isExpanded: true, animated: true)
}
}
tableView.endUpdates()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isExpandedSection(section: section) {
return data[section].sectionData.count
} else {
return 0
}
}
}
// MARK: Expanded Section
extension MyViewController {
/// Returns Indexpaths to be Inserted or Removed for a given section Index
fileprivate func indexPathsFor(section: Int) -> [IndexPath] {
var newIndexPaths = [IndexPath]()
for index in 0 ..< data[section].sectionData.count {
let newIndexPath = IndexPath(row: index , section: section)
newIndexPaths.append(newIndexPath)
}
return newIndexPaths
}
fileprivate func isExpandedSection(section: Int) -> Bool {
return expandedSectionIndex == section
}
}
extension MyViewController: DelegateToGetNotified {
func didTapHeader(sectionIndex: Int) {
expandedSectionIndex = sectionIndex
}
}
推荐阅读
- module - 如何更改 prestashop 模块中的元标题?
- html - 标题元素中的换行符
- tibco - 如何将 REST 触发器路径参数转换为活动输入参数
- python - tensorflow 停止,没有报错
- java - Hashmap 为所有键显示相同的值
- android - 空白应用程序没有显示任何错误
- datagridview - 按行更改 GridViewComboBox 列的数据源
- python - Running different models in one script in Tensorflow 1.9
- jasper-reports - Jasper 条形图:无法显示标签
- apache-spark - 如何使用 Spark 流将数据从 Kafka 插入到 Kudu