portaldacalheta.pt
  • Principal
  • Ferramentas E Tutoriais
  • Noticias Do Mundo
  • Pessoas E Equipes
  • Ascensão Do Remoto
Móvel

RxSwift e animações no iOS



Se você é um desenvolvedor iOS que fez uma quantidade razoável de trabalho de interface do usuário e é apaixonado por ele, você tem que amar o poder do UIKit quando se trata de animações. Animar um UIView é tão fácil quanto um bolo. Você não precisa pensar muito sobre como fazê-lo desaparecer, girar, mover ou encolher / expandir ao longo do tempo. No entanto, fica um pouco complicado se você quiser encadear animações e configurar dependências entre elas. Seu código pode acabar sendo bastante prolixo e difícil de seguir, com muitos fechamentos aninhados e níveis de indentação.

ponto de venda baseado em android

Neste artigo, explorarei como aplicar o poder de uma estrutura reativa como RxSwift para fazer o código parecer muito mais limpo, bem como mais fácil de ler e seguir. A ideia surgiu quando eu estava trabalhando em um projeto para um cliente. Esse cliente em particular era muito experiente em IU (o que combinava perfeitamente com minha paixão)! Eles queriam que a IU de seu aplicativo se comportasse de uma maneira muito particular, com muitas transições e animações muito elegantes. Uma de suas ideias era ter uma introdução ao aplicativo que contasse a história do que o aplicativo tratava. Eles queriam que a história fosse contada por meio de uma sequência de animações, em vez de reproduzir um vídeo pré-renderizado para que pudesse ser facilmente ajustado e ajustado. RxSwift acabou sendo a escolha perfeita para um problema como esse, como espero que você perceba assim que terminar o artigo.



Breve introdução à programação reativa

A programação reativa está se tornando um grampo e foi adotada na maioria das linguagens de programação modernas. Existem muitos livros e blogs que explicam detalhadamente por que a programação reativa é um conceito tão poderoso e como ela ajuda a encorajar um bom design de software ao impor certos princípios e padrões de design. Ele também fornece um kit de ferramentas que pode ajudá-lo a reduzir significativamente a confusão de código.



Eu gostaria de tocar em um aspecto que eu realmente gosto - a facilidade com que você pode encadear operações assíncronas e expressá-las de forma declarativa e fácil de ler.



Quando se trata de Swift, existem dois frameworks concorrentes que ajudam a transformá-lo em uma linguagem de programação reativa: ReactiveSwift e RxSwift. Usarei RxSwift em meus exemplos não porque seja melhor, mas porque estou mais familiarizado com ele. Presumirei que você, leitor, também esteja familiarizado com ele, para que eu possa ir direto ao ponto principal.

Encadeando animações: o jeito antigo

Digamos que você queira girar uma vista 180 ° e então desvanece-se. Você pode fazer uso do completion encerramento e fazer algo assim:



UIView.animate(withDuration: 0.5, animations: { self.animatableView.transform = CGAffineTransform(rotationAngle: .pi/2) }, completion: { _ in UIView.animate(withDuration: 0.5) { self.animatableView.alpha = 0 } })

GIF animado de um quadrado giratório

É um pouco volumoso, mas ainda está bom. Mas e se você quiser inserir mais uma animação no meio, digamos, deslocar a visualização para a direita depois de girar e antes que desapareça? Aplicando a mesma abordagem, você vai acabar com algo assim:



UIView.animate(withDuration: 0.5, animations: { self.animatableView.transform = CGAffineTransform(rotationAngle: .pi/2) }, completion: { _ in UIView.animate(withDuration: 0.5, animations: { self.animatableView.frame = self.animatableView.frame.offsetBy(dx: 50, dy: 0) }, completion: { _ in UIView.animate(withDuration: 0.5, animations: { self.animatableView.alpha = 0 }) }) })

GIF animado do retângulo girando, pausando e deslizando para a direita

Quanto mais etapas você adicionar, mais confuso e complicado ele se torna. E então, se você decidir alterar a ordem de certas etapas, terá que realizar algumas sequências não triviais de recortar e colar, que estão sujeitas a erros.



Bem, a Apple obviamente pensou nisso - eles oferecem uma maneira melhor de fazer isso, usando uma API de animações baseada em quadros-chave. Com essa abordagem, o código acima poderia ser reescrito assim:

