SwiftUI: Conhecimento

Neste tutorial, aprenderemos como planejar aplicativos de interface do usuário usando o View e como usar variáveis ​​de estado para modificar as interfaces de usuário.

Tempo estimado de leitura: 25 minutos.

O SwiftUI nos permite esquecer completamente o Interface Builder (IB) e os storyboards. O IB e o Xcode eram aplicativos separados antes do Xcode 4, mas o "encaixe" entre eles ainda é visível quando editamos o nome IBAction ou IBOutlet e nosso aplicativo falha, então o IB não sabe nada sobre alterações no código. Ou quando configuramos identificadores para segues ou células da tabela, mas o Xcode não pode verificá-los, pois eles são string.

SwiftUI para o resgate! Vemos imediatamente as alterações na Visualização assim que inserimos o código. As alterações de um lado resultam em uma atualização do outro, portanto, elas estão sempre relacionadas. Não há identificadores de cadeia que possam estar errados. E esse é todo o código, mas é muito menor do que se o escrevêssemos usando o UIKit, por isso é mais fácil entender, editar e depurar. Diga-me, isso não é maravilhoso?

Vamos lá


Vamos iniciar um novo projeto no projeto Xcode ( Shift-Command-N ), selecione iOS App Aplicativo de exibição única , chame RGBullsEye e escolha SwiftUI como interface.

Agora AppDelegate.swift está dividido em dois arquivos: AppDelegate.swift e SceneDelegate.swift , e SceneDelegate contém uma janela:



SceneDelegate quase não está relacionado ao SwiftUI, com exceção desta linha:

window.rootViewController = UIHostingController(rootView: ContentView()) 

O UIHostingController cria um controlador de exibição para o SwiftUI-view ContentView.
Nota: O UIHostingController nos permite integrar a visualização SwiftUI em um aplicativo existente. Adicione o Hosting View Controller ao nosso storyboard e crie um segue no UIViewController. Em seguida, usamos Control-drag com segue no código do controlador de exibição para criar uma IBSegueAction , onde configuramos o controlador de hospedagem como rootView - SwiftUI-view.
Quando o aplicativo é iniciado, a janela exibe uma instância do ContentView , definida no arquivo ContentView.swift . Esta é uma estrutura que está em conformidade com o protocolo View :

 struct ContentView: View { var body: some View { Text("Hello World") } } 

Esta é uma declaração SwiftUI do conteúdo de um ContentView ( body ). Agora existe uma exibição de texto com o texto Hello World.

Logo abaixo, o ContentView_Previews retorna uma instância do ContentView.

 struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } 

Aqui podemos definir os dados de teste para a visualização. Mas onde exatamente é essa prévia?

Imediatamente após o código, há um grande espaço vazio com isso acima:



Clique em Continuar , aguarde um momento e ...



Esboce nossa interface do usuário


Algo familiar não está visível - este é o arquivo Main.storyboard . Vamos criar nossa interface do usuário usando o SwiftUI, diretamente no código, no processo de visualização da prévia: o que chegamos lá? Mas não se preocupe, não precisamos escrever centenas de linhas de código para criar nossos pontos de vista.

O SwiftUI é declarativo: você declara como deve ser sua interface do usuário e o SwiftUI converte tudo isso em código eficiente que faz todo o trabalho. A Apple permite criar quantas visualizações forem necessárias para que o código seja simples e direto. Visualizações reutilizáveis ​​com parâmetros são especialmente recomendadas - isso é semelhante à alocação de código em uma função separada. Você fará isso sozinho mais tarde.

Nosso aplicativo terá muitas visualizações. Portanto, para começar, esboçaremos as visualizações de texto como stubs.

Substitua Text ("Hello World") por este:

 Text("Target Color Block") 

Se necessário, clique em Continuar para atualizar a visualização.

Agora, clique com a tecla Command pressionada nesta visualização na visualização e selecione Incorporar no HStack :



Observe que seu código também foi alterado:

 HStack { Text("Target Color Block") } 

Copie e cole o operador Text e edite-o dentro do nosso HStack. Observe: não separamos os operadores por vírgula, mas escrevemos cada um deles em uma nova linha:

 HStack { Text("Target Color Block") Text("Guess Color Block") } 

E assim aparece na pré-visualização:



Agora vamos preparar um local para os stubs deslizantes colocando o HStack no VStack . Desta vez, vamos clicar com o botão Command no HStack em nosso código :



Escolha Incorporar no VStack ; um novo código será exibido, mas a visualização não será alterada. Um pouco mais tarde, adicionaremos a visualização em futuros blocos de cores.

Adicione uma nova linha imediatamente após o HStack, clique em + na barra de ferramentas para abrir a biblioteca e arraste Pilha vertical para uma nova linha:



Como esperado, o código e a visualização foram alterados:



Conclua o trabalho no rascunho da interface do usuário, para que tudo fique assim:

 VStack { HStack { Text("Target Color Block") Text("Guess Color Block") } Text("Hit me button") VStack { Text("Red slider") Text("Green slider") Text("Blue slider") } } 

