当另一个 UIScrollView 滚动时停止动画 UIScrollView

Posted

技术标签:

【中文标题】当另一个 UIScrollView 滚动时停止动画 UIScrollView【英文标题】:Stop an animating UIScrollView when another UIScrollView is scrolled 【发布时间】:2015-07-04 08:47:36 【问题描述】:

假设我有多个滚动视图,并且我希望在任何给定时间只打开其中一个 (scrollView.contentOffset != 0)。因此,当scroll view 1 打开并且scroll view 2 滚动时,scroll view 1 应该以动画方式关闭。当我快速打开scroll view 1scroll view 2时出现问题;当这种情况发生时,scroll view 1 仍在减速,scroll view 2 的打开尝试强制 scroll view 1 关闭并中断动画,有时不会关闭。 解决此问题的一种方法是禁用滚动,直到滚动视图完成减速。但是,我正在寻找更无缝地处理这个问题的其他解决方案。 我试过scrollView.layer.removeAllAnimations()。这不会停止减速动画。我希望scroll view 1 的动画在scroll view 2 滚动时立即停止,然后scroll view 1 可以动画到contentOffset = 0

确定scroll view 是打开还是关闭。

func scrollViewDidScroll(scrollView: UIScrollView) 
    scrollView.bounces = scrollView.contentOffset.x > 20
    if scrollView.contentOffset.x < self.lastContentOffset && scrollView.contentOffset.x < 70 
        ifOpening = false
    
    else if scrollView.contentOffset.x > 5 
        ifOpening = true
    
    self.lastContentOffset = scrollView.contentOffset.x


scroll view 被拉近所有其他scroll view 时。

func scrollViewWillBeginDragging(scrollView: UIScrollView) 

    for eachScrollView in taskArrayScrollView
        if  eachScrollView != scrollView 
            eachScrollView.layer.removeAllAnimations()
            UIView.animateWithDuration(0.2,
                delay: 0.5,
                options: .CurveEaseIn ,
                animations:  eachScrollView.contentOffset.x = 0 ,
                completion: nil
            )
        
    

scroll view 捕捉到offset 0 或70

func scrollViewDidEndDragging(scrollViewa: UIScrollView, willDecelerate decelerate: Bool) 
    let intialContentOffset = scrollViewa.contentOffset.x
    var originalContentOffset: CGFloat
    var finalContentOffset: CGFloat
    var minOffset: CGFloat

    if intialContentOffset == boundOfScreen.width
        return
    

    if ifOpening
        minOffset = 20.0
        originalContentOffset = 0
        finalContentOffset = 70
    

    else 
        minOffset = 50.0
        originalContentOffset = 0
        finalContentOffset = 70
    

    if (!decelerate)
        if intialContentOffset < minOffset 
            UIView.animateWithDuration(0.2,
                delay: 0.1,
                options: .CurveEaseIn ,
                animations:  scrollViewa.contentOffset.x = originalContentOffset ,
                completion: 
                    finished in scrollViewa.userInteractionEnabled = true
                
            )
        
        else 
            UIView.animateWithDuration(0.2,
                delay: 0.1,
                options: .CurveEaseIn ,
                animations:  scrollViewa.contentOffset.x = finalContentOffset ,
                completion: 
                    finished in scrollViewa.userInteractionEnabled = true
                
            )
        
    



func scrollViewDidEndDecelerating(scrollViewb: UIScrollView) 
    let intialContentOffset = scrollViewb.contentOffset.x
    var originalContentOffset: CGFloat
    var finalContentOffset: CGFloat
    var minOffset: CGFloat
    //println("intialContentOffset: \(intialContentOffset)")

    if ifOpening
        minOffset = 20.0
        originalContentOffset = 0
        finalContentOffset = 70
        //println("dec: opening")
    

    else 
        minOffset = 50.0
        originalContentOffset = 0
        finalContentOffset = 70
        //println("dec: closing")
    


    if intialContentOffset < minOffset 
        UIView.animateWithDuration(0.2,
            delay: 0.1,
            options: .CurveEaseIn ,
            animations: scrollViewb.contentOffset.x = originalContentOffset ,
            completion: 
                finished in scrollViewb.userInteractionEnabled = true
            
        )
    
    else 
        UIView.animateWithDuration(0.2,
            delay: 0.1,
            options: .CurveEaseIn ,
            animations: scrollViewb.contentOffset.x = finalContentOffset ,
            completion: 
                finished in scrollViewb.userInteractionEnabled = true
            

        )
    

【问题讨论】:

【参考方案1】:

嗯...我找到了解决办法。我使用变量viewOpenCounter 来跟踪是否打开了另一个scroll view,如果是,则在完成动画后关闭当前正在动画的scroll view。不确定这是否有效。