UIView.animateKeyframes(withDuration: 1.5, delay: 0, options: [], animations: { UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.33, animations: { self.animatableView.transform = CGAffineTransform(rotationAngle: .pi/2) }) UIView.addKeyframe(withRelativeStartTime: 0.33, relativeDuration: 0.33, animations: { self.animatableView.frame = self.animatableView.frame.offsetBy(dx: 50, dy: 0) }) UIView.addKeyframe(withRelativeStartTime: 0.66, relativeDuration: 0.34, animations: { self.animatableView.alpha = 0 }) })

Essa é uma grande melhoria, com as principais vantagens sendo:



como funcionam os motores de física
  1. O código permanece estável, independentemente de quantas etapas você adiciona a ele
  2. Alterar a ordem é simples (com uma ressalva abaixo)

A desvantagem dessa abordagem é que você precisa pensar em termos de durações relativas e se torna difícil (ou pelo menos não muito simples) alterar o tempo absoluto ou a ordem das etapas. Pense em quais cálculos você teria que passar e que tipo de mudanças você teria que fazer na duração geral e durações / tempos de início relativos para cada uma das animações se você decidisse fazer a visualização desaparecer em 1 segundo em vez de meio segundo, mantendo todo o resto igual. O mesmo acontece se você quiser alterar a ordem das etapas - você terá que recalcular seus horários de início relativos.

Dadas as desvantagens, não acho nenhuma das abordagens acima boa o suficiente. A solução ideal que procuro deve satisfazer os seguintes critérios:



  1. O código deve permanecer estável, independentemente do número de etapas
  2. Devo ser capaz de adicionar / remover ou reordenar facilmente as animações e alterar suas durações de forma independente, sem quaisquer efeitos colaterais para outras animações

Encadeando animações: o jeito RxSwift

Descobri que, usando RxSwift, posso facilmente realizar esses dois objetivos. RxSwift não é a única estrutura que você pode usar para fazer algo assim - qualquer estrutura baseada em promessa que permite que você agrupe operações assíncronas em métodos que podem ser sintaticamente encadeados sem fazer uso de blocos de conclusão. Mas RxSwift tem muito mais a oferecer com sua gama de operadoras, que falaremos um pouco mais tarde.

Aqui está o esboço de como vou fazer isso:

  1. Envolverei cada uma das animações em uma função que retorna um observável do tipo Observable.
  2. Esse observável emitirá apenas um elemento antes de completar a sequência.
  3. O elemento será emitido assim que a animação envolvida pela função for concluída.
  4. Vou encadear esses observáveis ​​usando flatMap operador.

É assim que minhas funções podem ser:

func rotate(_ view: UIView, duration: TimeInterval) -> Observable { return Observable.create { (observer) -> Disposable in UIView.animate(withDuration: duration, animations: { view.transform = CGAffineTransform(rotationAngle: .pi/2) }, completion: { (_) in observer.onNext(()) observer.onCompleted() }) return Disposables.create() } } func shift(_ view: UIView, duration: TimeInterval) -> Observable { return Observable.create { (observer) -> Disposable in UIView.animate(withDuration: duration, animations: { view.frame = view.frame.offsetBy(dx: 50, dy: 0) }, completion: { (_) in observer.onNext(()) observer.onCompleted() }) return Disposables.create() } } func fade(_ view: UIView, duration: TimeInterval) -> Observable { return Observable.create { (observer) -> Disposable in UIView.animate(withDuration: duration, animations: { view.alpha = 0 }, completion: { (_) in observer.onNext(()) observer.onCompleted() }) return Disposables.create() } }

E aqui está como eu coloquei tudo junto:

como testar uma classe em java
rotate(animatableView, duration: 0.5) .flatMap { [unowned self] in self.shift(self.animatableView, duration: 0.5) } .flatMap { [unowned self] in self.fade(self.animatableView, duration: 0.5) } .subscribe() .disposed(by: disposeBag)

Certamente é muito mais código do que nas implementações anteriores e pode parecer um pouco exagerado para uma sequência tão simples de animações, mas a beleza é que pode ser estendido para lidar com algumas sequências de animação bastante complexas e é muito fácil de ler devido a a natureza declarativa da sintaxe.

