Caso prefira, você encontrará todo esse material, em inglês, no site do Developer Android. A tradução e comentários dos materiais eu faço livremente para ajudar a comunidade que fala português.

quarta-feira, 16 de março de 2011

Interface de Usuários - Construindo Componentes Customizados

O Android oferece um sofisticado e poderoso modelo componentizado para construir sua interface de usuário, baseado nas classes fundamentais de layout: View e ViewGroup. Para começar, a plataforma inclui uma variedade de Views e ViewGroup chamadas widgets e layouts, respectivamente, que você pode usar para construir sua interface.

Uma lista parcial dos widgets disponíveis incluem Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner e alguns com propostas mais específicas, como AutoCompleteTextView, ImageSwitcher e TextSwitcher.

Entre os layouts disponíveis estão o LinearLayout, FrameLayout, RelativeLayout e outros. Para outros exemplos, veja Common Layout Objects.

Se nenhum dos widgets padrão ou layouts atendem suas necessidades, você pode criar sua própria subclasse View. Você precisará fazer apenas pequenos ajustes no widget ou layout e você pode simplesmente criar uma subclasse do widget ou layout e fazer o override de seus métodos.

Criar sua própria subclasse View dá o controle preciso sobre a aparência e função de um elemento de tela. Para dar uma idéia do controle que você tem com uma view customizada, aqui vão alguns dos exemplos do que você pode fazer com eles:

  • Você pode criar um tipo View completamente customizado como, por exemplo, um controle de volume renderizado usando gráficos 2D que se assemelhe ao controle analógico real.
  • Você pode combinar um grupo de componentes View em um único componente, talvez para fazer algo como uma combobox (uma combinação de lista em popup e um campo text), um controle dual-pane (com paineis do lado esquerdo e direito onde você pode assinalar de qual lista um item faz parte) e assim por diante.
  • Você pode fazer o override na forma como um EditText é renderizado na tela.
  • Você pode capturar outros eventos como keypress e retornar alguma interação de acordo com a maneira como desejar (como em um jogo).

Abordagem básica

Aqui está um overview do que é necessário para começar a criar seus próprios componentes View customizados:
  1. Extenda uma classe View existente ou subclasse em sua própria classe.
  2. Faça o override de alguns dos métodos da superclasse. Os métodos da superclasse a serem feitos override começam com 'on'. Por exemplo, onDraw(), onMeasure(), on KeyDown(). 
  3. Use sua nova classe de extensão. Uma vez completada, a nova classe pode ser usada no lugar da classe na qual ela é baseada.
Dica: Classes de extensão podem ser definidas como classes internas às atividades que as usam. Isso é particularmente útil já que o controle de acesso à classe é feito automaticamente.

Componentes Customizados Completos

Componentes customizados completos podem ser usados para criar componentes gráficos da maneira como desejar. Talvez um medidor gráfico que se pareça com um medidor analógico ou qualquer outra coisa que você tenha em mente. De qualquer forma, você vai querer algo que os componentes padrão ainda não façam, não importa a maneira como você os combine.

Felizmente, você pode facilmente criar componentes que tem o visual e se comportam da maneira que você quer limitado, talvez, apenas pela sua imaginação, o tamanho da tela e o poder de processamento disponível (lembre-se que sua aplicação vai rodar em um dispositivo que terá muito menos poder de processamento que seu desktop onde está criando o app).

Para criar um componente customizado completo:
  1. A View mais genérica da qual você pode extender é, sem surpresa nenhuma, a View. Então, você vai começar, normalmente, extendendo seu código a partir dessa classe e criar seu novo super componente a partir dela.
  2. Você pode suprir um construtor que poderá receber atributos e parâmetros a partir de um arquivo XML.
  3. Você vai querer, provavelmente, criar seus próprios event listeners, property accessors e modifiers e possivelmente comportamentos mais sofisticados dentro da sua classe de componente.
  4. Você vai certamente querer fazer o override do método onMeasure() e também de onDraw() se você quiser que seu componente mostre alguma coisa. Mesmo tendo comportamentos padrão, o onDraw() padrão não faz nada e o onMeasure() padrão vai sempre colocar o tamanho como 100x100.
  5. Outros métodos on... deverão ser overriden.
