Как сделать пользовательский индикатор прокрутки с помощью Swift?

У меня есть UITableView, который потенциально может иметь много строк (импорт контактов), и я ищу, чтобы реализовать пользовательский индикатор прокрутки, похожий на то, что имеет Snapchat. Две основные цели заключаются в следующем:

  1. Когда вы прокручиваете просмотр таблицы, индикатор прокрутки перемещается вниз / вверх на правильную величину (и не превышает верх или низ таблицы).

  2. Когда вы перетаскиваете индикатор прокрутки, он не только следует за вашим пальцем, но и прокручивает таблицу до нужного количества.

Я пытался использовать разные расчеты для суммы прокрутки, но я не могу понять, что это правильно. Я работал над примером приложения (просто содержащим имена в виде таблицы), и я могу заставить его работать нормально, но когда я переношу код в более крупный вид таблицы, он не будет работать должным образом.

Я создал собственное представление для моего индикатора прокрутки, которое представляет собой просто представление с меткой, которая изменяется в зависимости от буквы имени в ячейке:

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

    }

}    

Пользовательский распознаватель жестов Pan:

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

Я нашел основы для кода, который вычисляет процент в другом посте Stackru, но по общему признанию, я не уверен на 100%, что он делает / почему он работает в моем демонстрационном приложении, а не в реальном. Я применил другое число и расчеты, но все еще не могу понять, как это правильно.

Любая помощь или понимание будет высоко ценится.

0 ответов

Другие вопросы по тегам