On 16 Jun 2011, at 03:48, Graham Cox wrote:

> I'm using -setPosition:ofDividerAtIndex: and I call this using the view's 
> animator:
> 
>       [[mySplitPane animator] setPosition:position ofDividerAtIndex:0];
> 
> But it doesn't animate and just jumps into position. I see other apps manage 
> this (e.g. Mail) so how's it done?

Hi Graham,

Having recently experienced the same limitation, I found we need to manually 
resize the subviews (through their animator). I posted a message here, on June 
1st, titled "Animated Split View", in which I exposed a solution and asked for 
feedback on it (got none). Meanwhile I have improved the code, since I found 
the first iteration not to be robust enough. The new version follows:

==========
@interface NSSplitView (NSSplitView_Animation)

- (CGFloat)catPositionOfDividerAtIndex:(NSInteger)index;
- (void)catAnimateDividerIndexes:(NSArray *)indexes toPositions:(NSArray 
*)newPositions;
- (void)catAnimateDividerAtIndex:(NSInteger)index 
toPosition:(CGFloat)newPosition;

@end


@protocol NMD_AnimatingSplitViewDelegate <NSObject>

@required
@property (readwrite, assign)   BOOL splitViewIsAnimating;

@end
==========

==========
@implementation NSSplitView (NSSplitView_Animation)

- (CGFloat)catPositionOfDividerAtIndex:(NSInteger)index
{
        NSRect frame = [[self.subviews objectAtIndex:index] frame];
        return self.isVertical ? NSMaxX(frame) : NSMaxY(frame);
}


- (void)catAnimateDividerIndexes:(NSArray *)indexes toPositions:(NSArray 
*)newPositions
{
        NSUInteger numberOfSubviews = self.subviews.count;

        NSAssert(indexes.count == newPositions.count, @"indexes and 
newPositions arrays must have same object count.");
        NSAssert(indexes.count < numberOfSubviews, @"Trying to move too many 
dividers");

        NSRect newRect[numberOfSubviews];
        
        for (NSUInteger i = 0; i < numberOfSubviews; i++) {
                newRect[i] = [[self.subviews objectAtIndex:i] frame];
        }
        
        for (NSNumber *indexObject in indexes) {
                NSInteger       index = [indexObject integerValue];
                CGFloat         newPosition = [[newPositions 
objectAtIndex:[indexes indexOfObject:indexObject]] doubleValue];
                if (self.isVertical) {
                        CGFloat oldMaxXOfRightHandView = NSMaxX(newRect[index + 
1]);
                        newRect[index].size.width = newPosition - 
NSMinX(newRect[index]);
                        CGFloat dividerAdjustment = (newPosition < 
NSWidth(self.bounds)) ? self.dividerThickness : 0.0;
                        newRect[index + 1].origin.x = newPosition + 
dividerAdjustment;
                        newRect[index + 1].size.width = oldMaxXOfRightHandView 
- newPosition - dividerAdjustment;
                } else {
                        CGFloat oldMaxYOfBottomView = NSMaxY(newRect[index + 
1]);
                        newRect[index].size.height = newPosition - 
NSMinY(newRect[index]);
                        CGFloat dividerAdjustment = (newPosition < 
NSHeight(self.bounds)) ? self.dividerThickness : 0.0;
                        newRect[index + 1].origin.y = newPosition + 
dividerAdjustment;
                        newRect[index + 1].size.height = oldMaxYOfBottomView - 
newPosition - dividerAdjustment;
                }
        }
        
        if ([self.delegate respondsToSelector:@selector(splitViewIsAnimating)]) 
{
                 
((id<NMD_AnimatingSplitViewDelegate>)self.delegate).splitViewIsAnimating = YES; 
        }
        [CATransaction begin]; {
                [CATransaction setAnimationDuration:0.25];
                [CATransaction 
setAnimationTimingFunction:[CAMediaTimingFunction 
functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
                [CATransaction setCompletionBlock:^{
                        if ([self.delegate 
respondsToSelector:@selector(splitViewIsAnimating)]) {
                                
((id<NMD_AnimatingSplitViewDelegate>)self.delegate).splitViewIsAnimating = NO;
                        }       
                }];
                
                for (NSUInteger i = 0; i < numberOfSubviews; i++) {
                        [[[self.subviews objectAtIndex:i] animator] 
setFrame:newRect[i]];
                }               
        } [CATransaction commit];
}


- (void)catAnimateDividerAtIndex:(NSInteger)index 
toPosition:(CGFloat)newPosition
{
        NSUInteger numberOfSubviews = self.subviews.count;

        NSAssert(index < numberOfSubviews - 1, @"index should be less than 
number of subviews - 1");
        
        [self catAnimateDividerIndexes:[NSArray arrayWithObject:[NSNumber 
numberWithInteger:index]]
                                           toPositions:[NSArray 
arrayWithObject:[NSNumber numberWithDouble:newPosition]]];
}

@end
==========

As you'll have noticed, I prefix all my category methods with "cat", in an 
attempt to be (OS X) future proof.

Since the resize behaviour of the subviews for the project I'm working on is 
tightly controlled, I need to know if the splitview is animating, hence I added 
a protocol to be adopted by parties who want to disable splitview delegate 
constraint checking during the animation.

I found one needs to be very careful to ensure the width/height of the subviews 
+ thickness of the dividers add up to the width/height of the splitview. I am 
currently using this on a splitview with three subviews (two dividers). The 
code is still quite young, so it may yet prove to need some tweaks, but it's 
been performing fine since I implemented the above a number of days ago.

Examples of how to use the category:
==========
        if (self.isShowingLeftSideList == NO) {
                // Make sure the subview is not collapsed
                [[self.splitView.subviews objectAtIndex:0] setHidden:NO];
                [self.splitView catAnimateDividerAtIndex:0
                                                                          
toPosition:DEFAULT_LEFT_SIDE_SPLITTER_WIDTH];
        } else {
                [self.splitView catAnimateDividerAtIndex:0
                                                                          
toPosition:0];
        }
==========
        if (NSWidth([[self.splitView.subviews objectAtIndex:0] bounds]) > 
NSWidth(self.splitView.bounds) - DEFAULT_OUTLINESPLITTER_WIDTH - 1) {
                [self.splitView catAnimateDividerIndexes:[NSArray 
arrayWithObjects:
                                                                                
                  [NSNumber numberWithInteger:0],
                                                                                
                  [NSNumber numberWithInteger:1],
                                                                                
                  nil]
                                                   toPositions:[NSArray 
arrayWithObjects:
                                                                                
[NSNumber numberWithDouble:DEFAULT_LEFT_SIDE_SPLITTER_WIDTH],
                                                                                
[NSNumber numberWithDouble:NSWidth(self.splitView.frame) - 
DEFAULT_OUTLINESPLITTER_WIDTH],
                                                                                
nil]];
        } else {
                [self.splitView catAnimateDividerAtIndex:1
                                                                          
toPosition:NSWidth(self.splitView.frame) - DEFAULT_OUTLINESPLITTER_WIDTH];
        }
==========


-António

-----------------------------------------
Forgiveness is not an occasional act;
it is a permanent attitude.

--Martin Luther King, Jr
-----------------------------------------




_______________________________________________

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

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

Reply via email to