Extendendo onDraw() e onMeasure()

O método onDraw() cria um Canvas sobre o qual você pode implementar qualquer coisa que queira: gráficos 2D, outros componentes padrão ou customizados, texto estilizado ou qualquer coisa que você possa imaginar. Imagine um pintor que vai criar sua obra. Ele pega as tintas e a tela onde vai pintar. Canvas é a tela onde você poderá criar o que imaginar. Em tecnologia, o termo canvas significa isso: o local onde você poderá criar o que deseja.

Nota: O canvas não se aplica a gráficos 3D. Se quiser usar gráficos dessa natureza, você deve extender SurfaceView ao invés da View, e desenhar o gráfico em uma thread separada. Você pode checar por GLSurfaceViewActivity para mais detalhes.

Já o método onMeasure() é um pouco mais complexo. onMeasure() é uma peça critica para o contrato de renderização do seu componente e o seu container. onMeasure() deve ser overriden para eficientemente e corretamente reportar as medidas de seu container para que a renderização seja perfeita na tela. O onMeasure() foi feito para ser mais complexo por conta dos requerimentos de limites dos componentes pais onde eles estão posicionados e pelo requerimento de chamar o método setMeasuredDimension() com a medida em largura e altura que foi calculada. Se você falhar em chamar esse método de um onMeasure() que foi overriden, o resultado é que uma exceção será chamada.

Implementar o onMeasure() seria algo assim:
  1. O método onMeasure() que foi overriden é chamado com as especificações de largura e altura (parâmetros widthMeasureSpec e heightMeasureSpec, ambos com valores em inteiro representando as dimensões do componente pai onde ele está sendo criado) que deve ser tratado como um requerimento para as restrições de largura e altura a serem produzidas. 
  2. O método onMeasure() do componente calcula as medidas de largura e altura necessárias para renderizar o componente. Ele vai tentar se manter dentro das especificações enviadas.
  3. Uma vez que a largura e altura foram calculadas, o método setMeasuredDimension(int width, int height) deve ser chamado com as medidas calculadas. Se houver uma falha em conseguir um resultado e uma exceção será lançada.
Aqui está um sumário de alguns dos outros métodos padrões que a framework chama nas views:

CategoryMethodsDescription
CreationConstrutoresExiste uma forma do construtor que é chamado quando a View é criada no código ou quando a View é inflada a partir de um arquivo de layout. A segunda forma passa quaisquer atributos definidos no arquivo de layout.
onFinishInflate()Chamado após a view e todos os itens filhos serem inflados da XML.
LayoutonMeasure(int, int)Chamado para determinar os requerimentos de tamanho para  a View e todos os seus filhos.
onLayout(boolean, int, int, int, int)Chamado quando a View deve assinalar o tamanho e posição de todos os seus filhos.
onSizeChanged(int, int, int, int)Chamado quando o tamanho da View foi mudado.
DrawingonDraw(Canvas)Chamado quando uma View deve renderizar seu conteúdo.
Event processingonKeyDown(int, KeyEvent)Chamado quando um novo evento de tecla ocorre.
onKeyUp(int, KeyEvent)Chamado quando um novo evento key up ocorre.
onTrackballEvent(MotionEvent)Chamado quando um evento de movimentação do trackball ocorre.
onTouchEvent(MotionEvent)Chamado quando um evento touch screen ocorre.
FocusonFocusChanged(boolean, int, Rect)Chamado quando uma View ganha ou perde o foco.
onWindowFocusChanged(boolean)Chamado quando uma janela contendo views ganha ou perde foco.
AttachingonAttachedToWindow()Chamado quando uma View é anexada a uma janela.
onDetachedFromWindow()Chamado quando uma View é desanexada de uma janela.
onWindowVisibilityChanged(int)Chamado quando a visibiliadde da janela contendo a View é modificada.
Na página de Demonstração de APIs existem vários exemplos de componentes customizados. Dê uma olhada lá para ver como é o código.

No próximo post, Controles Compostos e como modificar um View Type existente 

1 comentários:

Rafael Neiva disse...

Parabéns pelo texto, me ajudou bastante. Obrigado!

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.
Related Posts Plugin for WordPress, Blogger...