func scrollViewDidScroll(scrollView: UIScrollView) 

    scrollView.bounces = scrollView.contentOffset.x > 20

    if scrollView.contentOffset.x < self.lastContentOffset && scrollView.contentOffset.x < 70 
        isOpening = false
    
    else if scrollView.contentOffset.x > 5 
        isOpening = true
        viewOpenCounter = true
    
    self.lastContentOffset = scrollView.contentOffset.x


func scrollViewWillBeginDragging(scrollView: UIScrollView) 
    if !viewOpenCounter 
        for eachScrollView in taskArrayScrollView 
            if  eachScrollView != scrollView 
                UIView.animateWithDuration(0.2,
                    delay: 0.5,
                    options: .CurveEaseIn ,
                    animations:  eachScrollView.contentOffset.x = 0 ,
                    completion: nil
                )
        
    

 func scrollViewDidEndDragging(scrollViewa: UIScrollView, willDecelerate decelerate: Bool) 

    viewOpenCounter = false

    let intialContentOffset = scrollViewa.contentOffset.x
    var originalContentOffset: CGFloat
    var finalContentOffset: CGFloat
    var minOffset: CGFloat

    if intialContentOffset == boundOfScreen.width
        return
    

    if isOpening
        minOffset = 20.0
        originalContentOffset = 0
        finalContentOffset = 70
    

    else 
        minOffset = 50.0
        originalContentOffset = 0
        finalContentOffset = 70
    

    if (!decelerate)
        //println("no dec \(intialContentOffset)")

        if intialContentOffset < minOffset 
            UIView.animateWithDuration(0.2,
                delay: 0.1,
                options: .CurveEaseIn ,
                animations:  scrollViewa.contentOffset.x = originalContentOffset ,
                completion: 
                    finished in scrollViewa.userInteractionEnabled = true
                    if self.viewOpenCounter 
                        UIView.animateWithDuration(0.2, animations: 
                            scrollViewa.contentOffset.x = 0
                        ,
                            completion: 
                                finished in
                                self.viewOpenCounter = false
                            
                        )
                    
                
            )
        
        else 
            UIView.animateWithDuration(0.2,
                delay: 0.1,
                options: .CurveEaseIn ,
                animations:  scrollViewa.contentOffset.x = finalContentOffset ,
                completion: 
                    finished in scrollViewa.userInteractionEnabled = true
                    if self.viewOpenCounter 
                        UIView.animateWithDuration(0.2, animations: 
                            scrollViewa.contentOffset.x = 0

                        ,
                            completion: 
                                finished in
                                self.viewOpenCounter = false
                            
                        )
                    
                
            )
        
    


 func scrollViewDidEndDecelerating(scrollViewb: UIScrollView) 

    viewOpenCounter = false

    let intialContentOffset = scrollViewb.contentOffset.x
    var originalContentOffset: CGFloat
    var finalContentOffset: CGFloat
    var minOffset: CGFloat
    //println("intialContentOffset: \(intialContentOffset)")

    if isOpening
        minOffset = 20.0
        originalContentOffset = 0
        finalContentOffset = 70
        //println("dec: opening")
    

    else 
        minOffset = 50.0
        originalContentOffset = 0
        finalContentOffset = 70
        //println("dec: closing")
    


    if intialContentOffset < minOffset 
        UIView.animateWithDuration(0.2,
            delay: 0.1,
            options: .CurveEaseIn ,
            animations: scrollViewb.contentOffset.x = originalContentOffset ,
            completion: 
                finished in scrollViewb.userInteractionEnabled = true
                if self.viewOpenCounter 
                    UIView.animateWithDuration(0.2, animations: 
                        scrollViewb.contentOffset.x = 0
                    ,
                        completion: 
                            finished in
                            self.viewOpenCounter = false
                        
                    )
                
            
        )
    
    else 
        UIView.animateWithDuration(0.2,
            delay: 0.1,
            options: .CurveEaseIn ,
            animations: scrollViewb.contentOffset.x = finalContentOffset ,
            completion: 
                finished in scrollViewb.userInteractionEnabled = true
                if self.viewOpenCounter 
                    UIView.animateWithDuration(0.2, animations: 
                        scrollViewb.contentOffset.x = 0
                    ,
                        completion: 
                            finished in
                            self.viewOpenCounter = false
                        
                    )
                
            

        )
    

【讨论】:

以上是关于当另一个 UIScrollView 滚动时停止动画 UIScrollView的主要内容,如果未能解决你的问题,请参考以下文章

低于一定速度时停止滚动视图动画

如何将滚动动画从一个uiscrollview“传输”到另一个

IOS。当 UIScrollView 滚动时应用另一个滚动动画[关闭]

当另一个滚动时如何隐藏recyclerview

UIScrollView 滚动时为对象设置动画

图像缩放时在 UIScrollView 中停止滚动图像