Storyboard unificati in Xamarin.iOS

iOS 8 include un nuovo meccanismo più semplice da usare per la creazione dell'interfaccia utente, ovvero lo storyboard unificato. Con un singolo storyboard per coprire tutte le diverse dimensioni dello schermo hardware, è possibile creare visualizzazioni veloci e reattive in uno stile "design-once, use-many".

Poiché lo sviluppatore non deve più creare uno storyboard separato e specifico per i Telefono e iPad, ha la flessibilità di progettare applicazioni con un'interfaccia comune e quindi personalizzare tale interfaccia per classi di dimensioni diverse. In questo modo, un'applicazione può essere adattata ai punti di forza di ogni fattore di forma e ogni interfaccia utente può essere ottimizzata per offrire l'esperienza migliore.

Classi Size

Prima di iOS 8, lo sviluppatore usava UIInterfaceOrientation e UIInterfaceIdiom per distinguere tra modalità verticale e orizzontale e tra i dispositivi i Telefono e iPad. In iOS8 l'orientamento e il dispositivo sono determinati usando classi di dimensioni.

I dispositivi sono definiti dalle classi di dimensioni, sia negli assi verticali che orizzontali, e esistono due tipi di classi di dimensioni in iOS 8:

  • Regolare : si tratta di una grande dimensione dello schermo (ad esempio un iPad) o un gadget che dà l'impressione di una grande dimensione (ad esempio un UIScrollView
  • Compact: si tratta di dispositivi più piccoli (ad esempio, i Telefono). Questa dimensione tiene conto dell'orientamento del dispositivo.

Se i due concetti vengono usati insieme, il risultato è una griglia di 2 x 2 che definisce le diverse dimensioni possibili che possono essere usate in entrambi gli orientamenti diversi, come illustrato nel diagramma seguente:

A 2 x 2 grid that defines the different possible sizes that can be used in Regular and Compact orientations

Lo sviluppatore può creare un controller di visualizzazione che usa una delle quattro possibilità che comporterebbe layout diversi (come illustrato nella grafica precedente).

Classi di dimensioni iPad

L'iPad, a causa delle dimensioni, ha una dimensione di classe regolare per entrambi gli orientamenti.

iPad Size Classes

classi di dimensioni i Telefono

I Telefono ha classi di dimensioni diverse in base all'orientamento del dispositivo:

iPhone Size Classes

  • Quando il dispositivo è in modalità verticale, lo schermo ha una classe compatta orizzontalmente e regolare verticalmente
  • Quando il dispositivo è in modalità orizzontale, le classi dello schermo vengono invertite dalla modalità verticale.

i Telefono 6 classi di dimensioni più

Le dimensioni sono le stesse delle precedenti i Telefono quando sono in orientamento verticale, ma diverse in orizzontale:

iPhone 6 Plus Size Classes

Poiché l'i Telefono 6 Plus ha uno schermo sufficientemente grande, è in grado di avere una classe di dimensioni di larghezza regolare in modalità orizzontale.

Supporto per una nuova scala dello schermo

I Telefono 6 Plus usa un nuovo display Retina HD con un fattore di scala dello schermo pari a 3,0 (tre volte la risoluzione dello schermo originale i Telefono). Per offrire la migliore esperienza possibile su questi dispositivi, includere nuove opere d'arte progettate per questa scala dello schermo. In Xcode 6 e versioni successive, i cataloghi di asset possono includere immagini con dimensioni 1x, 2x e 3x; è sufficiente aggiungere i nuovi asset di immagine e iOS sceglieranno gli asset corretti durante l'esecuzione in un i Telefono 6 Plus.

Il comportamento di caricamento delle immagini in iOS riconosce anche un @3x suffisso nei file di immagine. Ad esempio, se lo sviluppatore include un asset di immagine (in risoluzioni diverse) nel bundle dell'applicazione con i nomi di file seguenti: MonkeyIcon.png, MonkeyIcon@2x.pnge MonkeyIcon@3x.png. In i Telefono 6 Plus l'immagine MonkeyIcon@3x.png verrà usata automaticamente se lo sviluppatore carica un'immagine usando il codice seguente:

UIImage icon = UIImage.FromFile("MonkeyImage.png");

Schermate di avvio dinamico

Il file della schermata di avvio viene visualizzato come schermata iniziale mentre un'applicazione iOS viene avviata per fornire feedback all'utente che l'app sta effettivamente avviando. Prima di iOS 8, lo sviluppatore dovrà includere più Default.png asset di immagine per ogni tipo di dispositivo, orientamento e risoluzione dello schermo su cui l'applicazione sarebbe in esecuzione.

Novità di iOS 8, lo sviluppatore può creare un singolo file atomico .xib in Xcode che usa classi di layout automatico e dimensioni per creare una schermata di avvio dinamico che funzionerà per ogni dispositivo, risoluzione e orientamento. Questo non solo riduce la quantità di lavoro richiesta dallo sviluppatore per creare e gestire tutti gli asset di immagine necessari, ma riduce le dimensioni del bundle installato dell'applicazione.

Tratti

I tratti sono proprietà che possono essere usate per determinare il modo in cui un layout cambia man mano che cambia l'ambiente. Sono costituiti da un set di proprietà (e HorizontalSizeClassVerticalSizeClass in UIUserInterfaceSizeClassbase a ), nonché dal linguaggio dell'interfaccia ( UIUserInterfaceIdiom) e dalla scala di visualizzazione.

