美文网首页iOS滚动视图tableview,collectionview
Swift在TableView中自定义索引IndexView

Swift在TableView中自定义索引IndexView

作者: 向日葵的夏天_summer | 来源:发表于2017-12-27 14:52 被阅读130次

    效果图

    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
    }
    }
    

    相关文章

      网友评论

        本文标题:Swift在TableView中自定义索引IndexView

        本文链接:https://www.haomeiwen.com/subject/zndugxtx.html