Criando interfaces de usuário do iOS em código no Xamarin.iOS
A interface do usuário de um aplicativo iOS é como uma vitrine – o aplicativo normalmente recebe uma janela, mas pode preencher a janela com quantos objetos forem necessários, e os objetos e arranjos podem ser alterados dependendo do que o aplicativo deseja exibir. Os objetos nesse cenário – as coisas que o usuário vê – são chamados de exibições. Para criar uma única tela em um aplicativo, as exibições são empilhadas umas sobre as outras em uma hierarquia de exibição de conteúdo e a hierarquia é gerenciada por um único controlador de exibição. Aplicativos com várias telas têm várias hierarquias de exibição de conteúdo, cada uma com seu próprio controlador de exibição; o aplicativo coloca as exibições na janela para criar uma hierarquia de exibição de conteúdo diferente com base na tela na qual o usuário está.
O diagrama a seguir ilustra as relações entre a janela, exibições, subexibições e controlador de exibição que levam a interface do usuário para a tela do dispositivo:
Essas hierarquias de exibição podem ser construídas usando o Construtor de Interface do Xcode, no entanto, é bom ter uma compreensão fundamental de como trabalhar inteiramente em código. Este artigo aborda alguns pontos básicos para começar a trabalhar com o desenvolvimento de interface do usuário somente de código.
Criando um projeto somente de código
Modelo de projeto em branco do iOS
Primeiro, crie um projeto iOS no Visual Studio usando o projeto File > New Project > Visual C# > iPhone & iPad > iOS App (Xamarin), mostrado abaixo:
Em seguida, selecione o modelo de projeto Aplicativo em Branco:
O modelo Projeto vazio adiciona 4 arquivos ao projeto:
- AppDelegate.cs - Contém uma
UIApplicationDelegate
subclasse,AppDelegate
, que é usada para manipular eventos de aplicativos do iOS. A janela do aplicativo é criada noAppDelegate
método 'sFinishedLaunching
. - Main.cs - Contém o ponto de entrada para o aplicativo, que especifica a classe para o
AppDelegate
. - Info.plist - Arquivo de lista de propriedades que contém informações de configuração do aplicativo.
- Entitlements.plist – Arquivo de lista de propriedades que contém informações sobre os recursos e permissões do aplicativo.
Os aplicativos iOS são criados usando o padrão MVC. A primeira tela que um aplicativo exibe é criada a partir do controlador de exibição raiz da janela. Consulte o guia Hello, iOS Multiscreen para obter mais detalhes sobre o próprio padrão MVC.
A implementação para o AppDelegate
adicionado pelo modelo cria a janela do aplicativo, da qual há apenas uma para cada aplicativo iOS, e a torna visível com o seguinte código:
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
}
Se você fosse executar este aplicativo agora, você provavelmente teria uma exceção lançada informando que Application windows are expected to have a root view controller at the end of application launch
. Vamos adicionar um Controlador e torná-lo o Controlador de Exibição Raiz do aplicativo.
Adicionando um controlador
Seu aplicativo pode conter muitos Controladores de Exibição, mas precisa ter um Controlador de Exibição Raiz para controlar todos os Controladores de Exibição. Adicione um controlador à janela criando uma UIViewController
instância e definindo-a para a Window.RootViewController
propriedade:
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var controller = new UIViewController();
controller.View.BackgroundColor = UIColor.LightGray;
Window.RootViewController = controller;
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
}
Cada controlador tem uma exibição associada, que é acessível a partir da View
propriedade. O código acima altera a propriedade da BackgroundColor
exibição para UIColor.LightGray
que ela fique visível, conforme mostrado abaixo:
Poderíamos definir qualquer UIViewController
subclasse como a RootViewController
desta maneira também, incluindo controladores de UIKit, bem como aqueles que nós mesmos escrevemos. Por exemplo, o código a seguir adiciona um UINavigationController
como o RootViewController
:
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var controller = new UIViewController();
controller.View.BackgroundColor = UIColor.LightGray;
controller.Title = "My Controller";
var navController = new UINavigationController(controller);
Window.RootViewController = navController;
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
}
Isso produz o controlador aninhado dentro do controlador de navegação, conforme mostrado abaixo:
Criando um controlador de exibição
Agora que vimos como adicionar um controlador como o RootViewController
da janela, vamos ver como criar um controlador de exibição personalizado no código.
Adicione uma nova classe com o nome CustomViewController
mostrado abaixo:
A classe deve herdar de UIViewController
, que está no UIKit
namespace, conforme mostrado:
using System;
using UIKit;
namespace CodeOnlyDemo
{
class CustomViewController : UIViewController
{
}
}
Inicializando o modo de exibição
UIViewController
contém um método chamado ViewDidLoad
que é chamado quando o controlador View é carregado pela primeira vez na memória. Esse é um local apropriado para fazer a inicialização do modo de exibição, como definir suas propriedades.
Por exemplo, o código a seguir adiciona um botão e um manipulador de eventos para pressionar um novo View Controller na pilha de navegação quando o botão é pressionado:
using System;
using CoreGraphics;
using UIKit;
namespace CodyOnlyDemo
{
public class CustomViewController : UIViewController
{
public CustomViewController ()
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
View.BackgroundColor = UIColor.White;
Title = "My Custom View Controller";
var btn = UIButton.FromType (UIButtonType.System);
btn.Frame = new CGRect (20, 200, 280, 44);
btn.SetTitle ("Click Me", UIControlState.Normal);
var user = new UIViewController ();
user.View.BackgroundColor = UIColor.Magenta;
btn.TouchUpInside += (sender, e) => {
this.NavigationController.PushViewController (user, true);
};
View.AddSubview (btn);
}
}
}
Para carregar esse controlador em seu aplicativo e demonstrar a navegação simples, crie uma nova instância do CustomViewController
. Crie um novo controlador de navegação, passe sua instância do controlador de exibição e defina o novo controlador de RootViewController
AppDelegate
navegação para a janela como antes:
var cvc = new CustomViewController ();
var navController = new UINavigationController (cvc);
Window.RootViewController = navController;
Agora, quando o aplicativo é carregado, o é carregado dentro de CustomViewController
um controlador de navegação:
Clicando no botão, irá empurrar um novo View Controller para a pilha de navegação:
Criando a hierarquia de exibição
No exemplo acima, começamos a criar uma interface de usuário no código adicionando um botão ao View Controller.
As interfaces de usuário do iOS são compostas por uma hierarquia de exibição. Modos de exibição adicionais, como rótulos, botões, controles deslizantes, etc. são adicionados como subexibições de alguns modos de exibição pai.
Por exemplo, vamos editar o CustomViewController
para criar uma tela de login onde o usuário pode inserir um nome de usuário e senha. A tela será composta por dois campos de texto e um botão.
Adicionando os campos de texto
Primeiro, remova o botão e o manipulador de eventos que foram adicionados na seção Inicializando o modo de exibição .
Adicione um controle para o nome de usuário criando e inicializando um UITextField
e, em seguida, adicionando-o à hierarquia de exibição, conforme mostrado abaixo:
class CustomViewController : UIViewController
{
UITextField usernameField;
public override void ViewDidLoad()
{
base.ViewDidLoad();
View.BackgroundColor = UIColor.Gray;
nfloat h = 31.0f;
nfloat w = View.Bounds.Width;
usernameField = new UITextField
{
Placeholder = "Enter your username",
BorderStyle = UITextBorderStyle.RoundedRect,
Frame = new CGRect(10, 82, w - 20, h)
};
View.AddSubview(usernameField);
}
}
Quando criamos o UITextField
, definimos a Frame
propriedade para definir sua localização e tamanho. No iOS, a coordenada 0,0 está no canto superior esquerdo com +x à direita e +y para baixo. Depois de definir o Frame
junto com algumas outras propriedades, chamamos View.AddSubview
para adicionar o UITextField
à hierarquia de exibição. Isso torna a usernameField
subexibição da UIView
instância à qual a View
propriedade faz referência. Uma subexibição é adicionada com uma ordem z superior à exibição pai, portanto, ela aparece na frente da exibição pai na tela.
A aplicação com o incluído é mostrada UITextField
abaixo:
Podemos adicionar um UITextField
para a senha de forma semelhante, só que desta vez definimos a SecureTextEntry
propriedade como true, como mostrado abaixo:
public class CustomViewController : UIViewController
{
UITextField usernameField, passwordField;
public override void ViewDidLoad()
{
// keep the code the username UITextField
passwordField = new UITextField
{
Placeholder = "Enter your password",
BorderStyle = UITextBorderStyle.RoundedRect,
Frame = new CGRect(10, 114, w - 20, h),
SecureTextEntry = true
};
View.AddSubview(usernameField);
View.AddSubview(passwordField);
}
}
A configuração SecureTextEntry = true
oculta o texto inserido UITextField
no pelo usuário, conforme mostrado abaixo:
Adicionando o botão
Em seguida, adicionaremos um botão para que o usuário possa enviar o nome de usuário e a senha. O botão é adicionado à hierarquia de exibição como qualquer outro controle, passando-o como um argumento para o método do modo de AddSubview
exibição pai novamente.
O código a seguir adiciona o botão e registra um manipulador de eventos para o TouchUpInside
evento:
var submitButton = UIButton.FromType (UIButtonType.RoundedRect);
submitButton.Frame = new CGRect (10, 170, w - 20, 44);
submitButton.SetTitle ("Submit", UIControlState.Normal);
submitButton.TouchUpInside += (sender, e) => {
Console.WriteLine ("Submit button pressed");
};
View.AddSubview(submitButton);
Com isso em vigor, a tela de login agora aparece como mostrado abaixo:
Ao contrário das versões anteriores do iOS, o fundo do botão padrão é transparente. Alterar a propriedade do BackgroundColor
botão altera isso:
submitButton.BackgroundColor = UIColor.White;
Isso resultará em um botão quadrado em vez do típico botão com bordas arredondadas. Para obter a borda arredondada, use o seguinte trecho:
submitButton.Layer.CornerRadius = 5f;
Com essas alterações, a exibição ficará assim:
Adicionando vários modos de exibição à hierarquia de exibição
O iOS fornece um recurso para adicionar vários modos de exibição à hierarquia de exibição usando AddSubviews
o .
View.AddSubviews(new UIView[] { usernameField, passwordField, submitButton });
Adicionando funcionalidade de botão
Quando um botão é clicado, seus usuários esperam que algo aconteça. Por exemplo, um alerta é mostrado ou a navegação é executada para outra tela.
Vamos adicionar algum código para enviar um segundo controlador de exibição para a pilha de navegação.
Primeiro, crie o segundo controlador de exibição:
var loginVC = new UIViewController () { Title = "Login Success!"};
loginVC.View.BackgroundColor = UIColor.Purple;
Em seguida, adicione a funcionalidade ao TouchUpInside
evento:
submitButton.TouchUpInside += (sender, e) => {
this.NavigationController.PushViewController (loginVC, true);
};
A navegação é ilustrada abaixo:
Observe que, por padrão, quando você usa um Controlador de Navegação, o iOS fornece ao aplicativo uma barra de navegação e um botão Voltar para permitir que você volte pela pilha.
Iterando através da hierarquia de exibição
É possível iterar através da hierarquia de subvisualização e escolher qualquer exibição específica. Por exemplo, para localizar cada UIButton
um e dar a esse botão um diferente BackgroundColor
, o seguinte trecho pode ser usado
foreach(var subview in View.Subviews)
{
if (subview is UIButton)
{
var btn = subview as UIButton;
btn.BackgroundColor = UIColor.Green;
}
}
Isso, no entanto, não funcionará se o modo de exibição que está sendo iterado for um UIView
como todos os modos de exibição voltarão como sendo um como os UIView
objetos adicionados ao modo de exibição pai herdarem UIView
.
Rotação de manuseio
Se o usuário girar o dispositivo para paisagem, os controles não serão redimensionados adequadamente, como ilustra a captura de tela a seguir:
Uma maneira de corrigir isso é definindo a AutoresizingMask
propriedade em cada modo de exibição. Neste caso, queremos que os controles se estendam horizontalmente, então definiríamos cada AutoresizingMask
. O exemplo a seguir é para usernameField
, mas o mesmo precisaria ser aplicado a cada gadget na hierarquia de exibição.
usernameField.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
Agora, quando giramos o dispositivo ou simulador, tudo se estende para preencher o espaço adicional, como mostrado abaixo:
Criando modos de exibição personalizados
Além de usar controles que fazem parte do UIKit, modos de exibição personalizados também podem ser usados. Um modo de exibição personalizado pode ser criado herdando e UIView
substituindo Draw
o . Vamos criar um modo de exibição personalizado e adicioná-lo à hierarquia de exibição para demonstrar.
Herdando de UIView
A primeira coisa que precisamos fazer é criar uma classe para o modo de exibição personalizado. Faremos isso usando o modelo Classe no Visual Studio para adicionar uma classe vazia chamada CircleView
. A classe base deve ser definida como UIView
, que lembramos estar no UIKit
namespace. Também precisaremos do System.Drawing
namespace. Os outros vários System.*
namespaces não serão usados neste exemplo, portanto, sinta-se à vontade para removê-los.
A classe deve ter esta aparência:
using System;
namespace CodeOnlyDemo
{
class CircleView : UIView
{
}
}
Desenhando em um UIView
Cada UIView
um tem um Draw
método que é chamado pelo sistema quando precisa ser desenhado. Draw
nunca deve ser chamado diretamente. Ele é chamado pelo sistema durante o processamento do loop de execução. Na primeira vez que um modo de exibição for adicionado à hierarquia de exibição, seu Draw
método será chamado. Chamadas subsequentes a Draw
ocorrer quando o modo de exibição é marcado como precisando ser desenhado chamando um SetNeedsDisplay
ou SetNeedsDisplayInRect
no modo de exibição.
Podemos adicionar código de desenho à nossa exibição adicionando esse código dentro do método substituído Draw
, conforme mostrado abaixo:
public override void Draw(CGRect rect)
{
base.Draw(rect);
//get graphics context
using (var g = UIGraphics.GetCurrentContext())
{
// set up drawing attributes
g.SetLineWidth(10.0f);
UIColor.Green.SetFill();
UIColor.Blue.SetStroke();
// create geometry
var path = new CGPath();
path.AddArc(Bounds.GetMidX(), Bounds.GetMidY(), 50f, 0, 2.0f * (float)Math.PI, true);
// add geometry to graphics context and draw
g.AddPath(path);
g.DrawPath(CGPathDrawingMode.FillStroke);
}
}
Uma vez que CircleView
é um UIView
, também podemos definir UIView
propriedades. Por exemplo, podemos definir o BackgroundColor
no construtor:
public CircleView()
{
BackgroundColor = UIColor.White;
}
Para usar o CircleView
que acabamos de criar, podemos adicioná-lo como uma subexibição à hierarquia de exibição em um controlador existente, como fizemos com o UILabels
e UIButton
anteriormente, ou podemos carregá-lo como a exibição de um novo controlador. Vamos fazer o último.
Carregando um modo de exibição
UIViewController
tem um método chamado LoadView
que é chamado pelo controlador para criar sua exibição. Este é um local apropriado para criar uma exibição e atribuí-la à propriedade do View
controlador.
Primeiro, precisamos de um controlador, então crie uma nova classe vazia chamada CircleController
.
Adicione CircleController
o seguinte código para definir o View
como a CircleView
(você não deve chamar a base
implementação em sua substituição):
using UIKit;
namespace CodeOnlyDemo
{
class CircleController : UIViewController
{
CircleView view;
public override void LoadView()
{
view = new CircleView();
View = view;
}
}
}
Finalmente, precisamos apresentar o controlador em tempo de execução. Vamos fazer isso adicionando um manipulador de eventos no botão de envio que adicionamos anteriormente, da seguinte maneira:
submitButton.TouchUpInside += delegate
{
Console.WriteLine("Submit button clicked");
//circleController is declared as class variable
circleController = new CircleController();
PresentViewController(circleController, true, null);
};
Agora, quando executamos o aplicativo e tocamos no botão enviar, a nova exibição com um círculo é exibida:
Criando uma tela de inicialização
Uma tela de inicialização é exibida quando o aplicativo é iniciado como uma maneira de exibir aos usuários que ele é responsivo. Como uma tela de inicialização é exibida quando o aplicativo está sendo carregado, ela não pode ser criada em código, pois o aplicativo ainda está sendo carregado na memória.
Quando você cria um projeto iOS no Visual Studio, uma tela de inicialização é fornecida para você na forma de um arquivo .xib, que pode ser encontrado na pasta Recursos dentro do seu projeto.
Isso pode ser editado clicando duas vezes nele e abrindo-o no Xcode Interface Builder.
A Apple recomenda que um arquivo .xib ou Storyboard seja usado para aplicativos direcionados ao iOS 8 ou posterior, Quando você inicia qualquer arquivo no Xcode Interface Builder, você pode usar Classes de tamanho e layout automático para adaptar seu layout para que ele tenha uma boa aparência e seja exibido corretamente para todos os tamanhos de dispositivo. Uma imagem de inicialização estática pode ser usada além de um .xib ou Storyboard para permitir suporte para aplicativos direcionados a versões anteriores.
Para obter mais informações sobre como criar uma tela de inicialização, consulte os documentos abaixo:
Importante
A partir do iOS 9, a Apple recomenda que os Storyboards sejam usados como o principal método de criação de uma tela de inicialização.
Criando uma imagem de inicialização para aplicativos anteriores ao iOS 8
Uma imagem estática pode ser usada além de uma tela de inicialização .xib ou Storyboard se o aplicativo tiver como alvo versões anteriores ao iOS 8.
Essa imagem estática pode ser definida no arquivo Info.plist ou como um Catálogo de Ativos (para iOS 7) em seu aplicativo. Você precisará fornecer imagens separadas para cada tamanho de dispositivo (320x480, 640x960, 640x1136) em que seu aplicativo pode ser executado. Para obter mais informações sobre tamanhos de tela de inicialização, consulte o guia Imagens de tela de inicialização.
Importante
Se o seu aplicativo não tiver a Tela de Inicialização, você poderá notar que ele não se encaixa totalmente na tela. Se esse for o caso, certifique-se de incluir, pelo menos, uma imagem 640x1136 nomeada Default-568@2x.png
para seu Info.plist.
Resumo
Este artigo discutiu como desenvolver aplicativos iOS programaticamente no Visual Studio. Analisamos como criar um projeto a partir de um modelo de projeto vazio, discutindo como criar e adicionar um controlador de exibição raiz à janela. Em seguida, mostramos como usar controles do UIKit para criar uma hierarquia de exibição dentro de um controlador para desenvolver uma tela de aplicativo. Em seguida, examinamos como fazer com que as exibições sejam dispostas adequadamente em diferentes orientações e vimos como criar uma exibição personalizada subclassificando UIView
, bem como carregar a exibição em um controlador. Finalmente, exploramos como adicionar uma tela de inicialização a um aplicativo.