A PhotoView API é uma simples API Android que permite implementar funcionalidade de zoom em imagens de forma fácil. A API oferece listeners para diferentes eventos de toque, métodos para controlar escala de zoom e rotação de imagens, e é compatível com APIs populares de carregamento de imagens como Picasso.
2. Android PhotoView
A PhotoView API é uma daquelas APIs
simples, mas que atendem a vários domínios
de problema, exatamente como a Picasso
API e o Retrofit, por exemplo.
A diferença da PhotoView para com as APIs
citadas anteriormente é que ela é ainda mais
simples de ser incorporada a projetos Android
e foi desenvolvida por um dos engenheiros do
Google Android, Chris Banes.
A PhotoView tem suporte a partir do Android
4, Donut. E apesar de oferecer algumas
características extras, como a rotação de
imagem, a proposta principal, zoom em
imagem, é muito bem atendida, mesmo com
o carregamento de imagens remotas.
3. Instalação da API
A API está presente no repositório JVM Jitpack. Logo, primeiro temos de adicionar
esse repositório no Gradle Project Level, ou build.gradle (Project:
NomeAplicativo):
Depois é adicionar a referência a API no Gradle App Level, ou build.gradle
(Module: app):
Na época da construção deste conjunto de slides a versão mais atual e estável da
API era a 2.1.4. Escolha sempre por utilizar a versão mais atual e estável.
4. Carregamento de imagem com PhotoView
A principal bandeira que faz com que a PhotoView API tenha mais de 13k estrelas
no GitHub (isso é um forte indício de que a API tem alta qualidade) é a facilidade de
uso. Veja o código de exemplo:
A PhotoView é uma implementação mais robusta do ImageView, ela herda desta
View. Logo, podemos utilizar todos os atributos possíveis no ImageView.
5. Executando o projeto Android com o trecho de código anterior, temos:
Clique aqui para abrir a animação
6. O acesso a PhotoView via código também é simples, utilizando o método
findViewById() ou então o ID da View seguindo a sintaxe do plugin kotlin-android-
extensions:
7. Carregamento remoto de imagem - Picasso API
A princípio a única API de carregamento remoto de imagem que não tem suporte
junto a PhotoView é a API Fresco, para driblar esta limitação, caso você realmente
esteja em um projeto onde a Fresco API seja indispensável, a documentação da
PhotoView indica a API PhotoDraweeView.
As outras APIs de carregamento remoto funcionam sem problemas junto a
PhotoView, ao menos as principais. A mais comum para esse tipo de tarefa é a
Picasso.
A seguir um XML PhotoView ainda sem uma imagem referenciada:
8. Agora a referência a Picasso API direto do Gradle App Level, build.gradle
(Module: app):
Então a permissão de Internet no AndroidManifest.xml:
E assim o código de carregamento de imagem via Picasso API:
9. Executando o projeto com os códigos anteriormente apresentados, temos:
Clique aqui para abrir a animação
10. Trabalhando as escalas de zoom
Se o domínio de problema do aplicativo em desenvolvimento exigir que as três
escalas de zoom padrão sejam trabalhadas em outros valores, você consegue isso
com as seguintes propriedades:
• minimumScale: defini / obtém a escala mínima de zoom. O valor padrão é
1.0F, valor que representa a escala inicial, onde o zoom ainda não foi aplicado;
• mediumScale: defini / obtém a segunda escala de zoom. O valor padrão é
1.75F;
• maximumScale: defini / obtém a terceira escala de zoom. O valor padrão é
3.0F.
Agora um PhotoView de exemplo:
11. Então o código de alteração de escalas de zoom:
Executando o projeto com os códigos anteriores, temos:
Clique aqui para abrir a animação
O método setScaleLevels()
permiti que as três escalas
sejam atualizadas em uma
única invocação.
12. Caso seja necessária a atualização da escala de zoom atual em imagem, utilize:
• scale: propriedade que permiti obter / atualizar a escala atual de zoom no PhotoView
alvo. Aqui a atualização vai gerar uma mudança brusca de escala de zoom. O valor
aceito / retornado é do tipo Float;
• setScale( escala_em_float, animacao_em_boolean ): método que permite definir a
nova escala de zoom no PhotoView alvo, mas aqui é possível, em segundo
argumento, informar se a animação de mudança de escala deve ou não ser aplicada. O
valor true indica que sim, false indica que não.
Segue código de exemplo de atualização de escala de zoom em imagem:
13. Como informado em comentário do código anterior: scale e setScale() somente
têm efeito depois que a PhotoView alvo já está renderizada em tela, por isso o
código de exemplo é acompanhado de uma thread e um SystemClock.sleep().
Importante: o valor definido em scale ou em setScale() deve estar no range
[minimumScale, maximumScale], caso contrário uma IllegalArgumentException
será gerada.
Executando o projeto com o trecho de código anterior, temos:
Clique aqui para abrir a animação
14. Listener de atualização de escala
Para ouvir a cada mudança de fator de escala basta implementar a Interface
OnScaleChangedListener como no código a seguir:
Como informado em comentário, focusX e focusY somente terão a mudança de valor se o
acionamento do zoom for em tela, em qualquer parte do PhotoView, não necessariamente na
parte onde a imagem aparece.
15. Verificação e duração de animação
Para verificar ou então atualizar o status de zoom na PhotoView, utilize a
propriedade isZoomable:
Para trabalhar o tempo de duração da animação de zoom, utilize o método
setZoomTransitionDuration(), veja a seguir:
16. Com a PhotoView de teste a seguir:
Podemos executar o código com delay de quatro segundos em animação de zoom:
Clique aqui para abrir a animação
17. Rotação da imagem
Por algum motivo foi adicionada a API a funcionalidade de rotação de acordo com o
grau definido. São dois métodos passíveis de serem utilizados: setRotationBy() e
setRotationTo().
Acredite, ambos os métodos aguardam o mesmo tipo de argumento, graus de
rotação em Float, e têm o mesmo código interno.
Os métodos de rotação seguem a mesma regra de negócio que a propriedade e
método de mudança de escala de zoom: somente terão efeitos visuais se
invocados depois que a PhotoView já estiver renderizada em tela.
A seguir uma PhotoView de exemplo:
19. Executando o projeto com os códigos anteriores, temos:
Clique aqui para abrir a animação
20. Listener de toque em imagem
Para ouvir o toque / clique único em imagem, podemos implementar a Interface
OnPhotoTapListener como a seguir:
Note que o método onPhotoTap() somente é invocado se o toque na imagem for exatamente
na área coberta por ela e não em toda a área coberta pela PhotoView, onde pode haver
espaços não cobertos pela imagem.
21. Listener de toque fora da imagem
Também é possível ouvir ao toque / clique dentro da PhotoView, porém fora da
área de cobertura da imagem, isso implementando a Interface
OnOutsidePhotoTapListener como no código a seguir:
22. Listener de toque na PhotoView
Para ouvir ao toque ou clique em qualquer parte da PhotoView, com cobertura ou
não da imagem carregada, é necessário implementar a Interface
OnViewTapListener como a seguir:
23. Listener de duplo toque, único toque e duplo toque seguido
de ação
Para ouvir ao toque duplo, ou ao
toque único, incluindo o listener
de ação pós toque duplo,
podemos implementar a Interface
GestureDetector.OnDoubleTap
Listener:
O método
onSingleTapConfirmed()
funciona exatamente com a
mesma regra de negócio que o
método onViewTap() de
OnViewTapListener: o toque
único precisa ocorrer dentro da
PhotoView.
24. Ouvindo ao evento de drag
O listener de drag na imagem é tão sensível que até mesmo quando o drag não é
passível de ser visualizado em tela, quando o zoom não foi ainda aplicado, esse
listener é invocado.
Antes de mostrar o código de listener de drag, vamos a um exemplo do que seria
um drag junto ao componente PhotoView:
Clique aqui para abrir a animação
25. Então podemos ir ao código que implementa a Interface OnViewDragListener:
26. Ouvindo a atualização da matriz da imagem
Se em seu domínio de problema é preciso algum trabalho quando houver a atualização do
objeto Matrix da imagem, para isso é possível implementar a Interface
OnMatrixChangedListener como a seguir:
27. Hackcode para ViewGroups problemáticos
Alguns ViewGroups que implementam OnInterceptTouchEvent, como o
ViewPager e o DrawerLayout, disparam exceções quando alguma PhotoView
está dentro deles.
O código hack para burlar esse problema é o seguinte:
28. Note que o código do slide anterior é bem genérico, serve para qualquer
ViewGroup problemático. Veja, por exemplo, as implementações de hackcode,
direto da documentação oficial da PhotoView API, para:
• ViewPager;
• DrawerLayout.
29. Pontos negativos
• A documentação não mostra, detalhadamente, como obter o máximo da
PhotoView, é preciso navegar pelos exemplos (sem comentários) para então
entender a API por completo;
• O nome da API é bem confuso em relação a proposta dela. Um rótulo como
ZoomView certamente cairia melhor na API;
• A funcionalidade de rotação de imagem poderia ser removida, pois não tem
haver com a proposta de ser uma API simples para a aplicação de zoom. Ou:
• É possível que a funcionalidade de rotação tenha sido adicionada devido ao
problema que alguns devices Android têm depois que uma fotografia é
realizada: a imagem é entregue invertida. Com os métodos de rotação seria
simples resolver isso, porém na documentação não há nada informando o
porquê da API de rotação.
• A Interface OnSingleFlingListener quando em uso não trás nada diferente do
que é conseguido com outras Interfaces da API PhotoView, Interfaces que têm
um rótulo muito mais significativo em termos boa de leitura de código.
30. Pontos positivos
• Código muito simples para já conseguirmos a aplicação completa de zoom;
• Possibilidade de atualização de níveis de escala e de duração do zoom;
• Vários tipos de listeners que permitem o acionamento das mais variadas
funções de acordo com o toque do usuário em View;
• Possibilidade de trabalho com APIs de carregamento de imagens remotas.
31. Conclusão
Apesar do zoom ser uma funcionalidade simples e que desenvolvedores Android
de primeira viagem possam imaginar já ser uma funcionalidade nativa no
ImageView, por exemplo, na verdade não é.
A API PhotoView faz o trabalho da melhor maneira possível:
• Exigindo poucas linhas de código;
• E entregando o zoom completo.
Obviamente que sempre é possível obter ainda mais de APIs Android, mas a
PhotoView tem realmente uma proposta de ser simples. Logo, seguindo as dicas
da documentação, se você precisa de algo ainda mais robusto em termos de
escala de imagem, tente a API Subsampling-Scale-Image-View.
32. Fontes
Conteúdo completo, em texto e em vídeo, no link a seguir:
• https://www.thiengo.com.br/photoview-android-para-a-completa-
implementacao-de-zoom
Fonte:
• https://github.com/chrisbanes/PhotoView
33. Para estudo
• Treinamento oficial:
• Prototipagem Profissional de Aplicativos Android.
• Meus livros:
• Receitas Para Desenvolvedores Android;
• Refatorando Para Programas Limpos.
• Redes:
• Udemy;
• YouTube;
• Facebook;
• LinkedIn;
• GitHub;
• Twitter;
• Google Plus.
• Blog App.
34. PhotoView Android Para a Completa
Implementação de Zoom
thiengo.com.br
Vinícius Thiengo
thiengocalopsita@gmail.com