Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSSplitViewItem collapse animation and window setFrame conflicting

I am trying to make a (new in 10.10) NSSplitViewItem collapse and uncollapse whilst moving its containing window so as to keep the whole thing "in place".

The problem is that I am getting a twitch in the animation (as seen here).

The code where I'm doing the collapsing is this:

func togglePanel(panelID: Int) {

     if let splitViewItem = self.splitViewItems[panelID] as? NSSplitViewItem {

          // Toggle the collapsed state
          NSAnimationContext.runAnimationGroup({ context in

               // special case for the left panel
               if panelID == 0 {
                    var windowFrame = self.view.window.frame
                    let panelWidth = splitViewItem.viewController.view.frame.width
                    if splitViewItem.collapsed {
                         windowFrame.origin.x -= panelWidth
                         windowFrame.size.width += panelWidth
                    } else {
                         windowFrame.origin.x += panelWidth
                         windowFrame.size.width -= panelWidth
                    }
                    self.view.window.animator().setFrame(windowFrame, display: true)
               }
               splitViewItem.animator().collapsed = !splitViewItem.collapsed
          }, completionHandler: nil)
     }
}

I am aware of the "Don't cross the streams" issue (from session 213, WWDC'13) where a window resizing animation running on the main thread and a core animation collapse animation running on a separate thread interfere with each other. Putting the splitViewItem collapse animation onto the main thread seems like the wrong approach and I've got a nagging feeling there's a much better way of doing this that I'm missing.

Since I am not finding any documentation on the NSSplitViewItems anywhere (yet) I would appreciate any insights on this.

I have the little test project on GitHub here if anyone wants a look.

Update The project mentioned has now been updated with the solution.

Thanks, Teo

like image 327
Teo Sartori Avatar asked Jul 05 '14 10:07

Teo Sartori


2 Answers

The problem is similar to the "don't cross the streams" issue in that there are two drivers to the animation you've created: (1) the split view item (2) the window, and they're not in sync.

In the example from the '13 Cocoa Animations talk, constraints were setup to result in the correct within-window animation as only the window's frame was animated.

Something similar could be tried here -- only animating the window's frame and not the split view item, but since the item manages the constraints used to (un)collapse, the app can't control exactly how within-window content animates:

Animating Window frame

Instead the split view item animation could completely drive the animation and use NSWindow's -anchorAttributeForOrientation: to describe how the window's frame is affected.

if let splitViewItem = self.splitViewItems[panelID] as? NSSplitViewItem {
    let window = self.view.window
    if panelID == 0 {
        // The Trailing edge of the window is "anchored", alternatively it could be the Right edge
        window.setAnchorAttribute(.Trailing, forOrientation:.Horizontal)
    }
    splitViewItem.animator().collapsed = !splitViewItem.collapsed
}

Animating SplitViewItem

like image 154
Taylor Avatar answered Feb 01 '23 21:02

Taylor


For anyone using Objective C and targeting 10.11 El Capitan. This did the trick for me, didn't need to set AnchorAttributes.

splitViewItem.collapsed = YES;
like image 26
Daniel Nordh Avatar answered Feb 01 '23 21:02

Daniel Nordh