【问题标题】:Manually scrolling UIScrollView which is animated by UIViewPropertyAnimator手动滚动由 UIViewPropertyAnimator 动画的 UIScrollView
【发布时间】:2021-10-09 23:33:11
【问题描述】:

我有一个UIScrollView,它通过UIViewPropertyAnimator 设置其内容偏移量来自动滚动。自动滚动按预期工作,但我也希望能够中断动画以手动滚动。

UIViewPropertyAnimator 中的这个seems to be one of the selling points

...在动画完成之前动态修改动画

但是它似乎不能很好地与滚动视图配合使用(除非我在这里做错了什么)。

在大多数情况下,它是有效的。当我在动画期间滚动时,它会暂停,然后在减速结束后恢复。但是,当我向底部滚动时,它会像橡皮筋一样,好像它已经在内容的末尾(即使它不远)。滚动到顶部时这不是问题。

注意到这一点后,我检查了scrollView.contentOffset 的值,它似乎卡在最大值 + 橡皮筋偏移量上。我发现this question/answer 似乎表明这可能是UIViewPropertyAnimator 的错误。

我的代码如下:

private var maxYOffset: CGFloat = .zero
private var interruptedFraction: CGFloat = .zero

override func layoutSubviews() {
    super.layoutSubviews()
    
    self.maxYOffset = self.scrollView.contentSize.height - self.scrollView.frame.height
}

private func scrollToEnd() {
    let maxOffset = CGPoint(x: .zero, y: self.maxYOffset)
    let duration = (Double(self.script.wordCount) / Double(self.viewModel.wordsPerMinute)) * 60.0
    
    let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
        self.scrollView.contentOffset = maxOffset
    }
    animator.startAnimation()
    self.scrollAnimator = animator
}

extension UIAutoScrollView: UIScrollViewDelegate {

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        // A user initiated pan gesture will begin scrolling.
    
        if let scrollAnimator = self.scrollAnimator, self.viewModel.isScrolling {
            self.interruptedFraction = scrollAnimator.fractionComplete
            scrollAnimator.pauseAnimation()
        }
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if let scrollAnimator = self.scrollAnimator, self.viewModel.isScrolling {
            scrollAnimator.startAnimation()
        }
    }

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if let scrollAnimator = self.scrollAnimator, self.viewModel.isScrolling {
            scrollAnimator.startAnimation()
        }
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        switch scrollView.panGestureRecognizer.state {
        case .changed:
            // A user initiated pan gesture triggered scrolling.
                    
            if let scrollAnimator = self.scrollAnimator {
                let fraction = (scrollView.contentOffset.y - self.maxYOffset) / self.maxYOffset
                let boundedFraction = min(max(.zero, fraction), 1)
            
                scrollAnimator.fractionComplete = boundedFraction + self.interruptedFraction
            }
        default:
        break
        }
    }
}

这里有什么明显的错误吗?或者我可以采用任何解决方法来使滚动视图在向下滚动时停止橡皮筋?

【问题讨论】:

  • 从您的代码中不清楚您在哪里设置 self.viewModel.isScrolling = true

标签: ios swift uiscrollview uiviewpropertyanimator


【解决方案1】:

您可以添加点击手势识别器并调用此功能,

extension UIScrollView  {
    func stopDecelerating() {
        let contentOffset = self.contentOffset
        self.setContentOffset(contentOffset, animated: false)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多