这是一个简单的iOS swift项目,旨在介绍如何实现可收起和展开的table section,并且,项目不需要main storyboard,XIB,注册nib等,只需要纯的Swfit代码!
项目源代码:https://github.com/jeantimex/ios-swift-collapsible-table-section
如果你希望获得Swift 3.0的代码,可以在migrate-to-swift-3.0分支里找到,最终将会汇入master分支。
效果假设我们有如下的数据,它已经按照不同的section进行组织和整理,每个section都是一个Section
结构(或对象):
struct Section { var name: String! var items: [String]! var collapsed: Bool! init(name: String,items: [String],collapsed: Bool = false) { self.name = name self.items = items self.collapsed = collapsed }}var sections = [Section]()sections = [ Section(name: "Mac",items: ["MacBook","MacBook Air","MacBook Pro","iMac","Mac Pro","Mac mini","AccessorIEs","OS X El CAPItan"]),Section(name: "iPad",items: ["iPad Pro","iPad Air 2","iPad mini 4","AccessorIEs"]),Section(name: "iPhone",items: ["iPhone 6s","iPhone 6","iPhone SE","AccessorIEs"])]
collapsed
表示当前的section是否被收起或展开,默认下是false
,即展开。
根据苹果 API reference,我们应该使用UItableVIEwheaderfooterVIEw
. 让我们创建一个section header的类来继承它,我们把这个section header类起名为CollapsibletableVIEwheader
:
class CollapsibletableVIEwheader: UItableVIEwheaderfooterVIEw { let TitleLabel = UILabel() let arrowLabel = UILabel() overrIDe init(reuseIDentifIEr: String?) { super.init(reuseIDentifIEr: reuseIDentifIEr) contentVIEw.addSubvIEw(TitleLabel) contentVIEw.addSubvIEw(arrowLabel) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }}
当用户点击section header的时候我们需要收起或者展开这个section,为了实现这样的效果,让我们借用一下UITapGestureRecognizer
. 同时我们需要将这个tap事件通知给table vIEw并让它来更新section的collapsed
值。
protocol CollapsibletableVIEwheaderDelegate { func toggleSection(header: CollapsibletableVIEwheader,section: Int)}class CollapsibletableVIEwheader: UItableVIEwheaderfooterVIEw { var delegate: CollapsibletableVIEwheaderDelegate? var section: Int = 0 ... overrIDe init(reuseIDentifIEr: String?) { super.init(reuseIDentifIEr: reuseIDentifIEr) ... addGestureRecognizer(UITapGestureRecognizer(target: self,action: #selector(CollapsibletableVIEwheader.tapheader(_:)))) } ... func tapheader(gestureRecognizer: UITapGestureRecognizer) { guard let cell = gestureRecognizer.vIEw as? CollapsibletableVIEwheader else { return } delegate?.toggleSection(self,section: cell.section) } func setCollapsed(collapsed: Bool) { // Animate the arrow rotation (see Extensions.swf) arrowLabel.rotate(collapsed ? 0.0 : CGfloat(M_PI_2)) }}
既然我们不用任何storyboard或者XIB,如何实现自动布局呢?答案是运用NSLayoutConstraint
的constraintsWithVisualFormat
函数。
overrIDe init(reuseIDentifIEr: String?) { ... // arrowLabel must have fixed wIDth and height arrowLabel.wIDthAnchor.constraintEqualToConstant(12).active = true arrowLabel.heightAnchor.constraintEqualToConstant(12).active = true TitleLabel.translatesautoresizingMaskIntoConstraints = false arrowLabel.translatesautoresizingMaskIntoConstraints = false}overrIDe func layoutSubvIEws() { super.layoutSubvIEws() ... let vIEws = [ "TitleLabel" : TitleLabel,"arrowLabel" : arrowLabel,] contentVIEw.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( "H:|-20-[TitleLabel]-[arrowLabel]-20-|",options: [],metrics: nil,vIEws: vIEws )) contentVIEw.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( "V:|-[TitleLabel]-|",vIEws: vIEws )) contentVIEw.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( "V:|-[arrowLabel]-|",vIEws: vIEws ))}第三步. UItableVIEw DataSource 以及 Delegate
首先,sections的数量为sections.count
:
overrIDe func numberOfSectionsIntableVIEw(tableVIEw: UItableVIEw) -> Int { return sections.count}
每个section里面cell的数量为:
overrIDe func tableVIEw(tableVIEw: UItableVIEw,numberOfRowsInSection section: Int) -> Int { return sections[section].items.count}
接下来使用tableVIEw的vIEwForheaderInSection
函数来渲染我们的section header:
overrIDe func tableVIEw(tableVIEw: UItableVIEw,vIEwForheaderInSection section: Int) -> UIVIEw? { let header = tableVIEw.dequeueReusableheaderfooterVIEwWithIDentifIEr("header") as? CollapsibletableVIEwheader ?? CollapsibletableVIEwheader(reuseIDentifIEr: "header") header.TitleLabel.text = sections[section].name header.arrowLabel.text = ">" header.setCollapsed(sections[section].collapsed) header.section = section header.delegate = self return header}
普通的cell就很简单了,没什么好说的:
overrIDe func tableVIEw(tableVIEw: UItableVIEw,cellForRowAtIndexPath indexPath: NSIndexPath) -> UItableVIEwCell { let cell = tableVIEw.dequeueReusableCellWithIDentifIEr("cell") as UItableVIEwCell? ?? UItableVIEwCell(style: .Default,reuseIDentifIEr: "cell") cell.textLabel?.text = sections[indexPath.section].items[indexPath.row] return cell}最后一步. 如何收起和展开?
思路超级简单!如果该section的collapsed
值为true
,我们就将这个section里所有cell的高度都设为0
,否则为 44.0
!
overrIDe func tableVIEw(tableVIEw: UItableVIEw,heightForRowAtIndexPath indexPath: NSIndexPath) -> CGfloat { return sections[indexPath.section].collapsed! ? 0 : 44.0}
切换收起和展开的函数如下:
extension CollapsibletableVIEwController: CollapsibletableVIEwheaderDelegate { func toggleSection(header: CollapsibletableVIEwheader,section: Int) { let collapsed = !sections[section].collapsed // Toggle collapse sections[section].collapsed = collapsed header.setCollapsed(collapsed) // Adjust the height of the rows insIDe the section tableVIEw.beginUpdates() for i in 0 ..< sections[section].items.count { tableVIEw.reloadRowsAtIndexPaths([NSIndexPath(forRow: i,inSection: section)],withRowAnimation: .automatic) } tableVIEw.endUpdates() }}
注意到我们不是简单的重绘整个section,实际上我们只需要重绘section里的所有cell就好,这样做的好处是避免了section header因重绘时闪烁的效果,最重要是的可以让我们更平滑地处理我们想要的动画效果,例如旋转那个箭头,改变背景颜色等等。
好了就这么多吧,如果你很感兴趣,请参考源码。
更多的关于table section收起和展开的项目有时候你可能想要在grouped-style的table里实现section的收起和展开,我写了另外一个demo,https://github.com/jeantimex/ios-swift-collapsible-table-section-in-grouped-section. 实现的方法其实很类似。
作者: Yong Su @ Box Inc.
总结以上是内存溢出为你收集整理的如何实现可收起和展开的Table Section全部内容,希望文章能够帮你解决如何实现可收起和展开的Table Section所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)