Как сделать пользовательский индикатор прокрутки с помощью Swift?
У меня есть UITableView, который потенциально может иметь много строк (импорт контактов), и я ищу, чтобы реализовать пользовательский индикатор прокрутки, похожий на то, что имеет Snapchat. Две основные цели заключаются в следующем:
Когда вы прокручиваете просмотр таблицы, индикатор прокрутки перемещается вниз / вверх на правильную величину (и не превышает верх или низ таблицы).
Когда вы перетаскиваете индикатор прокрутки, он не только следует за вашим пальцем, но и прокручивает таблицу до нужного количества.
Я пытался использовать разные расчеты для суммы прокрутки, но я не могу понять, что это правильно. Я работал над примером приложения (просто содержащим имена в виде таблицы), и я могу заставить его работать нормально, но когда я переношу код в более крупный вид таблицы, он не будет работать должным образом.
Я создал собственное представление для моего индикатора прокрутки, которое представляет собой просто представление с меткой, которая изменяется в зависимости от буквы имени в ячейке:
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%, что он делает / почему он работает в моем демонстрационном приложении, а не в реальном. Я применил другое число и расчеты, но все еще не могу понять, как это правильно.
Любая помощь или понимание будет высоко ценится.