2013-05-16 16 views
11

Con il layout automatico abilitato, il salvataggio automatico delle posizioni del divisore impostando un nome di salvataggio per NSSplitView nel builder dell'interfaccia comporta il blocco completo di ogni divisore in un riavvio dell'app. Disabilitare il layout automatico consente il salvataggio automatico funziona perfettamente.NSSplitVIew - la posizione di salvataggio automatico del divisore non funziona con il layout automatico abilitato

Ho provato questo anche in un nuovo progetto Xcode, stesso risultato. È un bug o un'incompatibilità conosciuta?

Come posso aggirare questo (o c'è una soluzione a questo, se si tratta di un bug)?

+0

Per me funziona perfettamente con un nuovo progetto. Hai assegnato alla vista divisa un nome di salvataggio automatico? Come si ferma il programma durante il test? Usando Cmd-Q, o il pulsante stop in XCode? –

risposta

0

Ho scoperto che l'utilizzo di NSSplitView è terribile in modalità layout automatico. Così ho scritto la vista divisa basata su autolayout: https://github.com/silvansky/TwinPanelView

Può memorizzare la posizione della maniglia (non completamente automatizzata).

9

mi sono imbattuto in questo problema come bene, e ho trovato che ho bisogno di impostare entrambi il identifier e la autosaveName valori per la NSSplitView, e che hanno bisogno di essere impostato su valori diversi.

+1

Ho lottato con questo per un po 'e finalmente ho trovato la tua risposta. Non riesco a credere che fosse qualcosa di sciocco come l'identificatore. Ma impostarlo su qualcosa di diverso dal mio nome di salvataggio automatico ha funzionato. Grazie! –

+0

Cosa intendi per 'identificatore'? Dove viene definita questa proprietà? –

2

NSSplitView è noto per essere particolarmente pignolo e problematico; a volte devi fare di tutto per farlo comportarsi correttamente. Sapevo che le mie impostazioni venivano salvate in User Defaults - Potevo vederle cambiare correttamente tramite il Terminale "Defaults read etc...", ma non venivano ripristinati quando l'applicazione si riapriva.

Ho risolto il problema leggendo manualmente i valori salvati e ripristinando le posizioni del divisore durante awakeFromNib.

Ecco una categoria a NSSplitView che chiede gentilmente a Si prega di impostare le proprie posizioni divisori ai valori salvati automaticamente:

@interface NSSplitView (PraxCategories) 
- (void)restoreAutosavedPositions; 
@end 

@implementation NSSplitView (PraxCategories) 
- (void)restoreAutosavedPositions { 

    // Yes, I know my Autosave Name; but I won't necessarily restore myself automatically. 
    NSString *key = [NSString stringWithFormat:@"NSSplitView Subview Frames %@", self.autosaveName]; 

    NSArray *subviewFrames = [[NSUserDefaults standardUserDefaults] valueForKey:key]; 

    // the last frame is skipped because I have one less divider than I have frames 
    for (NSInteger i=0; i < (subviewFrames.count - 1); i++) { 

     // this is the saved frame data - it's an NSString 
     NSString *frameString = subviewFrames[i]; 
     NSArray *components = [frameString componentsSeparatedByString:@", "]; 

     // only one component from the string is needed to set the position 
     CGFloat position; 

     // if I'm vertical the third component is the frame width 
     if (self.vertical) position = [components[2] floatValue]; 

     // if I'm horizontal the fourth component is the frame height 
     else position = [components[3] floatValue]; 

     [self setPosition:position ofDividerAtIndex:i]; 
    } 
} 
@end 

Poi basta chiamare il metodo durante awakeFromNib per ogni NSSplitView si desidera ripristinare:

for (NSSplitView *splitView in @[thisSplitView, thatSplitView, anotherSplitView]) { 
    [splitView restoreAutosavedPositions]; 
} 
4

Per me, l'impostazione dell'identificatore + autosavename non ha funzionato. Ho dovuto ricorrere alla soluzione fornita da ElmerCat. Tuttavia ho leggermente modificato il codice per evitare di impostare la posizione del divisore (non farlo funzionare). Invece, sto modificando le dimensioni della vista. Ho anche aggiunto la possibilità di nascondere le visualizzazioni compresse.

@interface NSSplitView (RestoreAutoSave) 
- (void)restoreAutosavedPositions; 
@end 

@implementation NSSplitView (RestoreAutoSave) 
- (void)restoreAutosavedPositions 
{ 
    NSString *key = [NSString stringWithFormat:@"NSSplitView Subview Frames %@", self.autosaveName]; 
    NSArray *subviewFrames = [[NSUserDefaults standardUserDefaults] valueForKey:key]; 

    // the last frame is skipped because I have one less divider than I have frames 
    for(NSInteger i = 0; i < subviewFrames.count; i++) { 

     if(i < self.subviews.count) { // safety-check (in case number of views have been removed while dev) 

      // this is the saved frame data - it's an NSString 
      NSString *frameString = subviewFrames[i]; 
      NSArray *components = [frameString componentsSeparatedByString:@", "]; 

      // Manage the 'hidden state' per view 
      BOOL hidden = [components[4] boolValue]; 
      NSView* subView =[self subviews][i]; 
      [subView setHidden: hidden]; 

      // Set height (horizontal) or width (vertical) 
      if(!self.vertical) { 

       CGFloat height = [components[3] floatValue]; 
       [subView setFrameSize: NSMakeSize(subView.frame.size.width, height) ]; 
      } 
      else { 

       CGFloat width = [components[2] floatValue]; 
       [subView setFrameSize: NSMakeSize(width, subView.frame.size.height) ]; 
      } 
     } 
    } 
} 
+0

I bug in NSSplitView rendono ancora necessario ciò e questa correzione funziona ancora. Grazie. Questa dovrebbe essere la risposta accettata. Il problema con la richiesta di 'identificatore' da impostare sembra essere stato risolto da Apple. – bhaller

17

ho scoperto che l'impostazione Identifier e Autosave all'interno di uno storyboard con layout automatico abilitato non funziona. Tuttavia ha funzionato per me una volta impostato il autosaveName in modo programmatico.

class MySplitViewController: NSSplitViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     splitView.autosaveName = "Please Save Me!" 
    } 
} 
+0