Tutti gli stati precedenti vengono inclusi in un contenitore a cui Apple fa riferimento come raccolta di tratti ( UITraitCollection), che contiene non solo le proprietà, ma anche i relativi valori.

Ambiente di tratto

Gli ambienti di tratto sono una nuova interfaccia in iOS 8 e sono in grado di restituire una raccolta di tratti per gli oggetti seguenti:

  • Schermate ( UIScreens ).
  • Windows ( UIWindows ).
  • Controller di visualizzazione ( UIViewController ).
  • Viste ( UIView ).
  • Presentation Controller ( UIPresentationController ).

Lo sviluppatore usa la raccolta di tratti restituita da un ambiente di tratto per determinare come deve essere disposta un'interfaccia utente.

Tutti gli ambienti di tratto costituiscono una gerarchia come illustrato nel diagramma seguente:

The Trait Environments hierarchy diagram

La raccolta di tratti che ognuno degli ambienti trait precedenti avrà come flusso, per impostazione predefinita, dall'elemento padre all'ambiente figlio.

Oltre a ottenere la raccolta dei tratti corrente, l'ambiente del tratto ha un TraitCollectionDidChange metodo, che può essere sottoposto a override nelle sottoclassi View o View Controller. Lo sviluppatore può usare questo metodo per modificare uno degli elementi dell'interfaccia utente che dipendono dai tratti quando tali tratti sono stati modificati.

Raccolte di caratteristiche tipiche

Questa sezione illustra i tipi tipici di raccolte di tratti che l'utente avrà esperienza quando si usa iOS 8.

Di seguito è riportata una tipica raccolta di tratti che lo sviluppatore potrebbe visualizzare in un i Telefono:

Proprietà valore
HorizontalSizeClass Compact
VerticalSizeClass Regolare
UserInterfaceIdom il numero
DisplayScale 2.0

Il set precedente rappresenta una raccolta di tratti completi, in quanto contiene valori per tutte le relative proprietà di tratto.

È anche possibile avere una Raccolta di tratti mancante per alcuni dei relativi valori (che Apple fa riferimento a come Non specificato):

Proprietà valore
HorizontalSizeClass Compact
VerticalSizeClass Non specificato
UserInterfaceIdom Non specificato
DisplayScale Non specificato

In genere, tuttavia, quando lo sviluppatore chiede a Trait Environment la relativa raccolta di tratti, restituirà una raccolta completa, come illustrato nell'esempio precedente.

Se un ambiente di tratto ,ad esempio un view o un controller di visualizzazione, non si trova all'interno della gerarchia di visualizzazione corrente, lo sviluppatore potrebbe ottenere valori non specificati per una o più proprietà del tratto.

Lo sviluppatore otterrà anche una raccolta di tratti parzialmente qualificata se usa uno dei metodi di creazione forniti da Apple, ad esempio UITraitCollection.FromHorizontalSizeClass, per creare una nuova raccolta.

Un'operazione che può essere eseguita su più raccolte di tratti consiste nel confrontarle tra loro, che comporta la richiesta di una raccolta di tratti se contiene un'altra. Ciò che significa contenimento è che, per qualsiasi tratto specificato nella seconda raccolta, il valore deve corrispondere esattamente al valore nella prima raccolta.

Per testare due tratti, usare il Contains metodo del UITraitCollection passaggio del valore del tratto da testare.

Lo sviluppatore può eseguire manualmente i confronti nel codice per determinare come layout visualizzazioni o controller di visualizzazione. Tuttavia, UIKit usa questo metodo internamente per fornire alcune delle relative funzionalità, ad esempio nel proxy di aspetto.

Proxy aspetto

Il proxy di aspetto è stato introdotto nelle versioni precedenti di iOS per consentire agli sviluppatori di personalizzare le proprietà delle visualizzazioni. È stato esteso in iOS 8 per supportare le raccolte di tratti.

I proxy di aspetto includono ora un nuovo metodo, AppearanceForTraitCollection, che restituisce un nuovo proxy di aspetto per la raccolta di tratti specificata passata. Tutte le personalizzazioni eseguite dallo sviluppatore su tale proxy di aspetto avranno effetto solo sulle visualizzazioni conformi alla raccolta di tratti specificata.

In genere lo sviluppatore passerà una raccolta di tratti parzialmente specificata al AppearanceForTraitCollection metodo , ad esempio una classe di dimensioni orizzontali di Compact, in modo da poter personalizzare qualsiasi visualizzazione nell'applicazione compattata.

UIImage

Un'altra classe a cui Apple ha aggiunto Trait Collection è UIImage. In passato lo sviluppatore doveva specificare un @1X e @2x versione di qualsiasi asset grafico bitmap che avrebbero dovuto includere nell'applicazione (ad esempio un'icona).

iOS 8 è stato ampliato per consentire allo sviluppatore di includere più versioni di un'immagine in un catalogo immagini basato su una raccolta di tratti. Ad esempio, lo sviluppatore potrebbe includere un'immagine più piccola per l'uso di una classe Di tratto compatto e un'immagine di dimensioni complete per qualsiasi altra raccolta.

Quando una delle immagini viene usata all'interno di una UIImageView classe, la visualizzazione immagini visualizzerà automaticamente la versione corretta dell'immagine per la relativa raccolta di tratti. Se l'ambiente del tratto cambia (ad esempio l'utente che passa da verticale a orizzontale), la visualizzazione immagini selezionerà automaticamente le nuove dimensioni dell'immagine in modo che corrispondano alla nuova raccolta di tratti e ne cambieranno le dimensioni in modo che corrispondano a quelle della versione corrente dell'immagine visualizzata.

