Re: autolayout-based animation on NSView
Re: autolayout-based animation on NSView
- Subject: Re: autolayout-based animation on NSView
- From: Ken Thomases <email@hidden>
- Date: Wed, 13 Aug 2014 20:55:28 -0500
On Aug 13, 2014, at 8:22 PM, Roland King <email@hidden> wrote:
> I have a constraint-based NSView layout which I can flip between states by adjusting the constraint priorities and/or constants, and/or removing and replacing some constraints. At the same time I make some views invisible or visible again. All that stuff say is in a method on the view ..
>
> -(void)updateConstraintsAndVariousViewPropertiesForState:(BOOL)state;
>
> With the fairly straightforward UIView on iOS I’m used to doing this
>
> [ myUIView layoutIfNeeded ]
> [ myUIView animateWithDuration:duration animations:^{
> [ myUIView updateConstraintsAndVariousViewPropertiesForState:state ];
> [ myUIView layoutIfNeeded ];
> } ];
>
> The view properties change, the second layoutIfNeeded re-evaluates the constraints and fixed up all the frames and bounds etc and the whole thing animates smoothly to the new state.
>
> How do I do this with an *NSView*?
>
> Doing some docs diving I found animator proxies, get the proxy, call the method on the proxy and it should animate. So I tried
>
> [ myNSView layoutSubtreeIfNeeded ];
> [ myNSView updateConstraintsAndVariousViewPropertiesForState:state ];
> [ [ myNSView animator ] layoutSubtreeIfNeeded ];
>
> no animation, layout change, but no animation, just jumps. I put it in an NSAnimationContext beginGrouping/endGrouping box … that didn’t help. Changing some alpha properties in the same block did animate, but it seems the layoutSubtreeIfNeeded doesn’t work with animator proxies. I tried just setting constraint priorities using their animator proxies, that didn’t work either, still just jumped. Looks like the only animator proxy able thing on a constraint is the constant. So it looks like animator proxies aren’t going to fly.
>
> Where do I go next? I see a few comments about layer-backed views, but examples are few, do I need to back myself with a layer for this?
As you discovered, you can set a constraint constant on the constraint's animator to animate that change in the constraint. That doesn't work for priorities and really couldn't. There's no in-between state with priorities. To the extent they matter at all, it's because it switches which constraints are in effect, and that's a binary condition. When you set the constant on the animator, you're really animating the constraint, not the view positions. The system adjusts the constraint a little bit, lays out the views according to the constraints, draws, adjusts the constraint some more, etc.
The alternative is to animate the view positions by doing something similar as in UIKit. You make sure the frames are up-to-date with respect to the layout and then, in an animation group, you change the constraints and lay them out again. The resulting view frame changes get animated.
It should work to do:
[view layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
context.duration = 0.25; // you can leave this out if the default is acceptable
context.allowsImplicitAnimation = YES;
[view updateConstraintsAndVariousViewPropertiesForState:state];
[view layoutSubtreeIfNeeded];
} completionHandler:nil];
This does require layer-backed views. It may be that you can leave out setting allowsImplicitAnimation if you use the view's animator for the second -layoutSubtreeIfNeeded, but I'm not sure. Supposedly, the animator turns on implicit animation, but I don't know if that's only when setting animatable properties.
Regards,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden