ScrollView惯性效果手动,iOS,Swift

Posted

技术标签:

【中文标题】ScrollView惯性效果手动,iOS,Swift【英文标题】:ScrollView inertia effect manually, iOS, Swift 【发布时间】:2020-03-07 19:25:20 【问题描述】:

我有UICollectionView,我是从代码中拖出来的(不要问我为什么它很长:))。 我的代码运行良好:

func move(prevPoint: CGPoint, curPoint: CGPoint) 
    let xDiff = curPoint.x - prevPoint.x
    let yDiff = curPoint.y - prevPoint.y
    let xSign =  xDiff == 0 ? 1 : (xDiff / abs(xDiff))
    let ySign = yDiff == 0 ? 1 : (yDiff / abs(yDiff))

    let x = max(min(abs(xDiff), maxPickerStep), minPickerStep) * -xSign * xMultiplier
    let y = max(min(abs(yDiff), maxPickerStep), minPickerStep) * -ySign

    let offset = CGPoint(x: collectionView.contentOffset.x + x, y: collectionView.contentOffset.y)
    let cell = (collectionView.visibleCells.first as? ColorsCollectionViewCell)
    let innerOffset = cell?.colorCollectionView.contentOffset ?? .zero
    let inset = (cell?.colorCollectionView.contentInset.top ?? 0) * 2
    let innerYContentOffset = min(max(innerOffset.y + y, -inset), (cell?.colorCollectionView.contentSize.height ?? 0) - inset)

    cell?.colorCollectionView.contentOffset = CGPoint(x: innerOffset.x, y: innerYContentOffset)
    collectionView.contentOffset = offset

但是除了滚动之外,我想达到和UICollectionView一样的效果,当scrollView在用户拿开手指后惯性移动时。谢谢。

【问题讨论】:

【参考方案1】:

首先,我认为手动移动滚动视图肯定是我会避免的事情。 可能有一些更简单的东西可以满足您需要的行为。 因此,我强烈建议您和任何其他读者不要继续阅读这篇文章,而是继续尝试解决最初引导您到这里的问题。

您还可以在 Stack Overflow 上提出另一个问题,以获得帮助以避免您手动更新 scrollView 位置。


因此,如果您仍在阅读,this article 可能是实现真正感觉像 UIScrollView 的方法的方法。做任何其他事情可能看起来和感觉都很糟糕。

基本上它包括使用 UIKit Dynamics 来控制惯性。

因此,您可以创建一个符合 UIDynamicItem(具有非零 CGRect)的对象,并更改其中心而不是 scrollView contentOffset,而不是使用 UIDynamicAnimator 及其 UIDynamicBehavior 来设置惯性并在期间连接更改使用 UIDynamicBehavior 的 action block 将动画到 scrollView 中对应的 contentOffset。

假设您有一个 UIDynamicItem 项目和一个 UIDynamicAnimator 动画器,panGesture 识别器的处理将如下所示:

func handlGestureRecognizer(panGesture: UIPanGestureRecognizer) 

    switch panGesture.state 
    case .began:
        self.animator.removeAllBehaviors()
    case .changed:
        // Update scroll view position
        break
    case .ended:
        var velocity = panGesture.velocity(in: panGesture.view!)
        velocity.x = -velocity.x
        velocity.y = -velocity.y   
        // You probably need to check for out of bound velocity too, and also put velocity.x to 0 if the scroll is only scrolling vertically

        // This is done to just save the current content offset and then change it alongside the animation from this starting point         
        item.center = scrollView.contentOffset

        let decelerationBehavior = UIDynamicItemBehavior(items: [item])
        decelerationBehavior.addLinearVelocity(velocity, for: item)
        decelerationBehavior.resistance = 2.0


        decelerationBehavior.action = 
            // Connect the item center to the scroll contentOffset. Probably something like this:
            scrollView.contentOffset = item.center
        
        self.animator.addBehavior(decelerationBehavior)
    default:
        break
    

您不仅需要发挥行为的价值,并注意您在行为中投入的速度,还要特别注意查看边缘情况(例如,如果您滚动到最小值/最大值上)

PS:毕竟我已经写了,我仍然认为你应该强烈考虑不要这样做,而是使用标准的 scrollView 滚动,避免手动更新。

【讨论】:

感谢您的回答@Enricoza,我稍微修改了您的解决方案(添加了resistance)并实现了预期的行为。谢谢!) @TabulaRasa 是的,我忘了添加它...感谢您指出这一点,我已经编辑了答案以供将来参考。【参考方案2】:

您可以尝试使用 decelerationRate 看看它是否满足您的需求。

 collectionView.decelerationRate = UIScrollView.DecelerationRate(rawValue: 1)

【讨论】:

以上是关于ScrollView惯性效果手动,iOS,Swift的主要内容,如果未能解决你的问题,请参考以下文章

ScrollView去除顶部下拉的时候半月牙阴影(惯性)

ScrollView去除顶部下拉的时候半月牙阴影(惯性)

android ScrollView 滑动特效 怎么做成iphone那样有惯性弹性!

Android ScrollView在滚动中调用scrollTo(0,0)回到顶部无效

(转载) Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

(转) cocos 里面scrollView一些方法