UIImageAsset

Apple ha aggiunto una nuova classe a iOS 8 chiamata UIImageAsset per offrire allo sviluppatore ancora più controllo sulla selezione delle immagini.

Un asset immagine esegue il wrapping di tutte le diverse versioni di un'immagine e consente allo sviluppatore di richiedere un'immagine specifica corrispondente a una raccolta di tratti passata. Le immagini possono essere aggiunte o rimosse da un asset immagine, in tempo reale.

Per altre informazioni sugli asset di immagini, vedere la documentazione uiImageAsset di Apple.

Combinazione di raccolte di caratteri

Un'altra funzione che uno sviluppatore può eseguire su Trait Collections consiste nell'aggiungere due insieme che comporterà la raccolta combinata, in cui i valori non specificati da una raccolta vengono sostituiti dai valori specificati in un secondo. Questa operazione viene eseguita usando il FromTraitsFromCollections metodo della UITraitCollection classe .

Come indicato in precedenza, se uno dei tratti non è specificato in una delle raccolte di caratteristiche e viene specificato in un altro, il valore verrà impostato sulla versione specificata. Tuttavia, se sono presenti più versioni di un determinato valore specificato, il valore dell'ultima raccolta di tratti sarà il valore utilizzato.

Controller di visualizzazione adattiva

Questa sezione illustra in dettaglio il modo in cui i controller di visualizzazione e visualizzazione iOS hanno adottato i concetti delle classi tratti e dimensioni per essere automaticamente più adattivi nelle applicazioni dello sviluppatore.

Controller di visualizzazione divisa

Una delle classi View Controller che ha modificato di più in iOS 8 è la UISplitViewController classe . In passato, lo sviluppatore usava spesso un controller split view nella versione iPad dell'applicazione e quindi avrebbe dovuto fornire una versione completamente diversa della gerarchia di visualizzazione per la versione i Telefono dell'app.

In iOS 8 la UISplitViewController classe è disponibile in entrambe le piattaforme (iPad e i Telefono), che consente allo sviluppatore di creare una gerarchia del controller di visualizzazione che funzionerà sia per i Telefono che per iPad.

Quando un i Telefono è in orizzontale, il controller di visualizzazione divisa presenterà le visualizzazioni affiancate, proprio come quando viene visualizzato su un iPad.

Override dei tratti

Tratto Ambienti a catena dal contenitore padre fino ai contenitori figlio, come nell'immagine seguente che mostra un controller di visualizzazione divisa in un iPad nell'orientamento orizzontale:

A Split View Controller on an iPad in the landscape orientation

Poiché l'iPad ha una classe Di dimensioni regolari sia negli orientamenti orizzontali che verticali, la visualizzazione divisa visualizzerà sia le visualizzazioni master che di dettaglio.

In un i Telefono, in cui la classe Size è compatta in entrambi gli orientamenti, il controller split view visualizza solo la visualizzazione dei dettagli, come illustrato di seguito:

The Split View Controller only displays the detail view

In un'applicazione in cui lo sviluppatore vuole visualizzare sia la visualizzazione master che quella dettagliata in un oggetto i Telefono nell'orientamento orizzontale, lo sviluppatore deve inserire un contenitore padre per il controller split view ed eseguire l'override della raccolta di tratti. Come illustrato nella figura seguente:

The developer must insert a parent container for the Split View Controller and override the Trait Collection

Un UIView oggetto viene impostato come elemento padre del controller di divisione visualizzazione e il SetOverrideTraitCollection metodo viene chiamato nella visualizzazione passando una nuova raccolta di tratti e destinata al controller di visualizzazione divisa. La nuova raccolta di tratti esegue l'override di HorizontalSizeClass, impostandola su Regular, in modo che il controller Dividi visualizzazione visualizzi sia le visualizzazioni master che di dettaglio su un i Telefono nell'orientamento orizzontale.

Si noti che è VerticalSizeClass stato impostato su unspecified, che consente di aggiungere la nuova raccolta di tratti all'insieme trait nell'elemento padre, generando un oggetto Compact VerticalSizeClass per il controller di divisione visualizzazione figlio.

Modifiche del tratto

Questa sezione esaminerà in dettaglio il modo in cui le raccolte di tratti passano quando cambia l'ambiente del tratto. Ad esempio, quando il dispositivo viene ruotato da verticale a orizzontale.

The portrait to landscape Trait Changes overview

Prima di tutto, iOS 8 esegue alcune operazioni di configurazione per prepararsi alla transizione. Successivamente, il sistema anima lo stato di transizione. Infine, iOS 8 pulisce tutti gli stati temporanei necessari durante la transizione.

iOS 8 fornisce diversi callback che lo sviluppatore può usare per partecipare alla modifica del tratto, come illustrato nella tabella seguente:

Fase Richiamata Descrizione
Attrezzaggio
  • WillTransitionToTraitCollection
  • TraitCollectionDidChange
  • Questo metodo viene chiamato all'inizio di una modifica del tratto prima che una raccolta di tratti venga impostata sul nuovo valore.
  • Il metodo viene chiamato quando il valore della raccolta di tratti è cambiato, ma prima che venga eseguita un'animazione.