Depois de aprender a lidar com isso, você pode criar animações tão complexas quanto um filme e ter à sua disposição uma grande variedade de operadores RxSwift úteis que você pode aplicar para realizar coisas que seriam muito difíceis de fazer com qualquer uma das abordagens acima mencionadas.

Aqui está como podemos usar o .concat operador para tornar meu código ainda mais conciso - a parte em que as animações são encadeadas:

Observable.concat([ rotate(animatableView, duration: 0.5), shift(animatableView, duration: 0.5), fade(animatableView, duration: 0.5) ]) .subscribe() .disposed(by: disposeBag)

Você pode inserir atrasos entre animações como este:

func delay(_ duration: TimeInterval) -> Observable { return Observable.of(()).delay(duration, scheduler: MainScheduler.instance) } Observable.concat([ rotate(animatableView, duration: 0.5), delay(0.5), shift(animatableView, duration: 0.5), delay(1), fade(animatableView, duration: 0.5) ]) .subscribe() .disposed(by: disposeBag)

Agora, vamos supor que queremos que a vista gire um certo número de vezes antes de começar a se mover. E queremos ajustar facilmente quantas vezes ele deve girar.

Primeiro, farei um método que repete a animação de rotação continuamente e emite um elemento após cada rotação. Quero que essas rotações parem assim que o observável for descartado. Eu poderia fazer algo assim:

como se tornar certificado pelo aws
func rotateEndlessly(_ view: UIView, duration: TimeInterval) -> Observable { var disposed = false return Observable.create { (observer) -> Disposable in func animate() { UIView.animate(withDuration: duration, animations: { view.transform = view.transform.rotated(by: .pi/2) }, completion: { (_) in observer.onNext(()) if !disposed { animate() } }) } animate() return Disposables.create { disposed = true } } }

E então minha bela cadeia de animações poderia ser assim:

Observable.concat([ rotateEndlessly(animatableView, duration: 0.5).take(5), shift(animatableView, duration: 0.5), fade(animatableView, duration: 0.5) ]) .subscribe() .disposed(by: disposeBag)

Você vê como é fácil controlar quantas vezes a visualização irá girar - basta alterar o valor passado para o take operador.

GIF animado da animação aprimorada

Agora, gostaria de levar minha implementação um passo adiante, envolvendo cada uma das funções de animação que criei na extensão 'Reativa' do UIView (acessível por meio do sufixo .rx). Isso o tornaria mais próximo das convenções RxSwift, em que funções reativas são geralmente acessadas por meio do .rx sufixo para deixar claro que eles estão retornando um observável.

extension Reactive where Base == UIView { func shift(duration: TimeInterval) -> Observable { return Observable.create { (observer) -> Disposable in UIView.animate(withDuration: duration, animations: { self.base.frame = self.base.frame.offsetBy(dx: 50, dy: 0) }, completion: { (_) in observer.onNext(()) observer.onCompleted() }) return Disposables.create() } } func fade(duration: TimeInterval) -> Observable { return Observable.create { (observer) -> Disposable in UIView.animate(withDuration: duration, animations: { self.base.alpha = 0 }, completion: { (_) in observer.onNext(()) observer.onCompleted() }) return Disposables.create() } } func rotateEndlessly(duration: TimeInterval) -> Observable { var disposed = false return Observable.create { (observer) -> Disposable in func animate() { UIView.animate(withDuration: duration, animations: { self.base.transform = self.base.transform.rotated(by: .pi/2) }, completion: { (_) in observer.onNext(()) if !disposed { animate() } }) } animate() return Disposables.create { disposed = true } } } }

Com isso, posso colocá-los juntos assim:

Observable.concat([ animatableView.rx.rotateEndlessly(duration: 0.5).take(5), animatableView.rx.shift(duration: 0.5), animatableView.rx.fade(duration: 0.5) ]) .subscribe() .disposed(by: disposeBag)

Para onde ir a partir daqui

Como este artigo ilustra, ao liberar o poder do RxSwift, e depois de ter seus primitivos no lugar, você pode se divertir muito com as animações. Seu código é limpo e fácil de ler, e não se parece mais com 'código' - você 'descreve' como suas animações são montadas e elas ganham vida! Se você quiser fazer algo mais elaborado do que o descrito aqui, certamente poderá fazer isso adicionando mais primitivos seus, encapsulando outros tipos de animações. Você também pode sempre aproveitar as vantagens do arsenal crescente de ferramentas e estruturas desenvolvidas por algumas pessoas apaixonadas na comunidade de código aberto.

