软滚动动画NSScrollView scrollToPoint:

WIN*_*gey 12 cocoa core-animation nsscrollview

我想在简单的UI中在转换之间创建软动画:

第一张幻灯片第二张幻灯片第三张幻灯片

移动的视图

视图

当调用scrollToPoint: for move view指向该过渡没有动画时.我是Cocoa编程的新手(iOS是我的背景).我不知道如何正确使用.animator或NSAnimationContext.

我也读过核心动画指南,但没有找到解决方案.

源可以在Git Hub存储库上访问

请帮忙 !!!

mah*_*tin 23

scrollToPoint不可动画.只有动画属性,如NSAnimatablePropertyContainer中的边界和位置等动画属性.你不需要对CALayer做任何事情:删除wantsLayer和CALayer的东西.然后使用以下代码进行动画处理.

- (void)scrollToXPosition:(float)xCoord {
    [NSAnimationContext beginGrouping];
    [[NSAnimationContext currentContext] setDuration:5.0];
    NSClipView* clipView = [_scrollView contentView];
    NSPoint newOrigin = [clipView bounds].origin;
    newOrigin.x = xCoord;
    [[clipView animator] setBoundsOrigin:newOrigin];
    [_scrollView reflectScrolledClipView: [_scrollView contentView]]; // may not bee necessary
    [NSAnimationContext endGrouping];
}
Run Code Online (Sandbox Code Playgroud)


Osk*_*kar 6

建议的答案有一个明显的缺点:如果用户尝试在正在进行的动画期间滚动,则输入将导致抖动,因为动画将强制继续进行直到完成。如果您设置了非常长的动画持续时间,问题就会变得明显。这是我的用例,动画滚动视图以捕捉到部分标题(同时尝试向上滚动):

在此处输入图片说明

我提出以下子类:

public class AnimatingScrollView: NSScrollView {

    // This will override and cancel any running scroll animations
    override public func scroll(_ clipView: NSClipView, to point: NSPoint) {
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        contentView.setBoundsOrigin(point)
        CATransaction.commit()
        super.scroll(clipView, to: point)
    }

    public func scroll(toPoint: NSPoint, animationDuration: Double) {
        NSAnimationContext.beginGrouping()
        NSAnimationContext.current.duration = animationDuration
        contentView.animator().setBoundsOrigin(toPoint)
        reflectScrolledClipView(contentView)
        NSAnimationContext.endGrouping()
    }

}
Run Code Online (Sandbox Code Playgroud)

通过覆盖正常scroll(_ clipView: NSClipView, to point: NSPoint)(在用户滚动时调用)并在CATransactionwith 中手动执行滚动setDisableActions,我们取消了当前动画。但是,我们不调用reflectScrolledClipView,而是调用super.scroll(clipView, to: point),它将执行其他必要的内部过程,然后执行reflectScrolledClipView

上面的类产生更好的结果:

在此处输入图片说明


And*_*nov 5

这个答案的 Swift 4代码

func scroll(toPoint: NSPoint, animationDuration: Double) {
    NSAnimationContext.beginGrouping()
    NSAnimationContext.current.duration = animationDuration
    let clipView = scrollView.contentView
    clipView.animator().setBoundsOrigin(toPoint)
    scrollView.reflectScrolledClipView(scrollView.contentView)
    NSAnimationContext.endGrouping()
}
Run Code Online (Sandbox Code Playgroud)