Questa soluzione ha funzionato perfettamente per me e molto più semplice rispetto alle soluzioni alternative precedenti. –

+0

Questo era quello anche per me! Voglio riutilizzare MySplitViewController per diverse divisioni sullo storyboard e ho scoperto che il valore che inserisco per ogni splitviewcontroller nello storyboard in 'Identity Inspector' -> 'Restoration ID' emerge nella variabile membro chiamata 'identificatore' in MySplitViewController. Puoi assegnarlo al valore di salvataggio automatico come sopra dicendo: "splitView.autosaveName = identificatore" – Hans

+0

Wow, questa è un'ottima risposta! – Christophe

0

sono ritrovato a guardare gli stessi vecchi problemi di salvataggio automatico NSSplitView da anni fa ora con Mac OS 10.12. Fortunatamente la soluzione di Joris è ancora un'ottima soluzione. Qui è un'estensione Swift 3 testata che funziona bene nel nostro progetto attuale.

Nota: Poiché Auto Layout sostituisce a quanto pare i valori di default di salvataggio automatico dopo awakeFromNib nel NSSplitView restoreAutoSavePositions() deve essere chiamato in viewDidLoad o giù di lì del regolatore al fine di ottenere questo lavoro.

extension NSSplitView { 

    /* 
    ** unfortunately this needs to be called in the controller's viewDidAppear function as 
    ** auto layout kicks in to override any default values after the split view's awakeFromNib 
    */ 
    func restoreAutoSavePositions() { 

     let key = String(format: "NSSplitView Subview Frames %@", self.autosaveName!) 
     let subViewFrames = UserDefaults.standard.array(forKey: key) 
     guard subViewFrames != nil else { return } 

     for (i, frame) in (subViewFrames?.enumerated())! { 

      if let frameString = frame as? String { 

       let components = frameString.components(separatedBy: ", ") 
       guard components.count >= 4 else { return } 

       var position: CGFloat = 0.0 

       // Manage the 'hidden state' per view 
       let hidden = NSString(string:components[4].lowercased()).boolValue 
       let subView = self.subviews[i] 
       subView.isHidden = hidden 

       // Set height (horizontal) or width (vertical) 
       if self.isVertical { 
        if let n = NumberFormatter().number(from: components[2]) { 
         position = CGFloat(n) 
        } 
       } else { 
        if let n = NumberFormatter().number(from: components[3]) { 
         position = CGFloat(n) 
        } 
       } 

       setPosition(position, ofDividerAt: i) 
      } 
     } 
    } 
}