Ora continuiamo nel nostro viaggio per scoprire altre cose interessanti.
Ridimensionare educatamente
Il comportamento di uno SplitView quando la finestra in cui è contenuto si ridimensiona è generico e spesso irritante: non fa altro che mantenere le proporzioni tra le viste. Così, se a schermo pieno abbiamo ridotto una delle viste a 30 pixel, quando usciamo dal full screen potremmo trovare che la stessa vista è ora di 5 pixel o meno! Non c'è differenza se le dimensioni della finestra sono cambiate da codice o a mano dall'utente: il signor SplitView non ne vuol sapere di controllare il suo delegate per sapere se può stringere una vista.Considerando l'esempio della prima parte, con uno SplitView fatto di 3 viste, noi vorremmo che la prima (di solito una SourceList) e l'ultima (di solito un Inspector) mantenessero costanti le proprie dimensioni, variando solamente la vista centrale.
Con MountainLion, Apple ha introdotto la priorità delle viste, con cui si può risolvere il problema, ma al momento non ce la sentiamo di tagliar fuori tutti gli utenti che stanno utilizzando Lion e SnowLeopard, per cui dobbiamo di nuovo rimboccarci le maniche e cominciare a battere sulla tastiera.
Il metodo che ci viene in aiuto è sempre del delegate:
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSizeQuesto viene continuamente chiamato durante il ridimensionamento dello SplitView (conseguente a quello della finestra) e propone una nuova dimensione (
oldSize
) che il delegate può accettare o meno; dobbiamo fare in modo che la prima e la terza vista restino costanti, modificando solo quella centrale.Cominciamo col registrarci alcuni dati che ci torneranno utili nel metodo:
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize { NSView *leftView = [[sender subviews] objectAtIndex:0]; NSView *centerView = [[sender subviews] objectAtIndex:1]; NSView *rightView = [[sender subviews] objectAtIndex:2]; float dividerThickness = [sender dividerThickness]; NSRect splitFrame = [sender frame]; NSRect leftFrame = [leftView frame]; NSRect centerFrame = [centerView frame]; NSRect rightFrame = [rightView frame]; BOOL collapsed = [sender isSubviewCollapsed:rightView];Notiamo che alla riga 11 teniamo conto se la vista di destra è collassata o meno.
Ora impostiamo le cose più semplici: per ogni sotto-view impostiamo che l'altezza sia sempre quella dello SplitView e che la view a sinistra resti sempre incollata all'angolo sinistro:
. leftFrame.size.height = splitFrame.size.height; centerFrame.size.height = splitFrame.size.height; rightFrame.size.height = splitFrame.size.height; leftFrame.origin = NSMakePoint(0, 0);Ora arriva la parte importante: modifichiamo la larghezza della view centrale, calcolando quanto deve essere grande se le altre viste restano costanti, ma tenendo anche conto della condizione di
collapsed
(e ricordiamoci della larghezza dei divider!):
. centerFrame.size.width = !collapsed ? (splitFrame.size.width - leftFrame.size.width - rightFrame.size.width - 2*dividerThickness) : (splitFrame.size.width - leftFrame.size.width - dividerThickness); centerFrame.origin = NSMakePoint(leftFrame.size.width + dividerThickness, 0);Ora osserviamo che in questo modo la vista centrale potrebbe diventare più piccola di quanto abbiamo impostato: non viene impedito dal delegate, per cui lo dobbiamo impedire noi! Se succede, impostiamo la view centrale al valore minimo ammesso e passiamo a cambiare la dimensione della view di sinistra, sempre tenendo conto se la terza view è collassata o meno:
. if (centerFrame.size.width <= kMinWidthTable) { centerFrame.size.width = kMinWidthTable; leftFrame.size.width = !collapsed ? (splitFrame.size.width - 2*dividerThickness - kMinWidthTable - rightFrame.size.width) : (splitFrame.size.width - kMinWidthTable - dividerThickness); centerFrame.origin = NSMakePoint(leftFrame.size.width + dividerThickness, 0); }Ricordiamoci di impostare la posizione della vista destra (se non collassata):
. if ( ! collapsed ) { rightFrame.origin = NSMakePoint(splitFrame.size.width - rightFrame.size.width, 0); }e concludiamo dando i nuovi frame alle viste:
. [leftView setFrame:leftFrame]; [centerView setFrame:centerFrame]; if (! collapsed) [rightView setFrame:rightFrame]; }Compiliamo e divertiamoci con uno splitView ora beneducato!