Pagine

2012-11-18

I segreti degli NSSplitView - II

Nella scorsa puntata abbiamo esaminato come sia possibile limitare le dimensioni delle viste di uno NSSplitView ed anche come fare in modo che l'utente possa far scomparire una vista, senza che questa si offenda e distribuisca a caso gli oggetti contenuti.
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)oldSize
Questo 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!

Nessun commento:

Posta un commento