Swift在TableView中自定义索引IndexView
2017-12-27 本文已影响130人
向日葵的夏天_summer
效果图
IndexView.gif过程
思路:
自定义tableView的IndexView实现方式有两种:第一种,tableView中自带UITableIndexView,可以拿到这个view,然后进行处理; 第二种,就是自己定义一个view,将这个view添加上去;哈哈,我采用的是第二种方法,挺灵活的。
实现步骤:
1. 弄一个tableView的分类UITableView+IndexView,提供一个IndexView属性和一个显示IndexView的方法:
extension UITableView {
var indexView: CustomIndexView? {
set(view) {
objc_setAssociatedObject(self, &IndexViewParamKey, view, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &IndexViewParamKey) as? CustomIndexView
}
}
func customIndexView(indexTitles: [String]) {
indexView = CustomIndexView(indexTitles: indexTitles)
self.superview?.addSubview(indexView!)
//滑动到对应的section
indexView?.selectedSection = { [weak self] section in
self?.scrollToRow(at: IndexPath(item: 0, section: section), at: UITableViewScrollPosition.top, animated: false)
}
}
}
2.接下来就是自定义IndexView了,根据tableView中将要显示多少组,依次创建UILabel;
func setupLabels() {
let itemX: CGFloat = 0
var itemY: CGFloat = 0
for i in 0..<indexTitles.count {
let label = UILabel(frame: CGRect(x: itemX, y: itemY, width: itemWidth, height: itemHeight))
label.text = indexTitles[i]
label.tag = Tag + i
label.textAlignment = .center
label.textColor = UIColor.black
label.font = fontSize
addSubview(label)
itemY += itemHeight
if i == indexTitles.count - 1 {
self.frame.size.height = itemY
}
}
self.frame = CGRect(x: ScreenWidth - itemWidth, y: 0, width: itemWidth, height: itemY)
self.center.y = ScreenHeight * 0.5
}
3. 监听自定义的IndexView的touchesBegan,touchesMoved,touchesCancelled,touchesEnded方法:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationWithTouches(touches: touches)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationWithTouches(touches: touches)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationFinished()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationFinished()
}
4. 外部调用
//titlesArray 是section 对应的titles数组
tableView.customIndexView(indexTitles: titlesArray)
总结
所有的代码如下:
import UIKit
let ScreenWidth = UIScreen.main.bounds.size.width
let ScreenHeight = UIScreen.main.bounds.size.height
private var IndexViewParamKey = "IndexViewParamKey"
extension UITableView {
var indexView: CustomIndexView? {
set(view) {
objc_setAssociatedObject(self, &IndexViewParamKey, view, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &IndexViewParamKey) as? CustomIndexView
}
}
func customIndexView(indexTitles: [String]) {
indexView = CustomIndexView(indexTitles: indexTitles)
self.superview?.addSubview(indexView!)
indexView?.selectedSection = { [weak self] section in
self?.scrollToRow(at: IndexPath(item: 0, section: section), at: UITableViewScrollPosition.top, animated: false)
}
}
}
//MARK:- 自定义IndexView
class CustomIndexView: UIView {
typealias SimpleCallBackWithInt = (_ index: Int) -> ()
var selectedSection: SimpleCallBackWithInt?
private var tipLabel: UILabel!
private var indexTitles: [String] = [String]()
private var itemHeight: CGFloat = 30
private var itemWidth: CGFloat = 40
private var tipLabelWidth: CGFloat = 60
private var Tag = 11111
private let fontSize = UIFont.systemFont(ofSize: 16)
private let animationDuration: TimeInterval = 0.25
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect = CGRect.zero, indexTitles: [String]) {
self.init(frame: frame)
self.indexTitles = indexTitles
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupUI() {
backgroundColor = UIColor.lightGray
setupLabels()
setupTipLabel()
}
func setupTipLabel() {
tipLabel = UILabel(frame: CGRect(x: -tipLabelWidth - 20, y: 0, width: tipLabelWidth, height: tipLabelWidth))
tipLabel.font = fontSize
tipLabel.textAlignment = .center
tipLabel.textColor = UIColor.black
tipLabel.backgroundColor = UIColor.orange
tipLabel.layer.cornerRadius = tipLabelWidth * 0.5
tipLabel.layer.masksToBounds = true
tipLabel.alpha = 0
self.addSubview(tipLabel)
}
func setupLabels() {
let itemX: CGFloat = 0
var itemY: CGFloat = 0
for i in 0..<indexTitles.count {
let label = UILabel(frame: CGRect(x: itemX, y: itemY, width: itemWidth, height: itemHeight))
label.text = indexTitles[i]
label.tag = Tag + i
label.textAlignment = .center
label.textColor = UIColor.black
label.font = fontSize
addSubview(label)
itemY += itemHeight
if i == indexTitles.count - 1 {
self.frame.size.height = itemY
}
}
self.frame = CGRect(x: ScreenWidth - itemWidth, y: 0, width: itemWidth, height: itemY)
self.center.y = ScreenHeight * 0.5
}
func showTipsLabel(section: Int, centerY: CGFloat) {
guard let tipLabel = self.tipLabel else { return }
selectedSection?(section)
tipLabel.text = self.indexTitles[section]
tipLabel.center.y = centerY
UIView.animate(withDuration: animationDuration, animations: {
tipLabel.alpha = 1
})
}
func panAnimationWithTouches(touches: Set<UITouch>) {
guard let touch = touches.first else { return }
let point = touch.location(in: self)
for i in 0..<indexTitles.count {
if let label = self.viewWithTag(Tag + i) {
if label.frame.contains(point) {
showTipsLabel(section: i, centerY: label.center.y)
}
}
}
}
func panAnimationFinished() {
guard let tipLabel = self.tipLabel else { return }
UIView.animate(withDuration: animationDuration, animations: {
tipLabel.alpha = 0
})
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationWithTouches(touches: touches)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationWithTouches(touches: touches)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationFinished()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
panAnimationFinished()
}
deinit {
self.tipLabel.removeFromSuperview()
self.removeFromSuperview()
self.selectedSection = nil
}
}