No novo VStack, três controles deslizantes aparecerão um pouco mais tarde, além de um botão entre os controles deslizantes e os blocos de cores.

Continuamos a trabalhar na interface do usuário


Agora vamos praticar no SwiftUI para preencher um HStack contendo blocos coloridos:

 HStack { // Target color block VStack { Rectangle() Text("Match this color") } // Guess color block VStack { Rectangle() HStack { Text("R: xxx") Text("G: xxx") Text("B: xxx") } } } 

Cada bloco de cores possui um retângulo. O bloco de cores de destino (destino) possui uma visualização de texto abaixo do retângulo, e o bloco selecionado (Adivinha) possui três visualizações de texto. Um pouco mais tarde, substituiremos 'xxx' pelos valores reais dos controles deslizantes.

Usando variáveis ​​'@State'


No SwiftUI, podemos usar variáveis ​​regulares, mas se queremos que a alteração da variável afete a interface do usuário, marcamos variáveis ​​como '@State' . Em nosso aplicativo, selecionamos a cor, para que todas as variáveis ​​que afetam a cor selecionada sejam '@State'.

Adicione estas linhas dentro do struct ContentView , antes da declaração do corpo :

 let rTarget = Double.random(in: 0..<1) let gTarget = Double.random(in: 0..<1) let bTarget = Double.random(in: 0..<1) @State var rGuess: Double @State var gGuess: Double @State var bGuess: Double 

Os valores de R, G e B estão entre 0 e 1. Inicializamos os valores desejados com valores aleatórios. Também podemos inicializar os valores selecionados para 0,5, mas deixá-los não inicializados por enquanto para mostrar o que precisa ser feito nesse caso.

Vamos um pouco mais abaixo para a estrutura ContentView_Previews , que inicializa a instância do ContentView para a visualização . Agora o inicializador precisa dos valores iniciais dos valores selecionados. Altere o ContentView () assim:

 ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5) 

Quando criamos os controles deslizantes, na visualização, seus valores estarão no meio.

Também devemos corrigir o inicializador em SceneDelegate , na função de cena (_: willConnectTo: options :) - substitua ContentView () pelo seguinte:

 window.rootViewController = UIHostingController(rootView: ContentView(rGuess: 0.5, gGuess: 0.5, bGuess: 0.5)) 

Quando o aplicativo é carregado, os ponteiros do controle deslizante ficam no centro.

Agora adicione um modificador de cores ao retângulo de destino:

 Rectangle() .foregroundColor(Color(red: rTarget, green: gTarget, blue: bTarget, opacity: 1.0)) 

O modificador .foregroundColor cria uma nova exibição de retângulo com a cor especificada pelos valores RGB gerados aleatoriamente.

Da mesma forma, modifique o retângulo de suposição:

 Rectangle() .foregroundColor(Color(red: rGuess, green: gGuess, blue: bGuess, opacity: 1.0)) 

Com valores de R, G e B em 0,5, obtemos uma cor cinza.

Clique em Continuar e aguarde um momento.



Tornando a visualização reutilizável


Primeiro, não vamos pensar em reutilizar e apenas fazer um controle deslizante para o vermelho. No VStack for sliders, substitua o plug Text ("Red slider") por este HStack :

 HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) } 

Tornamos a cor do texto na exibição de texto em vermelho. E eles adicionaram o Slider com um valor padrão. O intervalo padrão do controle deslizante é de 0 a 1, isso é algo que nos convém perfeitamente.
Nota: Sabemos que o controle deslizante varia de 0 a 1 e o rótulo de texto é '255' para a conveniência dos usuários que estão acostumados a representar valores RGB no intervalo de 0 a 255.
Mas que tipo de ícone $ a variável possui? Nós conhecemos ? e! ao trabalhar com opcionais e agora também $ ?

Apesar de ser tão pequeno e discreto, ele é muito importante. O RGuess em si é apenas um valor somente leitura . Mas $ rGuess é uma encadernação , precisamos que ele atualize o retângulo da cor selecionada quando o usuário move o controle deslizante.

Para entender a diferença, defina os valores para a visualização de três textos sob o retângulo previsível:

 HStack { Text("R: \(Int(rGuess * 255.0))") Text("G: \(Int(gGuess * 255.0))") Text("B: \(Int(bGuess * 255.0))") } 

Aqui usamos apenas os valores, não os alteramos, portanto não precisamos do prefixo $.

Aguarde a atualização da visualização:



Retângulos coloridos encolheram levemente para caber no controle deslizante. Mas os rótulos de texto do controle deslizante parecem bagunçados - eles são pressionados demais pelas bordas. Vamos adicionar outro modificador ao HStack - padding:

 HStack { Text("0") .foregroundColor(.red) Slider(value: $rGuess) Text("255") .foregroundColor(.red) } .padding() 

Agora muito melhor!



Faça Command-Clique no controle deslizante vermelho do HStack e selecione Extrair subview :



Isso funciona da mesma forma que Refatorar ▸ Extrair para função , mas para a visualização SwiftUI.

