On Wed, Jan 29, 2014, at 11:44 AM, Seth Willits wrote:
> 
> - ConnectionsLayer has a private property: @property int
> nodePositionsDidChange;
> - +needsDisplayForKey: returns YES for "nodePositionsDidChange" (calls
> super for anything else)
> - noteNodePositionsChanged calls:
>       [self addAnimation:[CABasicAnimation 
> animationWithKeyPath:@"nodePositionsDidChange"] 
> forKey:@"animateForNodePositionsChange"];
> 
> 
> The nodePositionsDidChange property itself is never set or get. It's
> simply there so that we can "animate" it, and Core Animation will
> recognize (via +needsDisplayForKey :) that while this property is
> animating, the layer should be redisplayed. Boom. (It's a bit voodoo that
> it can animate even though the value doesn't change at all, but there you
> go.)
> 
> 
> 
> The only "negative" part to this approach is that even if none of the
> boxes change positions, if noteNodePositionsChanged is called then it
> will redraw many times for whatever the duration of the animation is. So
> for efficiency's sake, noteNodePositionsChanged should only be called if
> a box's position actually did change. Ideally, we wouldn't need to call
> noteNodePositionsChanged manually at all.

Interesting that you chose this approach. I haven't gotten around to
writing it up yet, but the past day or so of thinking through the
problem, but I was coming to the conclusion that the only way to get
this to work reliably would be to not rely on implicit animations at
all.

Instead, when you wanted to animate the subtree, you'd need to add
explicit CAAnimations to the entire tree.

//begin
@implementation MyView
- (void)animateLayerTree {
  [CATransaction begin];

  // Generate a CALayer -> NSValue(CGPoint) map
  NSDictionary *sublayerToPositionMap = [self
  _generateMapOfSublayersToNewPositions];

  CAAnimationGroup *connectionsAnimGroup = [CAAnimationGroup animation];

  for (CALayer *sublayer in sublayerToPositionMap.allKeys) {
    CGPoint oldPosition = sublayer.position;
    CGPoint newPosition = [sublayerToPositionMap
    objectForKey:sublayer].pointValue;
    sublayer.position = newPosition;

    CGPoint oldConnectionEndpoint = [_connectionsLayer
    convertPoint:oldPosition fromLayer:sublayer];
    CGPoint newConnectionEndpoint = [_connectionsLayer
    convertPoint:newPosition fromLayer:sublayer];
    [connectionsAnimGroup addAnimation:[MyConnectionsAnimation
    animationOfLineNamed:sublayer.name
      fromPoint:oldConnectionEndpoint toPoint:newConnectionEndpoint];
  }

  // The connections layer returns YES for
  +needsDisplayForKey:@"connections"
  // TODO: Support retargeting animations mid-flight
  [_connectionsLayer addAnimation:connectionsAnimGroup
  forKey:@"connections"];

  [CATransaction commit];
}
//end

This at least avoids the possibility that CA might stop sending
-setNeedsDisplay for a key which never changes, and it feels less
"magic".

--Kyle Sluder
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to