Soft scroll animation NSScrollView scrollToPoint:

前端 未结 5 1329
旧巷少年郎
旧巷少年郎 2021-02-13 23:53

I want to create soft animation between transitions in simply UI:

\"first

5条回答
  •  孤城傲影
    2021-02-14 00:35

    I know, it's a little bit off topic, but I wanted to have a similar method to scroll to a rectangle with animation like in UIView's scrollRectToVisible(_ rect: CGRect, animated: Bool) for my NSView. I was happy to find this post, but apparently the accepted answer doesn't always work correctly. It turns out that there is a problem with bounds.origin of the clipview. If the view is getting resized (e.g. by resizing the surrounding window) bounds.origin is somehow shifted against the true origin of the visible rectangle in y-direction. I could not figure out why and by how much. Well, there is also this statement in the Apple docs not to manipulate the clipview directly since its main purpose is to function internally as a scrolling machine for views.

    But I do know the true origin of the visible area. It’s part of the clipview’s documentVisibleRect. So I take that origin for the calculation of the scrolled origin of the visibleRect and shift the bounds.origin of the clipview by the same amount, and voilà: that works even if the view is getting resized.

    Here is my implementation of the new method of my NSView:

       func scroll(toRect rect: CGRect, animationDuration duration: Double) {
            if let scrollView = enclosingScrollView {           // we do have a scroll view
                let clipView = scrollView.contentView           // and thats its clip view
                var newOrigin = clipView.documentVisibleRect.origin // make a copy of the current origin
                if newOrigin.x > rect.origin.x {                // we are too far to the right
                    newOrigin.x = rect.origin.x                 // correct that
                }
                if rect.origin.x > newOrigin.x + clipView.documentVisibleRect.width - rect.width {  // we are too far to the left
                    newOrigin.x = rect.origin.x - clipView.documentVisibleRect.width + rect.width   // correct that
                }
                if newOrigin.y > rect.origin.y {                // we are too low
                    newOrigin.y = rect.origin.y                 // correct that
                }
                if rect.origin.y > newOrigin.y + clipView.documentVisibleRect.height - rect.height {    // we are too high
                    newOrigin.y = rect.origin.y - clipView.documentVisibleRect.height + rect.height // correct that
                }
                newOrigin.x += clipView.bounds.origin.x - clipView.documentVisibleRect.origin.x  // match the new origin to bounds.origin
                newOrigin.y += clipView.bounds.origin.y - clipView.documentVisibleRect.origin.y
                NSAnimationContext.beginGrouping()              // create the animation
                NSAnimationContext.current.duration = duration  // set its duration
                clipView.animator().setBoundsOrigin(newOrigin)  // set the new origin with animation
                scrollView.reflectScrolledClipView(clipView)    // and inform the scroll view about that
                NSAnimationContext.endGrouping()                // finaly do the animation
            }
        }
    

    Please note, that I use flipped coordinates in my NSView to make it match the iOS behaviour. BTW: the animation duration in the iOS version scrollRectToVisible is 0.3 seconds.

    https://www.fpposchmann.de/animate-nsviews-scrolltovisible/

提交回复
热议问题