UIScrollView привязка к позиции при прокрутке

Я пытаюсь реализовать вид прокрутки, который привязывается к точкам при прокрутке.

все сообщения здесь, которые я видел о привязке к точке "после", пользователь закончил перетаскивание прокрутки. Я хочу, чтобы он щелкнул во время перетаскивания.

до сих пор у меня есть это, чтобы остановить инерцию после перетаскивания, и она отлично работает:

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
      targetContentOffset.memory = scrollView.contentOffset
}

Я пробовал это, но не работает как хотелось:

    var scrollSnapHeight : CGFloat = myScrollView.contentSize.height/10

scrollViewDidScroll:

func scrollViewDidScroll(scrollView: UIScrollView) {
    let remainder : CGFloat = scrollView.contentOffset.y % scrollSnapHeight
    var scrollPoint : CGPoint = scrollView.contentOffset
    if remainder != 0 && scrollView.dragging
    {
        if self.lastOffset > scrollView.contentOffset.y //Scrolling Down
        {
            scrollPoint.y += (scrollSnapHeight - remainder)
            NSLog("scrollDown")
        }
        else //Scrolling Up
        {
            scrollPoint.y -= (scrollSnapHeight - remainder)
        }
        scrollView .setContentOffset(scrollPoint, animated: true)
    }
    self.lastOffset = scrollView.contentOffset.y;
}

2 ответов


этот подход позволяет включить / отключить scrollEnabled собственность UIScrollView.

когда scrollView прокручивается за пределами данного scrollSnapHeight, выберите scrollEnabled to false. Это остановит прокрутку. Затем снова включите прокрутку для следующего перетаскивания.

extension ViewController: UIScrollViewDelegate {

    func scrollViewDidScroll(scrollView: UIScrollView) {

        if scrollView.contentOffset.y > lastOffset + scrollSnapHeight {
            scrollView.scrollEnabled = false
        } else if scrollView.contentOffset.y < lastOffset - scrollSnapHeight {
            scrollView.scrollEnabled = false
        }
    }

    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {

        guard !decelerate else {
            return
        }

        setContentOffset(scrollView)
    }

    func scrollViewWillBeginDecelerating(scrollView: UIScrollView) {

        setContentOffset(scrollView)
    }
}

func setContentOffset(scrollView: UIScrollView) {

    let stopOver = scrollSnapHeight
    var y = round(scrollView.contentOffset.y / stopOver) * stopOver
    y = max(0, min(y, scrollView.contentSize.height - scrollView.frame.height))
    lastOffset = y

    scrollView.setContentOffset(CGPointMake(scrollView.contentOffset.x, y), animated: true)

    scrollView.scrollEnabled = true
}

Подкласс UIScrollView / UICollectionView

Это решение не требует, чтобы вы подняли палец, чтобы разомкнуть и работает во время прокрутки. Если вам это нужно для вертикальной прокрутки, а не горизонтальной прокрутки, просто замените x на y.

Set snapPoint к смещению содержимого, где вы хотите, чтобы центр привязки был.

Set snapOffset к радиусу вокруг точки, где вы хотите привязать к происходить.

Если вам нужно знать, если scrollView щелкнул, просто проверьте isSnapped переменной.

class UIScrollViewSnapping : UIScrollView {
    public var snapPoint: CGPoint?
    public var snapOffset: CGFloat?
    public var isSnapped = false

    public override var contentOffset: CGPoint {
        set {
            if let snapPoint = self.snapPoint,
                let snapOffset = self.snapOffset,
                newValue.x > snapPoint.x - snapOffset,
                newValue.x < snapPoint.x + snapOffset {
                self.isSnapped = true
                super.contentOffset = snapPoint
            }
            else {
                self.isSnapped = false
                super.contentOffset = newValue
            }
        }
        get {
            return super.contentOffset
        }
    }
}