Animazione WillTransitionToTraitCollection Il coordinatore della transizione passato a questo metodo ha una AnimateAlongside proprietà che consente allo sviluppatore di aggiungere animazioni che verranno eseguite insieme alle animazioni predefinite.
Eliminazione WillTransitionToTraitCollection Fornisce un metodo che consente agli sviluppatori di includere il proprio codice di pulizia dopo l'esecuzione della transizione.

Il WillTransitionToTraitCollection metodo è ideale per animare i controller di visualizzazione insieme alle modifiche della raccolta di tratti. Il WillTransitionToTraitCollection metodo è disponibile solo nei controller di visualizzazione ( UIViewController) e non in altri ambienti di tratto, ad esempio UIViews.

è TraitCollectionDidChange ideale per lavorare con la UIView classe, in cui lo sviluppatore vuole aggiornare l'interfaccia utente man mano che cambiano i tratti.

Compressione dei controller di visualizzazione divisa

Si esaminerà ora in dettaglio cosa accade quando un controller di visualizzazione suddivisa si comprime da una colonna a una vista a una colonna. Come parte di questa modifica, sono necessari due processi:

  • Per impostazione predefinita, il controller di visualizzazione divisa userà il controller di visualizzazione principale quando si verifica la visualizzazione dopo la compressione. Lo sviluppatore può eseguire l'override di questo comportamento eseguendo l'override GetPrimaryViewControllerForCollapsingSplitViewController del metodo di UISplitViewControllerDelegate e fornendo qualsiasi controller di visualizzazione che desidera visualizzare nello stato compresso.
  • Il controller di visualizzazione secondario deve essere unito al controller di visualizzazione primario. In genere lo sviluppatore non dovrà eseguire alcuna azione per questo passaggio; Il controller split view include la gestione automatica di questa fase in base al dispositivo hardware. Tuttavia, potrebbero esserci alcuni casi speciali in cui lo sviluppatore vuole interagire con questa modifica. La chiamata al CollapseSecondViewController metodo di UISplitViewControllerDelegate consente di visualizzare il controller di visualizzazione master quando si verifica il compressione anziché la visualizzazione dettagli.

Espansione del controller di visualizzazione divisa

Si esaminerà ora in dettaglio cosa accade quando un controller di visualizzazione divisa viene espanso da uno stato compresso. Ancora una volta, esistono due fasi che devono verificarsi:

  • Prima di tutto, definire il nuovo controller di visualizzazione primario. Per impostazione predefinita, il controller di divisione visualizzazione userà automaticamente il controller di visualizzazione primaria dalla visualizzazione compressa. Anche in questo caso, lo sviluppatore può eseguire l'override di questo comportamento usando il GetPrimaryViewControllerForExpandingSplitViewController metodo di UISplitViewControllerDelegate .
  • Dopo aver scelto il controller di visualizzazione primario, è necessario ricreare il controller di visualizzazione secondario. Anche in questo caso, il controller split view include la gestione automatica di questa fase in base al dispositivo hardware. Lo sviluppatore può eseguire l'override di questo comportamento chiamando il SeparateSecondaryViewController metodo di UISplitViewControllerDelegate .

In un controller di visualizzazione divisa, il controller di visualizzazione primario svolge un ruolo sia nell'espansione che nella compressione delle visualizzazioni implementando i CollapseSecondViewController metodi e SeparateSecondaryViewController di UISplitViewControllerDelegate. UINavigationController implementa questi metodi per eseguire automaticamente il push e il pop del controller visualizzazione secondaria.

Visualizzazione dei controller di visualizzazione

