如何使用Swift制作自定义滚动指示器?

时间:2018-01-05 18:50:34

标签: ios swift uitableview scrollbar indicator

我有一个UITableView,它有可能有很多行(导入联系人),我希望实现类似于Snapchat的自定义滚动指示器。两个基本目标如下:

  1. 滚动桌面视图时,滚动指示器向下/向上移动正确的数量(并且不超过桌面视图的顶部或底部)。

  2. 拖动滚动指示器时,它不仅会跟随您的手指,还会将桌面视图滚动到正确的数量。

  3. 我一直在尝试对滚动量使用不同的计算,但我似乎无法让它变得正确。我一直在做一个示例应用程序(只是在tableview中包含名称)的工作,我可以让它在那里工作正常但是当我将代码转移到更大的tableview时,它不能正常工作。

    我已经为我的滚动指示器创建了一个自定义视图,它基本上只是一个带有标签的视图,该视图会根据单元格中的名称字母而改变:

    class IndicatorView: UIView {
    
    @IBOutlet var contentView: UIView!
    @IBOutlet weak var letterLabel: UILabel!
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    private func commonInit() {
        Bundle.main.loadNibNamed("IndicatorView", owner: self, options: nil)
        contentView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(contentView)
        contentView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
        contentView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        contentView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
        contentView.layer.cornerRadius = 5
    }
    

    }

    以下是我使用的方法......

    scrollViewWillEndDragging:

     func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        //Get velocity and store in global variable 
        self.velocity = velocity.y
    }
    

    scrollViewDidScroll:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        scrollBar.becomeFirstResponder()
    
        let offset: CGPoint = scrollView.contentOffset
        var frame = self.scrollBar.frame
        var numberOfRows = 0
        for i in 0...friendsTableView.numberOfSections - 1 {
            let rows = friendsTableView.numberOfRows(inSection: i)
            numberOfRows += rows
        }
    
        //Calculate the amount of scroll
        let percentage = (44*CGFloat(numberOfRows) + 40)/friendsTableView.frame.height
    
    
        UIView.animate(withDuration: 0.0) {
            //Set the y value to new percentage
            frame.origin.y = 30 + offset.y + (offset.y/percentage)
    
            //Set label to correct letter
            let currentPoint = CGPoint(x: 30, y: frame.origin.y)
            if let indexPath = self.friendsTableView.indexPathForRow(at: currentPoint) {
                let letter = self.sectionHeaders[indexPath.section]
                self.scrollBar.letterLabel.text = letter
            }
    
            //Only expand the scroll indicator if the user scrolls fast enough
            if abs(self.velocity) > 1.5 {
                self.scrollBar.letterLabel.isHidden = false
                frame.size.width = 50
                frame.origin.x = self.screenWidth - 50
            }
    
            //Set the new y value of the scroll indicator 
            self.scrollBar.frame = frame
    
        }
    
    }    
    

    Custom Pan Gesture Recognizer:

     @objc func customDrag(_ sender: UIPanGestureRecognizer) {
        self.friendsTableView.bringSubview(toFront: scrollBar)
    
        //Only expand fully if the state is not ended
        if sender.state != .ended {
            var frame = self.scrollBar.frame
    
            //Expand the view fully
            self.scrollBar.letterLabel.isHidden = false
            frame.size.width = 100
            frame.origin.x = self.screenWidth - 100
            self.scrollBar.frame = frame
    
            //Get translation and track the content offset
            let translation = sender.translation(in: friendsTableView)
            let originalContentOffset = friendsTableView.contentOffset
    
            var numberOfRows = 0
            for i in 0...friendsTableView.numberOfSections - 1 {
                let rows = friendsTableView.numberOfRows(inSection: i)
                numberOfRows += rows
            }
    
            //Calculate the percentage of scroll and add the translation to the original content offset
            let percentage = (44*CGFloat(numberOfRows) + 50)/friendsTableView.frame.height
            let vertTranslation = (percentage*translation.y) + originalContentOffset.y
    
            //Set the content offset and the center of the scroll indicator
            friendsTableView.contentOffset = CGPoint(x: 0, y: (vertTranslation))
            self.scrollBar.center = CGPoint(x: self.screenWidth-50, y: self.scrollBar.center.y + (translation.y/percentage))
    
    
            sender.setTranslation(CGPoint.zero, in: friendsTableView)
    
        } else {
            //once the state is ended, collapse back to the smaller size 
            var frame = self.scrollBar.frame
            self.scrollBar.letterLabel.isHidden = false
            frame.size.width = 50
            frame.origin.x = self.screenWidth - 50
            self.scrollBar.frame = frame
        }  
    } 
    

    我找到了在另一个StackOverflow帖子上进行百分比计算的代码的基础知识,但不可否认,我不是100%确定它在做什么/为什么它在我的演示应用程序中工作而不是真实的。我已经应用了不同的数字和计算但仍然无法正确使用它。

    非常感谢任何帮助或见解。

0 个答案:

没有答案