2014-10-30 23 views
6

Ho provato tutto quello che riesco a pensare, inclusi tutti i suggerimenti che ho trovato qui su SO e su altre mailing list, ma non riesco a capire come ridurre a livello di programmazione un riquadro NSSplitView con un'animazione mentre Layout automatico è attivo.Come comprimere un riquadro NSSplitView con l'animazione mentre si utilizza il layout automatico?

Ecco quello che ho in questo momento (scritto in Swift per divertimento), ma cade in diversi modi:

@IBAction func toggleSourceList(sender: AnyObject?) { 
    let isOpen = !splitView.isSubviewCollapsed(sourceList.view.superview!) 
    let position = (isOpen ? 0 : self.lastWidth) 

    if isOpen { 
     self.lastWidth = sourceList.view.frame.size.width 
    } 

    NSAnimationContext.runAnimationGroup({ context in 
     context.allowsImplicitAnimation = true 
     context.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) 
     context.duration = self.duration 

     self.splitView.setPosition(position, ofDividerAtIndex: 0) 
    }, completionHandler: {() -> Void in 
    }) 
} 

Il comportamento e l'aspetto desiderato è quello di Mail.app, che anima davvero bene.

Ho un'app completa di esempio disponibile a https://github.com/mdiep/NSSplitViewTest.

+0

Prova a inviare '-setPosition: ofDividerAtIndex:' al proxy 'animator' della vista divisa. –

+0

@KenThomases L'ho provato. Niente da fare. – mdiep

risposta

0

Se si utilizza il layout automatico e si desidera animare alcuni aspetti delle dimensioni/posizione della vista, si potrebbe avere più fortuna nell'animazione dei vincoli stessi. Ho avuto una rapida partenza con uno NSSplitView ma finora ho incontrato solo un successo limitato. Posso ottenere una divisione per espandere e comprimere dopo una pressione di un pulsante, ma ho finito per dover tentare di incappare in un sacco di altri problemi causati interferendo con i vincoli. Nel caso la vostra familiarità con essa, ecco una semplice animazione vincolo:

- (IBAction)animate:(NSButton *)sender { 
    /* Shrink view to invisible */ 

    NSLayoutConstraint *constraint = self.viewWidthConstraint; 
    [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { 

     [[NSAnimationContext currentContext] setDuration:0.33]; 
     [[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]]; 
     [[constraint animator] setConstant:0]; 

    } completionHandler:^{ 
     /* Do Some clean-up, if required */ 

    }]; 

Tenete a mente è possibile animare solo vincoli constant, non è possibile animare la sua priority.

10

Objective-C:

[[splitViewItem animator] setCollapse:YES] 

Swift:

splitViewItem.animator().collapsed = true 

Da aiuto di Apple:

o meno il bambino ViewController corrispondente al SplitViewItem è col scaduto nel SplitViewController. L'impostazione predefinita è NO. Questo può essere impostato con il proxy animatore per animare la compressione o uncollapse. L'esatta animazione utilizzata può essere personalizzata impostandola su nel dizionario -animazioni con una chiave di "compresso". Se questo è impostato su SÌ prima di essere aggiunto a SplitViewController, sarà inizialmente collassato e lo SplitViewController non causerà il caricamento della vista finché non viene interrotta. Questo è compatibile con KVC/KVO e verrà aggiornato se il valore cambia dall'interazione dell'utente.

+1

Sfortunatamente, 'NSSplitViewItem' fa parte di una nuova API il 10.10. Se fosse in grado di usarlo, non avrei avuto bisogno di porre la domanda. :) – mdiep

+0

Controlla la modifica. –

+3

Capisco. Ma NSSplitViewItem è disponibile solo il 10.10 e successivi. – mdiep

0

Per qualche motivo, nessuno dei metodi di animazione dei frame ha funzionato per la mia scrollview. Non ho provato ad animare i vincoli però.

Ho finito per creare un'animazione personalizzata per animare la posizione del divisore. Se qualcuno è interessato, ecco la mia soluzione:

Animazione.h:

@interface MySplitViewAnimation : NSAnimation <NSAnimationDelegate> 

@property (nonatomic, strong) NSSplitView* splitView; 
@property (nonatomic) NSInteger dividerIndex; 
@property (nonatomic) float startPosition; 
@property (nonatomic) float endPosition; 
@property (nonatomic, strong) void (^completionBlock)(); 

- (instancetype)initWithSplitView:(NSSplitView*)splitView 
        dividerAtIndex:(NSInteger)dividerIndex 
          from:(float)startPosition 
           to:(float)endPosition 
        completionBlock:(void (^)())completionBlock; 
@end 

Animazione .m

@implementation MySplitViewAnimation 

- (instancetype)initWithSplitView:(NSSplitView*)splitView 
        dividerAtIndex:(NSInteger)dividerIndex 
          from:(float)startPosition 
           to:(float)endPosition 
        completionBlock:(void (^)())completionBlock; 
{ 
    if (self = [super init]) { 
     self.splitView = splitView; 
     self.dividerIndex = dividerIndex; 
     self.startPosition = startPosition; 
     self.endPosition = endPosition; 
     self.completionBlock = completionBlock; 

     [self setDuration:0.333333]; 
     [self setAnimationBlockingMode:NSAnimationNonblocking]; 
     [self setAnimationCurve:NSAnimationEaseIn]; 
     [self setFrameRate:30.0]; 
     [self setDelegate:self]; 
    } 
    return self; 
} 

- (void)setCurrentProgress:(NSAnimationProgress)progress 
{ 
    [super setCurrentProgress:progress]; 

    float newPosition = self.startPosition + ((self.endPosition - self.startPosition) * progress); 

    [self.splitView setPosition:newPosition 
       ofDividerAtIndex:self.dividerIndex]; 

    if (progress == 1.0) { 
     self.completionBlock(); 
    } 
} 

@end 

sto usando in questo modo - ho una visione splitter 3 riquadro, e sto spostando il riquadro di destra in/out da un importo fisso (235).

- (IBAction)togglePropertiesPane:(id)sender 
{ 
    if (self.rightPane.isHidden) { 

     self.rightPane.hidden = NO; 

     [[[MySplitViewAnimation alloc] initWithSplitView:_splitView 
              dividerAtIndex:1 
                from:_splitView.frame.size.width 
                to:_splitView.frame.size.width - 235                            
         completionBlock:^{ 
       ; 
           }] startAnimation]; 
} 
else { 
    [[[MySplitViewAnimation alloc] initWithSplitView:_splitView 
             dividerAtIndex:1               
               from:_splitView.frame.size.width - 235 
               to:_splitView.frame.size.width 
            completionBlock:^{   
     self.rightPane.hidden = YES; 
            }] startAnimation]; 
    } 
} 
0

NSSplitViewItem (cioè disposte visualizzazione secondaria di NSSplitView) può essere completamente collassato, se può raggiungere Zero dimensione (larghezza o altezza). Quindi, dobbiamo solo disattivare i vincoli appropriati prima dell'animazione e consentire alla vista di raggiungere la dimensione Zero. Dopo l'animazione possiamo attivare nuovamente i vincoli necessari.

Vedere il mio commento per SO domanda How to expand and collapse NSSplitView subviews with animation?.