Neste ponto, várias mensagens de erro aparecerão, não se preocupe, agora vamos corrigi-lo.

Nomeie a visualização resultante ColorSlider e adicione este código na parte superior, na frente do corpo da nova visualização:

 @Binding var value: Double var textColor: Color 

Agora substitua $ rGuess por $ value e .red por textColor :

 Text("0") .foregroundColor(textColor) Slider(value: $value) Text("255") .foregroundColor(textColor) 

Vamos voltar à definição de ColorSlider () no VStack e adicionar nossos parâmetros:

 ColorSlider(value: $rGuess, textColor: .red) 

Verifique se a visualização está OK com o controle deslizante vermelho e substitua os stubs de texto pelos controles deslizantes verde e azul. Não se esqueça de inserir os parâmetros corretos lá:

 ColorSlider(value: $gGuess, textColor: .green) ColorSlider(value: $bGuess, textColor: .blue) 

Clique em Continuar para atualizar a visualização:


Nota: você deve ter notado que muitas vezes precisa clicar em Continuar . Se você gosta de atalhos, provavelmente adorará Option-Command-P .
E agora algo de bom! No canto inferior direito da visualização, clique no botão de visualização ao vivo :



A visualização ao vivo nos permite interagir com a visualização como se o aplicativo estivesse sendo executado em um simulador!

Tente mover os controles deslizantes:



Ótimo! Passamos para a fase final. Afinal, queremos saber o quão bem escolhemos a cor?

Mostrar alerta


Após definir os controles deslizantes para as posições desejadas, o usuário pressiona o botão Hit Me , após o qual o Alerta aparece com uma classificação.

Primeiro, adicione um método ao ContentView para calcular a pontuação. Entre as variáveis ​​@State e
body adicione este método:

 func computeScore() -> Int { let rDiff = rGuess - rTarget let gDiff = gGuess - gTarget let bDiff = bGuess - bTarget let diff = sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff) return Int((1.0 - diff) * 100.0 + 0.5) } 

O valor diff é simplesmente a distância entre dois pontos no espaço tridimensional, ou seja, o valor do erro do usuário. Para obter uma estimativa, subtraia diff de 1 e reduza seu valor para o intervalo de 0 a 100. Quanto menor a diff, maior a estimativa.

Em seguida, substitua o stub Text ("Hit me button") por este código:

 Button(action: { }) { Text("Hit Me!") } 

O botão possui ação e rótulo, como UIButton. Queremos ação para acionar uma exibição de alerta. Mas, se criarmos Alerta no botão de ação, nada acontecerá.

Em vez disso, tornaremos o Alert parte do ContentView e adicionaremos uma variável '@State' do tipo Bool. Em seguida, definimos essa variável como true, no local em que queremos que nosso alerta apareça no botão de ação. O valor será redefinido para false - para ocultar o alerta - quando o usuário ocultar o alerta.

Adicione esta variável '@State':

 @State var showAlert = false 

Em seguida, adicione este código como um botão de ação:

 self.showAlert = true 

self é necessário para nós, já que showAlert está dentro do fechamento.

Por fim, adicione o modificador de alerta ao botão, para que nosso botão fique completamente assim:

 Button(action: { self.showAlert = true }) { Text("Hit Me!") } .alert(isPresented: $showAlert) { Alert(title: Text("Your Score"), message: Text("\(computeScore())")) } 

Passamos $ showAlert como uma ligação, pois o valor dessa variável mudará no momento em que o usuário ocultar o alerta e essa alteração fará com que a exibição seja atualizada.

O SwiftUI possui um inicializador simples para a visualização de alertas. Por padrão, ele possui um botão OK, portanto, nem precisamos configurá-lo como parâmetro.

Ative a visualização ao vivo, mova os controles deslizantes e pressione o botão Hit me. Voila!



Agora, com a visualização ao vivo, você não precisa mais de um simulador para iOS. Embora com ele você possa testar seu aplicativo horizontalmente:



Conclusão


Aqui você pode baixar o rascunho da publicação finalizada.

Este tutorial abordou o SwiftUI apenas um pouco, mas agora você tem a impressão dos novos recursos do Xcode para criar interfaces de usuário e visualizações, além de como usar as variáveis ​​'@State' para atualizar sua interface do usuário.

Para simplificar, não criamos um modelo de dados para RGB. Mas a maioria dos aplicativos cria modelos de dados usando estruturas ou classes. Se você deseja rastrear alterações no modelo no SwiftUI, ele deve estar em conformidade com o protocolo ObservableObject e implementar a propriedade willChange , que notifica você sobre alterações. Confira os exemplos da Apple e, especialmente, o Data Flow Through SwiftUI .

Para facilitar a compreensão do SwiftUI, você pode adicionar uma visualização do SwiftUI a um aplicativo existente. Veja exemplos de como fazer isso de maneira rápida e fácil.

Veja minha publicação sobre a implementação de listas dobráveis ​​/ suspensas usando o SwiftUI.

Por fim, estude a documentação do SwiftUI e realmente existem muitas coisas úteis!

Source: https://habr.com/ru/post/pt471918/


All Articles