iOS滚动视图tableview,collectionview

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
}
}
上一篇下一篇

猜你喜欢

热点阅读