Un'altra modifica apportata da Apple a iOS 8 è il modo in cui lo sviluppatore mostra i controller di visualizzazione. In passato, se l'applicazione aveva un controller di visualizzazione foglia (ad esempio un controller di visualizzazione tabella) e lo sviluppatore ne ha mostrato uno diverso (ad esempio, in risposta al tocco dell'utente su una cella), l'applicazione raggiungeva la gerarchia del controller al controller di visualizzazione di spostamento e chiamerà il PushViewController metodo su di esso per visualizzare la nuova visualizzazione.

Questo ha presentato un accoppiamento molto stretto tra il controller di spostamento e l'ambiente in cui era in esecuzione. In iOS 8, Apple ha disaccoppiato questo fornendo due nuovi metodi:

  • ShowViewController : si adatta per visualizzare il nuovo controller di visualizzazione in base al relativo ambiente. Ad esempio, in un UINavigationController oggetto semplicemente esegue il push della nuova visualizzazione nello stack. In un controller di visualizzazione divisa il nuovo controller di visualizzazione verrà visualizzato sul lato sinistro come nuovo controller di visualizzazione primario. Se non è presente alcun controller di visualizzazione contenitore, la nuova visualizzazione verrà visualizzata come controller di visualizzazione modale.
  • ShowDetailViewController : funziona in modo simile a ShowViewController, ma viene implementato in un controller di visualizzazione divisa per sostituire la visualizzazione dei dettagli con il nuovo controller di visualizzazione passato. Se il controller di divisione visualizzazione è compresso (come potrebbe essere visualizzato in un'applicazione i Telefono), la chiamata verrà reindirizzata al ShowViewController metodo e la nuova visualizzazione verrà visualizzata come controller di visualizzazione primaria. Anche in questo caso, se non è presente alcun controller di visualizzazione contenitore, la nuova visualizzazione verrà visualizzata come controller di visualizzazione modale.

Questi metodi funzionano iniziando dal controller visualizzazione foglia e passando verso l'alto nella gerarchia di visualizzazione fino a trovare il controller di visualizzazione contenitore corretto per gestire la visualizzazione della nuova visualizzazione.

Gli sviluppatori possono implementare ShowViewController e ShowDetailViewController in propri controller di visualizzazione personalizzati per ottenere le stesse funzionalità automatizzate fornite UINavigationController e UISplitViewController fornite.

Funzionamento

In questa sezione verrà illustrato come questi metodi vengono effettivamente implementati in iOS 8. Esaminiamo prima di tutto il nuovo GetTargetForAction metodo:

The new GetTargetForAction method

Questo metodo esegue la catena di gerarchie fino a quando non viene trovato il controller di visualizzazione contenitore corretto. Ad esempio:

  1. Se viene chiamato un ShowViewController metodo, il primo controller di visualizzazione nella catena che implementa questo metodo è il controller di spostamento, quindi viene usato come elemento padre della nuova visualizzazione.
  2. Se invece è stato chiamato un ShowDetailViewController metodo, il controller di divisione visualizzazione è il primo controller di visualizzazione a implementarlo, quindi viene usato come elemento padre.

Il GetTargetForAction metodo funziona individuando un controller di visualizzazione che implementa un'azione specificata e quindi chiedendo al controller di visualizzazione se vuole ricevere tale azione. Poiché questo metodo è pubblico, gli sviluppatori possono creare metodi personalizzati che funzionano esattamente come i ShowViewController metodi predefiniti e ShowDetailViewController .

Presentazione adattiva

In iOS 8 Apple ha fatto anche le presentazioni popover ( UIPopoverPresentationController) adattive. Pertanto, un controller visualizzazione presentazione popover presenterà automaticamente una normale visualizzazione popover in una classe di dimensioni regolari, ma lo visualizzerà a schermo intero in una classe dimensioni orizzontale compatta (ad esempio in un i Telefono).

Per gestire le modifiche all'interno del sistema storyboard unificato, è stato creato un nuovo oggetto controller per gestire i controller di visualizzazione presentati : UIPresentationController. Questo controller viene creato dal momento in cui il controller di visualizzazione viene presentato fino a quando non viene ignorato. Poiché si tratta di una classe di gestione, può essere considerata una superclasse sul controller di visualizzazione in quanto risponde alle modifiche del dispositivo che influiscono sul controller di visualizzazione (ad esempio l'orientamento) che vengono quindi reinserito nel controller di visualizzazione i controlli Presentation Controller.

Quando lo sviluppatore presenta un controller di visualizzazione usando il PresentViewController metodo , la gestione del processo di presentazione viene passata a UIKit. UiKit gestisce ( tra le altre cose) il controller corretto per lo stile creato, con l'unica eccezione che si verifica quando un controller di visualizzazione ha lo stile impostato su UIModalPresentationCustom. In questo caso, l'applicazione può fornire il proprio PresentationController anziché usare il UIKit controller.

Stili di presentazione personalizzati

Con uno stile di presentazione personalizzato, gli sviluppatori hanno la possibilità di usare un controller presentazione personalizzato. Questo controller personalizzato può essere usato per modificare l'aspetto e il comportamento della visualizzazione a cui è associato.

Uso delle classi di dimensioni

Il progetto Xamarin adattivo Foto incluso in questo articolo fornisce un esempio funzionante dell'uso di classi di dimensioni e controller di visualizzazione adattiva in un'applicazione interfaccia unificata iOS 8.

Mentre l'applicazione crea completamente l'interfaccia utente dal codice, anziché creare uno storyboard unificato usando Interface Builder di Xcode, si applicano le stesse tecniche.

Si esaminerà ora in modo più approfondito il modo in cui il progetto di Foto adattivo implementa diverse funzionalità della classe di dimensioni in iOS 8 per creare un'applicazione adattiva.

Adattamento alle modifiche dell'ambiente dei tratti

Quando si esegue l'applicazione Adaptive Foto in un i Telefono, quando l'utente ruota il dispositivo da verticale a orizzontale, il controller split view visualizzerà sia la visualizzazione master che quella dei dettagli:

The Split View Controller will display both the master and details view as seen here

Questa operazione viene eseguita eseguendo l'override del UpdateConstraintsForTraitCollection metodo del controller di visualizzazione e modificando i vincoli in base al valore di VerticalSizeClass. Ad esempio:

public void UpdateConstraintsForTraitCollection (UITraitCollection collection)
{
    var views = NSDictionary.FromObjectsAndKeys (
        new object[] { TopLayoutGuide, ImageView, NameLabel, ConversationsLabel, PhotosLabel },
        new object[] { "topLayoutGuide", "imageView", "nameLabel", "conversationsLabel", "photosLabel" }
    );

    var newConstraints = new List<NSLayoutConstraint> ();
    if (collection.VerticalSizeClass == UIUserInterfaceSizeClass.Compact) {
        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|[imageView]-[nameLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("[imageView]-[conversationsLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("[imageView]-[photosLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:|[topLayoutGuide]-[nameLabel]-[conversationsLabel]-[photosLabel]",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:|[topLayoutGuide][imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.Add (NSLayoutConstraint.Create (ImageView, NSLayoutAttribute.Width, NSLayoutRelation.Equal,
            View, NSLayoutAttribute.Width, 0.5f, 0.0f));
    } else {
        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|[imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[nameLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[conversationsLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[photosLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:[topLayoutGuide]-[nameLabel]-[conversationsLabel]-[photosLabel]-20-[imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));
    }

    if (constraints != null)
        View.RemoveConstraints (constraints.ToArray ());

    constraints = newConstraints;
    View.AddConstraints (constraints.ToArray ());
}

Aggiunta di animazioni di transizione

Quando il controller di visualizzazione divisa nell'applicazione adaptive Foto passa da compresso a espanso, le animazioni vengono aggiunte alle animazioni predefinite eseguendo l'override del WillTransitionToTraitCollection metodo del controller di visualizzazione. Ad esempio:

public override void WillTransitionToTraitCollection (UITraitCollection traitCollection, IUIViewControllerTransitionCoordinator coordinator)
{
    base.WillTransitionToTraitCollection (traitCollection, coordinator);
    coordinator.AnimateAlongsideTransition ((UIViewControllerTransitionCoordinatorContext) => {
        UpdateConstraintsForTraitCollection (traitCollection);
        View.SetNeedsLayout ();
    }, (UIViewControllerTransitionCoordinatorContext) => {
    });
}

Override dell'ambiente del tratto

Come illustrato in precedenza, l'applicazione Adaptive Foto impone al controller di split view di visualizzare sia i dettagli che le visualizzazioni master quando il dispositivo i Telefono è nella visualizzazione orizzontale.

Questa operazione è stata eseguita usando il codice seguente nel controller di visualizzazione:

private UITraitCollection forcedTraitCollection = new UITraitCollection ();
...

public UITraitCollection ForcedTraitCollection {
    get {
        return forcedTraitCollection;
    }

    set {
        if (value != forcedTraitCollection) {
            forcedTraitCollection = value;
            UpdateForcedTraitCollection ();
        }
    }
}
...

public override void ViewWillTransitionToSize (SizeF toSize, IUIViewControllerTransitionCoordinator coordinator)
{
    ForcedTraitCollection = toSize.Width > 320.0f ?
         UITraitCollection.FromHorizontalSizeClass (UIUserInterfaceSizeClass.Regular) :
         new UITraitCollection ();

    base.ViewWillTransitionToSize (toSize, coordinator);
}

public void UpdateForcedTraitCollection ()
{
    SetOverrideTraitCollection (forcedTraitCollection, viewController);
}

Espansione e compressione del controller di visualizzazione divisa

Si esaminerà ora come è stato implementato il comportamento di espansione e compressione del controller split view in Xamarin. AppDelegateIn , quando viene creato il controller di visualizzazione divisa, il relativo delegato viene assegnato per gestire queste modifiche:

public class SplitViewControllerDelegate : UISplitViewControllerDelegate
{
    public override bool CollapseSecondViewController (UISplitViewController splitViewController,
        UIViewController secondaryViewController, UIViewController primaryViewController)
    {
        AAPLPhoto photo = ((CustomViewController)secondaryViewController).Aapl_containedPhoto (null);
        if (photo == null) {
            return true;
        }

        if (primaryViewController.GetType () == typeof(CustomNavigationController)) {
            var viewControllers = new List<UIViewController> ();
            foreach (var controller in ((UINavigationController)primaryViewController).ViewControllers) {
                var type = controller.GetType ();
                MethodInfo method = type.GetMethod ("Aapl_containsPhoto");

                if ((bool)method.Invoke (controller, new object[] { null })) {
                    viewControllers.Add (controller);
                }
            }

            ((UINavigationController)primaryViewController).ViewControllers = viewControllers.ToArray<UIViewController> ();
        }

        return false;
    }

    public override UIViewController SeparateSecondaryViewController (UISplitViewController splitViewController,
        UIViewController primaryViewController)
    {
        if (primaryViewController.GetType () == typeof(CustomNavigationController)) {
            foreach (var controller in ((CustomNavigationController)primaryViewController).ViewControllers) {
                var type = controller.GetType ();
                MethodInfo method = type.GetMethod ("Aapl_containedPhoto");

                if (method.Invoke (controller, new object[] { null }) != null) {
                    return null;
                }
            }
        }

        return new AAPLEmptyViewController ();
    }
}

Il SeparateSecondaryViewController metodo verifica se viene visualizzata una foto e agisce in base a tale stato. Se non viene visualizzata alcuna foto, comprime il controller di visualizzazione secondario in modo che venga visualizzato il controller di visualizzazione master.

Il CollapseSecondViewController metodo viene usato quando si espande il controller di visualizzazione divisa per verificare se sono presenti foto nello stack, se è così che viene compresso di nuovo in tale visualizzazione.

Spostamento tra controller di visualizzazione

Si esaminerà ora il modo in cui l'applicazione adattiva Foto si sposta tra i controller di visualizzazione. AAPLConversationViewController Nella classe quando l'utente seleziona una cella dalla tabella, viene chiamato il ShowDetailViewController metodo per visualizzare la visualizzazione dei dettagli:

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    var photo = PhotoForIndexPath (indexPath);
    var controller = new AAPLPhotoViewController ();
    controller.Photo = photo;

    int photoNumber = indexPath.Row + 1;
    int photoCount = (int)Conversation.Photos.Count;
    controller.Title = string.Format ("{0} of {1}", photoNumber, photoCount);
    ShowDetailViewController (controller, this);
}

Visualizzazione di indicatori di divulgazione

Nell'applicazione Foto adattiva ci sono diversi luoghi in cui gli indicatori di divulgazione sono nascosti o visualizzati in base alle modifiche apportate all'ambiente del tratto. Questa operazione viene gestita con il codice seguente:

public bool Aapl_willShowingViewControllerPushWithSender ()
{
    var selector = new Selector ("Aapl_willShowingViewControllerPushWithSender");
    var target = this.GetTargetViewControllerForAction (selector, this);

    if (target != null) {
        var type = target.GetType ();
        MethodInfo method = type.GetMethod ("Aapl_willShowingDetailViewControllerPushWithSender");
        return (bool)method.Invoke (target, new object[] { });
    } else {
        return false;
    }
}

public bool Aapl_willShowingDetailViewControllerPushWithSender ()
{
    var selector = new Selector ("Aapl_willShowingDetailViewControllerPushWithSender");
    var target = this.GetTargetViewControllerForAction (selector, this);

    if (target != null) {
        var type = target.GetType ();
        MethodInfo method = type.GetMethod ("Aapl_willShowingDetailViewControllerPushWithSender");
        return (bool)method.Invoke (target, new object[] { });
    } else {
        return false;
    }
}

Questi vengono implementati usando il GetTargetViewControllerForAction metodo descritto in dettaglio in precedenza.

Quando un controller visualizzazione tabella visualizza i dati, usa i metodi implementati in precedenza per verificare se si verificherà o meno un push e se visualizzare o nascondere di conseguenza l'indicatore di divulgazione:

public override void WillDisplay (UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
    bool pushes = ShouldShowConversationViewForIndexPath (indexPath) ?
         Aapl_willShowingViewControllerPushWithSender () :
         Aapl_willShowingDetailViewControllerPushWithSender ();

    cell.Accessory = pushes ? UITableViewCellAccessory.DisclosureIndicator : UITableViewCellAccessory.None;
    var conversation = ConversationForIndexPath (indexPath);
    cell.TextLabel.Text = conversation.Name;
}

Nuovo ShowDetailTargetDidChangeNotification tipo

Apple ha aggiunto un nuovo tipo di notifica per l'uso di classi di dimensioni e ambienti di tratto dall'interno di un controller split view, ShowDetailTargetDidChangeNotification. Questa notifica viene inviata ogni volta che cambia la visualizzazione dettagli di destinazione per un controller di visualizzazione divisa, ad esempio quando il controller si espande o comprime.

L'applicazione Adaptive Foto usa questa notifica per aggiornare lo stato dell'indicatore di divulgazione quando cambia il controller visualizzazione dettagli:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    TableView.RegisterClassForCellReuse (typeof(UITableViewCell), AAPLListTableViewControllerCellIdentifier);
    NSNotificationCenter.DefaultCenter.AddObserver (this, new Selector ("showDetailTargetDidChange:"),
        UIViewController.ShowDetailTargetDidChangeNotification, null);
    ClearsSelectionOnViewWillAppear = false;
}

Esaminare in modo più approfondito l'applicazione adattiva Foto per visualizzare tutti i modi in cui è possibile usare classi di dimensioni, raccolte di tratti e controller di visualizzazione adattiva per creare facilmente un'applicazione unificata in Xamarin.iOS.

Storyboard unificati

Novità di iOS 8, gli storyboard unificati consentono allo sviluppatore di creare un file storyboard unificato che può essere visualizzato in dispositivi i Telefono e iPad scegliendo più classi di dimensioni. Usando storyboard unificati, lo sviluppatore scrive meno codice specifico dell'interfaccia utente e ha una sola progettazione dell'interfaccia per creare e gestire.

I vantaggi principali degli storyboard unificati sono:

  • Usa lo stesso file storyboard per i Telefono e iPad.
  • Eseguire la distribuzione all'indietro in iOS 6 e iOS 7.
  • Visualizzare in anteprima il layout per dispositivi, orientamenti e versioni del sistema operativo diversi.

Abilitazione delle classi di dimensioni

Per impostazione predefinita, qualsiasi nuovo progetto Xamarin.iOS userà classi di dimensioni. Per usare classi di dimensioni e segue adattivi all'interno di uno storyboard di un progetto precedente, deve prima essere convertito nel formato storyboard unificato Xcode 6 e la casella di controllo Usa classi dimensioni è selezionata all'interno di Xcode File Inspector per gli storyboard.

Schermate di avvio dinamico

Il file della schermata di avvio viene visualizzato come schermata iniziale mentre un'applicazione iOS viene avviata per fornire feedback all'utente che l'app sta effettivamente avviando. Prima di iOS 8, lo sviluppatore dovrà includere più Default.png asset di immagine per ogni tipo di dispositivo, orientamento e risoluzione dello schermo su cui l'applicazione sarebbe in esecuzione. Ad esempio, Default@2x.png, Default-Landscape@2x~ipad.png, Default-Portrait@2x~ipad.pnge così via.

Il factoring nei nuovi dispositivi i Telefono 6 e i Telefono 6 Plus (e il prossimo Apple Watch) con tutti i dispositivi i Telefono e iPad esistenti, rappresenta una vasta gamma di dimensioni, orientamenti e risoluzioni variabili degli asset di immagine dello schermo di Default.png avvio che devono essere creati e mantenuti. Inoltre, questi file possono essere abbastanza grandi e "bloat" il bundle dell'applicazione finale, aumentando la quantità di tempo necessaria per scaricare l'applicazione dall'App Store di iTunes (possibilmente mantenendo che sia in grado di essere recapitata su una rete cellulare) e aumentando la quantità di spazio di archiviazione richiesto nel dispositivo dell'utente finale.

Novità di iOS 8, lo sviluppatore può creare un singolo file atomico .xib in Xcode che usa classi di layout automatico e dimensioni per creare una schermata di avvio dinamico che funzionerà per ogni dispositivo, risoluzione e orientamento. Questo non solo riduce la quantità di lavoro richiesto dallo sviluppatore per creare e gestire tutti gli asset di immagine necessari, ma riduce notevolmente le dimensioni del bundle installato dell'applicazione.

Le schermate di avvio dinamico presentano le limitazioni e le considerazioni seguenti:

  • Usare solo UIKit le classi.
  • Usare una singola visualizzazione radice che è un UIView oggetto o UIViewController .
  • Non stabilire connessioni al codice dell'applicazione (non aggiungere azioni o outlet).
  • Non aggiungere UIWebView oggetti.
  • Non usare classi personalizzate.
  • Non usare gli attributi di runtime.

Tenendo presenti le linee guida precedenti, si esaminerà l'aggiunta di una schermata di avvio dinamico a un progetto Xamarin iOS 8 esistente.

Effettua le operazioni seguenti:

  1. Aprire Visual Studio per Mac e caricare la soluzione per aggiungere la schermata di avvio dinamico.

  2. Nel Esplora soluzioni fare clic con il pulsante destro del mouse sul MainStoryboard.storyboard file e scegliere Apri con>Xcode Interface Builder:

    Open With Xcode Interface Builder

  3. In Xcode selezionare File>nuovo>file...:

    Select File / New

  4. Selezionare la schermata di avvio dell'interfaccia>utente iOS>e fare clic sul pulsante Avanti:

    Select iOS / User Interface / Launch Screen

  5. Assegnare un nome al file LaunchScreen.xib e fare clic sul pulsante Crea :

    Name the file LaunchScreen.xib

  6. Modificare la progettazione della schermata di avvio aggiungendo elementi grafici e usando Vincoli layout per posizionarli per i dispositivi, gli orientamenti e le dimensioni dello schermo specificati:

    Editing the design of the launch screen

  7. Salvare le modifiche in LaunchScreen.xib.

  8. Selezionare la destinazione delle applicazioni e la scheda Generale :

    Select the Applications Target and the General tab

  9. Fare clic sul pulsante Scegli Info.plist , selezionare per l'app Info.plist Xamarin e fare clic sul pulsante Scegli :

    Select the Info.plist for the Xamarin app

  10. Nella sezione Icone dell'app e immagini di avvio aprire l'elenco a discesa Avvia file schermata e scegliere il LaunchScreen.xib file creato in precedenza:

    Choose the LaunchScreen.xib

  11. Salvare le modifiche apportate al file e tornare a Visual Studio per Mac.

  12. Attendere Visual Studio per Mac completare la sincronizzazione delle modifiche con Xcode.

  13. Nella Esplora soluzioni fare clic con il pulsante destro del mouse sulla cartella Risorsa e scegliere Aggiungi>file...:

    Select Add / Add Files...

  14. Selezionare il LaunchScreen.xib file creato in precedenza e fare clic sul pulsante Apri :

    Select the LaunchScreen.xib file

  15. Compila l'applicazione.

Test della schermata di avvio dinamico

In Visual Studio per Mac selezionare il simulatore i Telefono 4 Retina ed eseguire l'applicazione. La schermata di avvio dinamico verrà visualizzata nel formato e nell'orientamento corretti:

The Dynamic Launch Screen displayed in the vertical orientation

Arrestare l'applicazione in Visual Studio per Mac e selezionare un dispositivo iPad iOS 8. Eseguire l'applicazione e la schermata di avvio verrà formattata correttamente per questo dispositivo e l'orientamento:

The Dynamic Launch Screen displayed in the horizontal orientation

Tornare a Visual Studio per Mac e arrestare l'esecuzione dell'applicazione.

Uso di iOS 7

Per mantenere la compatibilità con le versioni precedenti con iOS 7, includere solo gli asset di immagine normali Default.png nell'applicazione iOS 8. IOS tornerà al comportamento precedente e userà tali file come schermata di avvio quando viene eseguito in un dispositivo iOS 7.

Per visualizzare un'implementazione di una schermata di avvio dinamico in Xamarin, vedere l'applicazione iOS 8 di esempio iOS 8 associata a questo documento.

Riepilogo

Questo articolo ha esaminato rapidamente le classi di dimensioni e come influiscono sul layout nei dispositivi i Telefono e iPad. Ha illustrato in che modo Traits, Trait Environments e Trait Collections funzionano con le classi size per creare interfacce unificate. Sono stati esaminati brevemente i controller di visualizzazione adattivi e il modo in cui funzionano con le classi di dimensioni all'interno di interfacce unificate. È stata esaminata l'implementazione di classi di dimensioni e interfacce unificate completamente dal codice C# all'interno di un'applicazione Xamarin iOS 8.

Infine, questo articolo ha illustrato le nozioni di base sulla creazione di un'unica schermata di avvio dinamica che verrà visualizzata come schermata di avvio in ogni dispositivo iOS 8.