Se você é um convertido RxSwift, continue visitando o Repositório RxSwiftCommunity regularmente: você sempre pode encontrar algo novo!

Se você estiver procurando por mais conselhos sobre a interface do usuário, tente ler Como implementar um design de interface do usuário iOS perfeito para pixels pelo colega ApeeScapeer Roman Stetsenko.


Notas da fonte (entendendo o básico)

como hackear um número de cartão de crédito Visa Master Cards
  • Wikipedia - Swift (linguagem de programação)
  • Lynda.com - RxSwift: Padrões de design para desenvolvedores iOS
  • We Heart Swift - UIView Fundamentals
  • Angular - Observáveis

Compreender o básico

Para que é usado o Swift?

'Swift é uma linguagem de programação compilada multi-paradigma de propósito geral desenvolvida pela Apple Inc. para iOS, macOS, watchOS, tvOS, Linux ez / OS. O Swift foi projetado para funcionar com as estruturas Cocoa e Cocoa Touch da Apple e o grande corpo de código Objective-C existente escrito para produtos Apple. '

O que é UIVIew no iOS?

'A classe UIView define uma área retangular na tela na qual mostra o conteúdo. Ele lida com a renderização de qualquer conteúdo em sua área e também com quaisquer interações com esse conteúdo - toques e gestos. '

O que se entende por programação reativa?

A programação reativa é um paradigma de programação assíncrona preocupado com fluxos de dados assíncronos e a propagação da mudança.

O que é RxSwift?

RxSwift é a biblioteca de programação reativa para iOS. Facilita a programação de aplicativos dinâmicos que respondem a alterações de dados e eventos do usuário.

O que é um observável?

Os observáveis ​​fornecem suporte para a passagem de mensagens entre editores e assinantes em seu aplicativo. Os observáveis ​​convertem fluxos de dados em sequência de eventos entregues a um ou mais assinantes de forma assíncrona.

ApeeScape oferece seu talento de programação de elite com custo reduzido para empreendedores iniciantes

De Outros

ApeeScape oferece seu talento de programação de elite com custo reduzido para empreendedores iniciantes
Executivo de Vendas Corporativas - Dallas / Houston

Executivo de Vendas Corporativas - Dallas / Houston

De Outros

Publicações Populares
Manter frameworks PHP MVC Slim com uma estrutura em camadas
Manter frameworks PHP MVC Slim com uma estrutura em camadas
Modelos de preços SaaS - exemplos de estratégia de preços e práticas recomendadas
Modelos de preços SaaS - exemplos de estratégia de preços e práticas recomendadas
A pessoa mais velha do mundo, a italiana Emma Morano, morre aos 117 anos
A pessoa mais velha do mundo, a italiana Emma Morano, morre aos 117 anos
Salesforce Einstein AI: um tutorial de API
Salesforce Einstein AI: um tutorial de API
UX em evolução - Design de produto experimental com um CXO
UX em evolução - Design de produto experimental com um CXO
 
Na adolescência, o estresse excessivo pode desencadear acidez
Na adolescência, o estresse excessivo pode desencadear acidez
Princípios de Design Organizacional e Otimização: Lições da Grande Recessão
Princípios de Design Organizacional e Otimização: Lições da Grande Recessão
Da política à família: como a indicação de Kamala Harris é relevante para a Índia
Da política à família: como a indicação de Kamala Harris é relevante para a Índia
Implementando um servidor Framebuffer remoto em Java
Implementando um servidor Framebuffer remoto em Java
Republicanos e democratas criticam Trump por reivindicar a vitória prematuramente
Republicanos e democratas criticam Trump por reivindicar a vitória prematuramente
Publicações Populares
  • rendimento de dendê por hectare
  • como escrever uma linguagem de programação
  • onde posso aprender c ++
  • como hackear um PIN de cartão de crédito
  • gulp-minify-css
  • diferença em c corp e s corp
  • como fazer sua própria linguagem de codificação
Categorias
  • Ferramentas E Tutoriais
  • Noticias Do Mundo
  • Pessoas E Equipes
  • Ascensão Do Remoto
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt