Guiones gráficos unificados en Xamarin.iOS
iOS 8 incluye un nuevo mecanismo más sencillo para crear la interfaz de usuario: el guión gráfico unificado. Con un guión gráfico único para cubrir todos los distintos tamaños de pantalla de hardware, las vistas rápidas y con capacidad de respuesta se pueden crear en un estilo "diseño una vez, usar varios".
Como el desarrollador ya no necesita crear un guión gráfico independiente y específico para dispositivos iPhone y iPad, tienen la flexibilidad de diseñar aplicaciones con una interfaz común y, a continuación, personalizar esa interfaz para diferentes clases de tamaño. De esta manera, una aplicación se puede adaptar a los puntos fuertes de cada factor de forma y cada interfaz de usuario se puede ajustar para proporcionar la mejor experiencia.
Clases de tamaño
Antes de iOS 8, el desarrollador usaba y para diferenciar entre los modos vertical y horizontal, y entre iPhone UIInterfaceOrientationUIInterfaceIdiom y iPad dispositivos. En iOS8, la orientación y el dispositivo se determinan mediante clases de tamaño.
Los dispositivos se definen mediante clases de tamaño, tanto en ejes verticales como horizontales, y hay dos tipos de clases de tamaño en iOS 8:
- Normal: se trata de un tamaño de pantalla grande (por ejemplo, un iPad) o un televisor que da la impresión de un tamaño grande (por ejemplo,
- Compacto: se trata de para dispositivos más pequeños (por ejemplo, un iPhone). Este tamaño tiene en cuenta la orientación del dispositivo.
Si los dos conceptos se usan juntos, el resultado es una cuadrícula de 2 x 2 que define los distintos tamaños posibles que se pueden usar en las dos orientaciones diferentes, como se muestra en el diagrama siguiente:
El desarrollador puede crear un controlador de vistas que use cualquiera de las cuatro posibilidades que darían lugar a diseños diferentes (como se ve en los gráficos anteriores).
iPad size (Clases)
El iPad, debido al tamaño, tiene un tamaño de clase normal para ambas orientaciones.
iPhone size (Clases)
El iPhone tiene clases de tamaño diferentes en función de la orientación del dispositivo:
- Cuando el dispositivo está en modo vertical, la pantalla tiene una clase compacta horizontal y regular verticalmente
- Cuando el dispositivo está en modo horizontal, las clases de pantalla se invierten desde el modo vertical.
iPhone 6 clases de tamaño más
Los tamaños son los mismos que los iPhone anteriores cuando están en orientación vertical, pero diferentes en horizontal:
Dado que iPhone 6 Plus tiene una pantalla lo suficientemente grande, puede tener una clase de tamaño de ancho normal en el modo Horizontal.
Compatibilidad con una nueva escala de pantalla
El iPhone 6 Plus usa una nueva pantalla Hd de Retina con un factor de escala de pantalla de 3,0 (tres veces la resolución iPhone pantalla original). Para proporcionar la mejor experiencia posible en estos dispositivos, incluya nuevas ilustraciones diseñadas para esta escala de pantalla. En Xcode 6 y posteriores, los catálogos de recursos pueden incluir imágenes con tamaños 1x, 2x y 3x. simplemente agregue los nuevos recursos de imagen e iOS elegirá los recursos correctos cuando se ejecute en iPhone 6 Plus.
El comportamiento de carga de imágenes en iOS también reconoce un @3x sufijo en los archivos de imagen. Por ejemplo, si el desarrollador incluye un recurso de imagen (en diferentes resoluciones) en el paquete de la aplicación con los siguientes nombres de archivo: MonkeyIcon.pngMonkeyIcon@2x.png , y MonkeyIcon@3x.png . En el iPhone 6 Más, la imagen se usará automáticamente si el desarrollador MonkeyIcon@3x.png carga una imagen con el código siguiente:
UIImage icon = UIImage.FromFile("MonkeyImage.png");
Pantallas de inicio dinámico
El archivo de pantalla de inicio se muestra como una pantalla de presentación mientras se inicia una aplicación de iOS para proporcionar comentarios al usuario de que la aplicación se está iniciando realmente. Antes de iOS 8, el desarrollador tendría que incluir varios recursos de imagen para cada tipo de dispositivo, orientación y resolución de pantalla en los que se Default.png ejecutaría la aplicación.
Como novedad de iOS 8, el desarrollador puede crear un único archivo atómico en Xcode que usa clases de diseño automático y tamaño para crear una pantalla de inicio dinámico que funcionará para cada dispositivo, resolución y .xib orientación. .xib Esto no solo reduce la cantidad de trabajo necesario para que el desarrollador cree y mantenga todos los recursos de imagen necesarios, sino que reduce el tamaño del paquete instalado de la aplicación.
Rasgos
Los rasgos son propiedades que se pueden usar para determinar cómo cambia un diseño a medida que cambia su entorno. Constan de un conjunto de propiedades (y basadas en ), así como la expresión de interfaz HorizontalSizeClass ( ) y la escala de VerticalSizeClassUIUserInterfaceSizeClassUIUserInterfaceIdiom presentación.
Todos los estados anteriores se encapsulan en un contenedor al que Apple hace referencia como colección de rasgos ( ), que contiene no solo las propiedades, sino UITraitCollection también sus valores.
Entorno de rasgos
Los entornos de rasgos son una nueva interfaz en iOS 8 y pueden devolver una colección de rasgos para los siguientes objetos:
- Pantallas (
UIScreens). - Windows (
UIWindows). - Controladores de vista (
UIViewController). - Vistas (
UIView). - Controlador de presentación (
UIPresentationController).
El desarrollador usa la colección trait devuelta por un entorno de rasgos para determinar cómo se debe establecer una interfaz de usuario.
Todos los entornos de rasgos hacen una jerarquía como se muestra en el diagrama siguiente:
La colección de rasgos que tienen cada uno de los entornos de rasgos anteriores fluirá, de forma predeterminada, del entorno primario al secundario.
Además de obtener la colección de rasgos actual, el entorno de rasgos tiene un método , que se puede invalidar en las subclases Vista o Controlador TraitCollectionDidChange de vista. El desarrollador puede usar este método para modificar cualquiera de los elementos de la interfaz de usuario que dependen de rasgos cuando esos rasgos han cambiado.
Colecciones típicas de rasgos
En esta sección se tratarán los tipos típicos de colecciones de rasgos que experimentará el usuario al trabajar con iOS 8.
A continuación se muestra una colección de rasgos típica que el desarrollador podría ver en un iPhone:
| Propiedad | Valor |
|---|---|
HorizontalSizeClass |
Compacto |
VerticalSizeClass |
Normal |
UserInterfaceIdom |
Teléfono |
DisplayScale |
2.0 |
El conjunto anterior representaría una colección de rasgos completos, ya que tiene valores para todas sus propiedades de rasgo.
También es posible tener una colección de rasgos a la que faltan algunos de sus valores (a los que Apple hace referencia como Sin especificar):
| Propiedad | Value |
|---|---|
HorizontalSizeClass |
Compacto |
VerticalSizeClass |
Sin especificar |
UserInterfaceIdom |
Sin especificar |
DisplayScale |
Sin especificar |
Sin embargo, por lo general, cuando el desarrollador solicita al entorno de rasgos su colección de rasgos, devolverá una colección completa como se muestra en el ejemplo anterior.
Si un entorno de rasgos (como un controlador de vista o vista) no está dentro de la jerarquía de vistas actual, el desarrollador podría obtener valores no especificados para una o varias de las propiedades de rasgo.
El desarrollador también recibirá una colección de rasgos parcialmente calificada si usa uno de los métodos de creación proporcionados por Apple, como , para UITraitCollection.FromHorizontalSizeClass crear una nueva colección.
Una operación que se puede realizar en varias colecciones de rasgos es compararlas entre sí, lo que implica preguntar a una colección de rasgos si contiene otra. Lo que significa contención es que, para cualquier rasgo especificado en la segunda colección, el valor debe coincidir exactamente con el valor de la primera colección.
Para probar dos rasgos, use el método de pasar el valor del rasgo que ContainsUITraitCollection se va a probar.
El desarrollador puede realizar las comparaciones manualmente en el código para determinar cómo crear vistas o controladores de vista. Sin embargo, usa este método internamente para proporcionar parte de su funcionalidad, como en UIKit el proxy de apariencia, por ejemplo.
Proxy de apariencia
El proxy de apariencia se introdujo en versiones anteriores de iOS para permitir a los desarrolladores personalizar las propiedades de sus vistas. Se ha ampliado en iOS 8 para admitir colecciones de rasgos.
Los servidores proxy de apariencia ahora incluyen un nuevo método, , que devuelve un nuevo proxy de apariencia para la colección de rasgos especificada que AppearanceForTraitCollection se ha pasado. Las personalizaciones que realice el desarrollador en ese proxy de apariencia solo tendrán efecto en las vistas que se ajusten a la colección de rasgos especificada.
Por lo general, el desarrollador pasará una colección de rasgos parcialmente especificada al método , como una que acaba de especificar una clase de tamaño horizontal de Compact, para que pueda personalizar cualquier vista de la aplicación que sea compacta AppearanceForTraitCollection horizontalmente.
UIImage
Otra clase a la que Apple ha agregado Trait Collection es UIImage . En el pasado, el desarrollador tenía que especificar una versión @1X y @2x de cualquier recurso gráfico con mapa de bits que se va a incluir en la aplicación (por ejemplo, un icono).
iOS 8 se ha ampliado para permitir al desarrollador incluir varias versiones de una imagen en un catálogo de imágenes basada en una colección de rasgos. Por ejemplo, el desarrollador podría incluir una imagen más pequeña para trabajar con una clase de rasgo compacto y una imagen de tamaño completo para cualquier otra colección.
Cuando se usa una de las imágenes dentro de una clase, la vista de imagen mostrará automáticamente la versión correcta de la imagen UIImageView para su colección de rasgos. Si cambia el entorno de rasgos (por ejemplo, el usuario cambia el dispositivo de vertical a horizontal), la vista de imagen seleccionará automáticamente el nuevo tamaño de imagen para que coincida con la nueva colección de rasgos y cambiará su tamaño para que coincida con el de la versión actual de la imagen que se muestra.
UIImageAsset
Apple ha agregado una nueva clase a iOS 8 llamada para proporcionar al desarrollador UIImageAsset un mayor control sobre la selección de imágenes.
Un recurso de imagen encapsula todas las distintas versiones de una imagen y permite al desarrollador solicitar una imagen específica que coincida con una colección de rasgos que se ha pasado. Las imágenes se pueden agregar o quitar de un recurso de imagen sobre la marcha.
Para más información sobre los recursos de imagen, consulte la documentación de UIImageAsset de Apple.
Combinar colecciones de rasgos
Otra función que un desarrollador puede realizar en Colecciones de rasgos es agregar dos juntos que darán como resultado la colección combinada, donde los valores no especificados de una colección se reemplazan por los valores especificados en una segunda. Esto se hace mediante FromTraitsFromCollections el método de la clase UITraitCollection .
Como se indicó anteriormente, si alguno de los rasgos no está especificado en una de las colecciones de rasgos y se especifica en otra, el valor se establecerá en la versión especificada. Sin embargo, si se especifican varias versiones de un valor determinado, el valor de la última colección de rasgos será el valor que se usa.
Controladores de vista adaptable
En esta sección se tratarán los detalles de cómo los controladores de vista y vista de iOS han adoptado los conceptos de rasgos y clases de tamaño para que sean automáticamente más adaptables en las aplicaciones del desarrollador.
Controlador de vista dividida
Una de las clases del controlador de vistas que más ha cambiado en iOS 8 es la UISplitViewController clase . En el pasado, el desarrollador solía usar un controlador de vista dividida en la versión iPad de la aplicación y, a continuación, tendría que proporcionar una versión completamente diferente de su jerarquía de vistas para la versión iPhone de la aplicación.
En iOS 8, la clase está disponible en ambas plataformas (iPad y iPhone), lo que permite al desarrollador crear una jerarquía de controlador de vista que funcionará para iPhone UISplitViewController y iPad.
Cuando un iPhone está en horizontal, el controlador de vista dividida presentará sus vistas en paralelo, tal como lo haría cuando se muestra en un iPad.
Reemplazar rasgos
Los entornos de rasgo se en cascada desde el contenedor primario hasta los contenedores secundarios, como en el gráfico siguiente que muestra un controlador de vista dividida en un iPad en la orientación horizontal:
Puesto que iPad tiene una clase de tamaño normal en las orientaciones horizontal y vertical, la vista dividida mostrará las vistas maestra y de detalles.
En un iPhone, donde la clase Size es compacta en ambas orientaciones, el controlador de vista dividida solo muestra la vista de detalles, como se muestra a continuación:
En una aplicación en la que el desarrollador quiere mostrar la vista maestra y la vista de detalles en un iPhone en la orientación horizontal, el desarrollador debe insertar un contenedor primario para el controlador de vista dividida e invalidar la colección trait. Como se muestra en el gráfico siguiente:
se establece como el elemento primario del controlador de vista dividida y se llama al método en la vista que pasa una nueva colección de rasgos y tiene como destino el controlador UIViewSetOverrideTraitCollection de vista dividida. La nueva colección trait reemplaza a , estableciendo en , para que el controlador de vista dividida muestre las vistas maestra y de detalles en un iPhone en la HorizontalSizeClassRegular orientación horizontal.
Tenga en cuenta que se estableció en , lo que permite agregar la nueva colección de rasgos a la colección de rasgos en el elemento primario, lo que da como resultado un para el controlador de VerticalSizeClassunspecified vista dividida Compact VerticalSizeClass secundario.
Cambios de rasgos
En esta sección se echará un vistazo, en detalle, a la transición de las colecciones de rasgos cuando cambia el entorno de rasgos. Por ejemplo, cuando el dispositivo gira de vertical a horizontal.
En primer lugar, iOS 8 realiza alguna configuración para prepararse para que se lleve a cabo la transición. A continuación, el sistema anima el estado de transición. Por último, iOS 8 limpia los estados temporales necesarios durante la transición.
iOS 8 proporciona varias devoluciones de llamada que el desarrollador puede usar para participar en el cambio de rasgo, como se muestra en la tabla siguiente:
| Fase | Devolución de llamada | Descripción |
|---|---|---|
| Configuración |
|
|
| Animación | WillTransitionToTraitCollection |
El Coordinador de transición que se pasa a este método tiene una propiedad que permite al desarrollador agregar animaciones que se ejecutarán junto con AnimateAlongside las animaciones predeterminadas. |
| Limpieza | WillTransitionToTraitCollection |
Proporciona un método para que los desarrolladores incluyan su propio código de limpieza después de que se lleve a cabo la transición. |
El WillTransitionToTraitCollection método es excelente para animar controladores de vista junto con los cambios de colección de rasgos. El método solo está disponible en los controladores de vista ( ) y WillTransitionToTraitCollectionUIViewController no en otros entornos de rasgos, como UIViews .
es excelente para trabajar con la clase , donde el desarrollador quiere actualizar la interfaz de usuario TraitCollectionDidChange a medida que cambian los UIView rasgos.
Contraer los controladores de vista dividida
Ahora echemos un vistazo más de cerca a lo que sucede cuando un controlador de vista dividida se contrae de una vista de dos columnas a una vista de columna. Como parte de este cambio, hay dos procesos que deben producirse:
- De forma predeterminada, el controlador de vistas divididas usará el controlador de vista principal como vista después de que se produzca la conmoción. El desarrollador puede invalidar este comportamiento invalidando el método de y proporcionando cualquier controlador de vista que quiera mostrar
GetPrimaryViewControllerForCollapsingSplitViewControllerUISplitViewControllerDelegateen estado contraído. - El controlador de vista secundario tiene que combinarse con el controlador de vista principal. Por lo general, el desarrollador no tendrá que realizar ninguna acción para este paso; El controlador de vista dividida incluye el control automático de esta fase en función del dispositivo de hardware. Sin embargo, puede haber algunos casos especiales en los que el desarrollador quiera interactuar con este cambio. Llamar al método de permite que se muestre el controlador de vista maestra cuando se produce la conmoción, en lugar de la
CollapseSecondViewControllerUISplitViewControllerDelegatevista de detalles.
Expandir el controlador de vista dividida
Ahora echemos un vistazo más de cerca a lo que sucede cuando un controlador de vista dividida se expande desde un estado contraído. Una vez más, hay dos fases que deben producirse:
- En primer lugar, defina el nuevo controlador de vista principal. De forma predeterminada, el controlador de vistas divididas usará automáticamente el controlador de vista principal de la vista contraida. De nuevo, el desarrollador puede invalidar este comportamiento mediante
GetPrimaryViewControllerForExpandingSplitViewControllerel método deUISplitViewControllerDelegate. - Una vez elegido el controlador de vista principal, se debe volver a crear el controlador de vista secundario. De nuevo, el controlador de vista dividida incluye el control automático de esta fase en función del dispositivo de hardware. El desarrollador puede invalidar este comportamiento llamando al
SeparateSecondaryViewControllermétodo deUISplitViewControllerDelegate.
En un controlador de vista dividida, el controlador de vista principal desempeña un papel en la expansión y la conste de las vistas mediante la implementación de los métodos CollapseSecondViewControllerSeparateSecondaryViewController y de UISplitViewControllerDelegate . UINavigationController implementa estos métodos para insertar y sacar automáticamente el controlador de vista secundaria.
Mostrar controladores de vista
Otro cambio que Apple ha realizado en iOS 8 es la forma en que el desarrollador muestra los controladores de vista. En el pasado, si la aplicación tenía un controlador de vista hoja (por ejemplo, un controlador de vista de tabla) y el desarrollador mostraba otro diferente (por ejemplo, en respuesta al usuario que pulsaba en una celda), la aplicación llegaba a través de la jerarquía del controlador al controlador de vista de navegación y llamaba al método en él para mostrar la PushViewController nueva vista.
Esto presentaba un acoplamiento muy estricto entre el controlador de navegación y el entorno en el que se estaba ejecutando. En iOS 8, Apple lo ha desacoplado proporcionando dos métodos nuevos:
ShowViewController: se adapta para mostrar el nuevo controlador de vistas en función de su entorno. Por ejemplo, enUINavigationControllerun , simplemente inserta la nueva vista en la pila. En un controlador de vista dividida, el nuevo controlador de vistas se presentará en el lado izquierdo como el nuevo controlador de vista principal. Si no hay ningún controlador de vista de contenedor, la nueva vista se mostrará como controlador de vista modal.ShowDetailViewController: funciona de forma similar a , pero se implementa en un controlador de vista dividida para reemplazar la vista de detalles por el nuevo controladorShowViewControllerde vista que se pasa. Si el controlador de vista dividida está contraído (como se puede ver en una aplicación de iPhone), la llamada se redirigirá al método y la nueva vista se mostrará como controlador de vistaShowViewControllerprincipal. De nuevo, si no hay ningún controlador de vista de contenedor, la nueva vista se mostrará como un controlador de vista modal.
Estos métodos funcionan empezando en el controlador de vista hoja y recorrer la jerarquía de vistas hasta que encuentran el controlador de vista de contenedor adecuado para controlar la presentación de la nueva vista.
Los desarrolladores pueden implementar y en sus propios controladores de vista ShowViewControllerShowDetailViewController personalizados para obtener la misma funcionalidad automatizada que UINavigationController y UISplitViewController proporciona.
Cómo funciona
En esta sección echaremos un vistazo a cómo se implementan realmente estos métodos en iOS 8. En primer lugar, echemos un vistazo al nuevo GetTargetForAction método:
Este método recorre la cadena de jerarquía hasta que se encuentra el controlador de vista de contenedor correcto. Por ejemplo:
- Si se llama a un método, el primer controlador de vista de la cadena que implementa este método es el controlador de navegación, por lo que se usa como elemento primario
ShowViewControllerde la nueva vista. - Si se llamó a un método en su lugar, el controlador de vista dividida es el primer controlador de vistas que lo implementa, por lo que
ShowDetailViewControllerse usa como elemento primario.
El método funciona localizando un controlador de vista que implementa una acción determinada y, a continuación, preguntando al controlador de vista si GetTargetForAction desea recibir esa acción. Puesto que este método es público, los desarrolladores pueden crear sus propios métodos personalizados que funcionan igual que los métodos ShowViewController y ShowDetailViewController integrados.
Presentación adaptable
En iOS 8, Apple también ha convertido las presentaciones popover UIPopoverPresentationController () en adaptables. Por lo tanto, un controlador de vista de presentación emergente presentará automáticamente una vista emergente normal en una clase de tamaño normal, pero la mostrará en pantalla completa en una clase de tamaño horizontalmente compacta (por ejemplo, en una iPhone).
Para dar cabida a los cambios en el sistema de guión gráfico unificado, se ha creado un nuevo objeto de controlador para administrar los controladores de vista presentados: UIPresentationController . Este controlador se crea desde el momento en que se presenta el controlador de vista hasta que se descarta. Como es una clase de administración, se puede considerar una super class sobre el controlador de vistas, ya que responde a los cambios del dispositivo que afectan al Controlador de vistas (por ejemplo, la orientación) que, a continuación, se introducen de nuevo en el controlador de vistas los controles del controlador de presentación.
Cuando el desarrollador presenta un controlador de vista mediante PresentViewController el método , la administración del proceso de presentación se entrega a UIKit . UIKit controla (entre otras cosas) el controlador correcto para el estilo que se crea, con la única excepción de cuando un controlador de vista tiene el estilo establecido en UIModalPresentationCustom . Aquí, la aplicación puede proporcionar su propio PresentationController en lugar de usar el UIKit controlador.
Estilos de presentación personalizados
Con un estilo de presentación personalizado, los desarrolladores tienen la opción de usar un controlador de presentación personalizado. Este controlador personalizado se puede usar para modificar la apariencia y el comportamiento de la vista a la que está acostumbrado.
Trabajar con clases de tamaño
El Fotos de Xamarin Project que se incluye en este artículo proporciona un ejemplo práctico del uso de clases de tamaño y controladores de vista adaptables en una aplicación de interfaz unificada de iOS 8.
Aunque la aplicación crea su interfaz de usuario completamente a partir del código, en lugar de crear un guión gráfico unificado mediante el Interface Builder Xcode, se aplican las mismas técnicas.
Ahora echemos un vistazo más de cerca a cómo el proyecto adaptive Fotos implementa varias de las características de size class en iOS 8 para crear una aplicación adaptable.
Adaptación a los cambios del entorno de rasgos
Al ejecutar la aplicación adaptive Fotos en un iPhone, cuando el usuario gira el dispositivo de vertical a horizontal, el controlador de vista dividida mostrará la vista maestra y la vista de detalles:
Esto se logra invalidando el método del controlador de vista y ajustando las restricciones en UpdateConstraintsForTraitCollection función del valor de VerticalSizeClass . Por ejemplo:
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 ());
}
Agregar animaciones de transición
Cuando el controlador de vista dividida de la aplicación adaptive Fotos pasa de contraído a expandido, las animaciones se agregan a las animaciones predeterminadas invalidando el método del controlador WillTransitionToTraitCollection de vista. Por ejemplo:
public override void WillTransitionToTraitCollection (UITraitCollection traitCollection, IUIViewControllerTransitionCoordinator coordinator)
{
base.WillTransitionToTraitCollection (traitCollection, coordinator);
coordinator.AnimateAlongsideTransition ((UIViewControllerTransitionCoordinatorContext) => {
UpdateConstraintsForTraitCollection (traitCollection);
View.SetNeedsLayout ();
}, (UIViewControllerTransitionCoordinatorContext) => {
});
}
Invalidar el entorno de rasgo
Como se muestra anteriormente, la aplicación adaptive Fotos obliga al controlador de vista dividida a mostrar los detalles y las vistas maestras cuando el dispositivo iPhone está en la vista horizontal.
Esto se ha logrado mediante el código siguiente en el controlador de vistas:
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);
}
Expandir y contraer el controlador de vista dividida
A continuación, se examinará cómo se implementó el comportamiento de expansión y con contraer del controlador de vista dividida en Xamarin. En AppDelegate , cuando se crea el controlador de vista dividida, su delegado se asigna para controlar estos cambios:
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 ();
}
}
El método prueba para ver si se muestra una foto y SeparateSecondaryViewController toma medidas en función de ese estado. Si no se muestra ninguna foto, contrae el Controlador de vista secundario para que se muestre el Controlador de vista maestra.
El método se usa al expandir el controlador de vista dividida para ver si existen fotos en la pila, si es así, se contrae de nuevo CollapseSecondViewController en esa vista.
Movimiento entre controladores de vista
A continuación, echemos un vistazo a cómo se mueve la aplicación adaptive Fotos controladores de vista. En la clase cuando el usuario selecciona una celda de la tabla, se llama al método AAPLConversationViewController para mostrar la vista de ShowDetailViewController detalles:
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);
}
Mostrar indicadores de divulgación
En la aplicación Adaptive Photo hay varios lugares donde los indicadores de divulgación se ocultan o se muestran en función de los cambios en el entorno de rasgos. Esto se controla con el código siguiente:
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;
}
}
Se implementan mediante el GetTargetViewControllerForAction método descrito en detalle anteriormente.
Cuando un controlador de vista de tabla muestra datos, usa los métodos implementados anteriormente para ver si se va a producir o no una inserción y si se muestra u oculta el indicador de divulgación en consecuencia:
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;
}
Nuevo ShowDetailTargetDidChangeNotification tipo
Apple ha agregado un nuevo tipo de notificación para trabajar con clases de tamaño y entornos de rasgos desde un controlador de vista dividida, ShowDetailTargetDidChangeNotification . Esta notificación se envía siempre que cambia la vista de detalles de destino de un controlador de vista dividida, por ejemplo, cuando el controlador se expande o se contrae.
La aplicación adaptive Fotos usa esta notificación para actualizar el estado del indicador de divulgación cuando cambia el controlador de vista de detalles:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
TableView.RegisterClassForCellReuse (typeof(UITableViewCell), AAPLListTableViewControllerCellIdentifier);
NSNotificationCenter.DefaultCenter.AddObserver (this, new Selector ("showDetailTargetDidChange:"),
UIViewController.ShowDetailTargetDidChangeNotification, null);
ClearsSelectionOnViewWillAppear = false;
}
Echa un vistazo más de cerca a la aplicación Adaptive Fotos para ver todas las formas en que se pueden usar las clases de tamaño, las colecciones de rasgos y los controladores de vista adaptables para crear fácilmente una aplicación unificada en Xamarin.iOS.
Guiones gráficos unificados
Como novedad de iOS 8, los guiones gráficos unificados permiten al desarrollador crear un archivo de guión gráfico unificado que se puede mostrar en dispositivos iPhone y iPad mediante el destino de varias clases de tamaño. Mediante el uso de guiones gráficos unificados, el desarrollador escribe menos código específico de la interfaz de usuario y solo tiene un diseño de interfaz para crear y mantener.
Las principales ventajas de los guiones gráficos unificados son:
- Use el mismo archivo de guión gráfico para iPhone y iPad.
- Implementación hacia atrás en iOS 6 e iOS 7.
- Obtenga una vista previa del diseño para diferentes dispositivos, orientaciones y versiones del sistema operativo.
Habilitar clases de tamaño
De forma predeterminada, cualquier nuevo proyecto de Xamarin.iOS usará clases de tamaño. Para usar clases de tamaño y segues adaptables dentro de un guión gráfico de un proyecto anterior, primero se debe convertir al formato de guión gráfico unificado de Xcode 6 y la casilla Usar clases de tamaño está activada en el Inspector de archivos Xcode para los guiones gráficos.
Pantallas de inicio dinámico
El archivo de pantalla de inicio se muestra como una pantalla de presentación mientras se inicia una aplicación de iOS para proporcionar comentarios al usuario de que la aplicación se está iniciando realmente. Antes de iOS 8, el desarrollador tendría que incluir varios recursos de imagen para cada tipo de dispositivo, orientación y resolución de pantalla en los que se Default.png ejecutaría la aplicación. Por ejemplo, Default@2x.png , Default-Landscape@2x~ipad.png , , Default-Portrait@2x~ipad.png etc.
Factoring in the new iPhone 6 and iPhone 6 Plus devices (and the upcoming Apple Watch) with all the existing iPhone and iPad devices, this represents a large array of varying sizes, orientations and resolutions of startup screen image assets that must Default.png be created and maintained. Además, estos archivos pueden ser bastante grandes y "engordarán" el conjunto de aplicaciones entregables, lo que aumenta la cantidad de tiempo necesario para descargar la aplicación desde iTunes App Store (posiblemente evitar que se pueda entregar a través de una red de telefonía móvil) y aumentar la cantidad de almacenamiento necesario en el dispositivo del usuario final.
Como novedad de iOS 8, el desarrollador puede crear un único archivo atómico en Xcode que usa clases de diseño automático y de tamaño para crear una pantalla de inicio dinámico que funcionará para cada dispositivo, resolución y .xib orientación. .xib Esto no solo reduce la cantidad de trabajo necesario para que el desarrollador cree y mantenga todos los recursos de imagen necesarios, sino que reduce en gran medida el tamaño del paquete instalado de la aplicación.
Las pantallas de inicio dinámico tienen las siguientes limitaciones y consideraciones:
- Use solo
UIKitclases. - Use una única vista raíz que sea un
UIViewobjetoUIViewControllero . - No realice ninguna conexión al código de la aplicación (no agregue Acciones ni Salidas).
- No agregue
UIWebViewobjetos. - No use clases personalizadas.
- No use atributos en tiempo de ejecución.
Con las directrices anteriores en mente, veamos cómo agregar una pantalla de inicio dinámico a un proyecto existente de Xamarin iOS 8.
Haga lo siguiente:
Abra Visual Studio para Mac y cargue la solución a la que agregar la pantalla de inicio dinámico.
En la Explorador de soluciones, haga clic con el botón derecho en el archivo y seleccione Abrir conXcode Interface Builder:
En Xcode, seleccione Archivonuevoarchivo...:
Seleccione iOSInterfaz de usuarioLaunch Screen (Pantalla de inicio de iOS) y haga clic en el botón Siguiente:
Asigne un nombre al archivo
LaunchScreen.xiby haga clic en elLaunchScreen.xibCrear:Edite el diseño de la pantalla de inicio mediante la adición de elementos gráficos y el uso de restricciones de diseño para colocarlos para los dispositivos, orientaciones y tamaños de pantalla dados:
Guarde los cambios en
LaunchScreen.xib.Seleccione las pestañas Destino de aplicaciones y General:
Haga clic en el botón Elegir Info.plist, seleccione para la aplicación Xamarin y haga clic en el botón Elegir:
En la sección Iconos de aplicación e Imágenes de inicio, abra la lista desplegable Launch Screen File (Iniciar archivo de pantalla) y elija el archivo creado anteriormente:
Guarde los cambios en el archivo y vuelva a Visual Studio para Mac.
Espere a Visual Studio para Mac para terminar de sincronizar los cambios con Xcode.
En la Explorador de soluciones, haga clic con el botón derecho en la carpeta Recurso y seleccione Agregaragregar archivos...:
Seleccione el
LaunchScreen.xibarchivo creado anteriormente y haga clic en elLaunchScreen.xibAbrir:Compile la aplicación.
Prueba de la pantalla de inicio dinámico
En Visual Studio para Mac, seleccione el simulador iPhone 4 Retina y ejecute la aplicación. La pantalla de inicio dinámico se mostrará con el formato y la orientación correctos:
Detenga la aplicación en Visual Studio para Mac seleccione un iPad dispositivo iOS 8. Ejecute la aplicación y la pantalla de inicio tendrá el formato correcto para este dispositivo y orientación:
Vuelva a Visual Studio para Mac y detenga la ejecución de la aplicación.
Trabajar con iOS 7
Para mantener la compatibilidad con versiones anteriores con iOS 7, solo tiene que incluir los recursos de imagen habituales de la forma Default.png habitual en la aplicación de iOS 8. iOS volverá al comportamiento anterior y usará esos archivos como pantalla de inicio cuando se ejecute en un dispositivo iOS 7.
Para ver una implementación de una pantalla de inicio dinámico en Xamarin, consulte la aplicación iOS 8 de ejemplo de pantallas de inicio dinámico asociada a este documento.
Resumen
En este artículo se ha tomado un vistazo rápido a las clases de tamaño y cómo afectan al diseño en iPhone y iPad dispositivos. Se ha analizado cómo funcionan los rasgos, los entornos de rasgos y las colecciones de rasgos con las clases de tamaño para crear interfaces unificadas. Se ha visto brevemente los controladores de vistas adaptables y cómo funcionan con las clases de tamaño dentro de interfaces unificadas. Se ha visto cómo implementar clases de tamaño e interfaces unificadas completamente desde código de C# dentro de una aplicación xamarin iOS 8.
Por último, en este artículo se han abordado los aspectos básicos de la creación de una sola pantalla de inicio dinámico que se mostrará como pantalla de inicio en cada dispositivo iOS 8.






















