Com o Glass, você pode criar interações avançadas com seus cards, como rolagem. e animações.
Como rolar cards em atividades
A tela e o touchpad do Google Glass são ótimos para exibir cartões que podem ser deslizados,
como no cronograma do Glass. Se você estiver criando uma atividade, poderá criar
o mesmo tipo de efeito com
CardScrollView
widget.
- Implementar um
CardScrollAdapter
para fornecer cartões aoCardScrollView
Você pode criar uma hierarquia de visualização padrão por conta própria ou usar oCardBuilder
. - Crie um
CardScrollView
que usa oCardScrollAdapter
como fornecedor de cartões. - Defina a visualização de conteúdo da sua atividade como a
CardScrollView
ou exibirCardScrollView
em um layout.
Confira esta implementação simples que percorre três cards:
public class CardScrollActivity extends Activity {
private List<CardBuilder> mCards;
private CardScrollView mCardScrollView;
private ExampleCardScrollAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createCards();
mCardScrollView = new CardScrollView(this);
mAdapter = new ExampleCardScrollAdapter();
mCardScrollView.setAdapter(mAdapter);
mCardScrollView.activate();
setContentView(mCardScrollView);
}
private void createCards() {
mCards = new ArrayList<CardBuilder>();
mCards.add(new CardBuilder(this, CardBuilder.Layout.TEXT)
.setText("This card has a footer.")
.setFootnote("I'm the footer!"));
mCards.add(new CardBuilder(this, CardBuilder.Layout.CAPTION)
.setText("This card has a puppy background image.")
.setFootnote("How can you resist?")
.addImage(R.drawable.puppy_bg));
mCards.add(new CardBuilder(this, CardBuilder.Layout.COLUMNS)
.setText("This card has a mosaic of puppies.")
.setFootnote("Aren't they precious?")
.addImage(R.drawable.puppy_small_1);
.addImage(R.drawable.puppy_small_2);
.addImage(R.drawable.puppy_small_3));
}
private class ExampleCardScrollAdapter extends CardScrollAdapter {
@Override
public int getPosition(Object item) {
return mCards.indexOf(item);
}
@Override
public int getCount() {
return mCards.size();
}
@Override
public Object getItem(int position) {
return mCards.get(position);
}
@Override
public int getViewTypeCount() {
return CardBuilder.getViewTypeCount();
}
@Override
public int getItemViewType(int position){
return mCards.get(position).getItemViewType();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return mCards.get(position).getView(convertView, parent);
}
}
}
Como interagir com cards de rolagem
Como
CardScrollView
estende AdapterView
implemente os listeners padrão do Android.
- Chamar o modelo
setOnItemClickListener()
no seuCardScrollView
. - Implementar um
onItemClick()
para o evento de toque.
Aqui está uma extensão ao exemplo anterior que toca um som de toque ao tocar em um cartão:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
setupClickListener();
setContentView(mCardScrollView);
}
private void setupClickListener() {
mCardScrollView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
am.playSoundEffect(Sounds.TAP);
}
});
}
Animar cartões de rolagem
Há três animações disponíveis para cartões de rolagem: navegação, inserção e exclusão.
- Implemente uma ação de inserção ou exclusão em um card em uma posição específica no conjunto de cards.
- Ligação
animate()
e use um valor da enumeraçãoCardScrollView.Animation
. Para exibir uma animação mais suave, remova todas as referências a
notifyDataSetChanged()
Oanimate()
gerencia a atualização da visualização do conjunto de dados.private class ExampleCardScrollAdapter extends CardScrollAdapter { ... // Inserts a card into the adapter, without notifying. public void insertCardWithoutNotification(int position, CardBuilder card) { mCards.add(position, card); } } private void insertNewCard(int position, CardBuilder card) { // Insert new card in the adapter, but don't call // notifyDataSetChanged() yet. Instead, request proper animation // to inserted card from card scroller, which will notify the // adapter at the right time during the animation. mAdapter.insertCardWithoutNotification(position, card); mCardScrollView.animate(position, CardScrollView.Animation.INSERTION); }
Dicas de desempenho e implementação para cartões de rolagem
Tenha em mente as seguintes implicações de design e desempenho ao criar controles de rolagem de cartão.
Ciclo de vida do cartão
Para melhorar o desempenho, um CardScrollView
carrega apenas um subconjunto dos cards que um
CardScrollAdapter
fornece (geralmente, os que são visíveis para o usuário e alguns outros).
Por isso, um card pode estar em qualquer um destes quatro estados gerais:
- Independente: a visualização de rolagem do card não precisa desse card no momento.
Você vai receber uma notificação pelo
onDetachedToWindow()
do cartão se um cartão tiver sido previamente anexado e, em seguida, desanexado. - Anexado: a visualização de rolagem do card solicita o cartão do adaptador com
getView()
, porque o cartão está perto de ser "ativado". Quando isso acontece, você recebe uma notificação pelo métodoonAttachedToWindow()
do cartão. - Ativado: o card fica parcialmente visível para o usuário, mas a rolagem do card
visualização não "selecionada" o card a ser exibido ao usuário. A
Método 'isActivated()'
retorna
true
nesse caso. - Selecionado: o card está ocupando o
em toda a tela. Chamar
getSelectedView()
retorna o cartão selecionado. O métodoisSelected()
retorna verdadeiro nesse caso.
Se estiver animando a visualização do cartão ou fazendo outras operações que custam caro,
iniciar e interromper as operações
onAttachedToWindow()
e
onDetachedToWindow()
para economizar recursos.
Reciclagem de cartões
Quando um card passa de ser anexado para desanexado, o objeto de visualização associado a o cartão pode ser reciclado e usado por outro cartão anexado. Reciclar visualizações com informações atualizadas é muito mais eficiente do que criando novas visualizações.
Para aproveitar a reciclagem de cartões, implemente a
getItemViewType()
,
getViewTypeCount()
,
e getView()
métodos do
CardScrollAdapter
. Depois, você vai usar alguns dos métodos de conveniência no CardBuilder
.
para implementar a reciclagem na sua CardScrollAdapter
,
como no exemplo a seguir:
private List<CardBuilder> mCards;
...
/**
* Returns the number of view types for the CardBuilder class. The
* CardBuilder class has a convenience method that returns this value for
* you.
*/
@Override
public int getViewTypeCount() {
return CardBuilder.getViewTypeCount();
}
/**
* Returns the view type of this card, so the system can figure out
* if it can be recycled. The CardBuilder.getItemViewType() method
* returns it's own type.
*/
@Override
public int getItemViewType(int position){
return mCards.get(position).getItemViewType();
}
/**
* When requesting a card from the adapter, recycle the view if possible.
* The CardBuilder.getView() method automatically recycles the convertView
* it receives, if possible, or creates a new view if convertView is null or
* of the wrong type.
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return mCards.get(position).getView(convertView, parent);
}
Implementação de IDs de cartão estáveis
Quando um card é selecionado e exibido aos usuários, é possível que você não
quer que as mudanças no adaptador afetem a placa que aparece para os usuários.
naquele momento. Por exemplo, se um usuário estiver visualizando um cartão selecionado, e um cartão
é removido à esquerda do cartão, o cartão que o usuário
pode mudar para a esquerda, porque
CardScrollAdapter
por padrão, reatribui IDs ao conjunto de dados subjacente quando ocorrem alterações.
Se fizer sentido atribuir IDs exclusivos aos seus cartões, você poderá manter
um ID consistente no conjunto de dados subjacente para evitar o problema mencionado acima.
Para fazer isso, substitua
hasStableIds()
e retornam true
. Isso especifica para o sistema que o
CardScrollAdapter
mantém IDs estáveis nas mudanças do conjunto de dados. Além disso, implemente
getItemId()
para retornar o ID exclusivo apropriado para os cartões no adaptador.
A implementação padrão retorna o índice de posição do cartão no adaptador,
que é inerentemente instável.
CardRoleAdapter vazio
Quando você tem um conjunto de dados vazio para os adaptadores, a visualização padrão é mostrar
uma tela preta. Se você quiser exibir uma visualização diferente nesses casos,
não use setEmptyView()
.
Em vez disso, crie um único cartão no CardScrollAdapter
.
Feedback de reboque horizontal
Muitas imersões integradas ao Google Glass oferecem "puxar" feedback ao deslizar para trás e para a frente, não realizam uma ação. Por exemplo, é possível conferir esse feedback deslizando o dedo após tirar uma foto.
Se a imersão não usar gestos de deslizar horizontalmente para realizar
específicas de cada aplicativo, forneça esse efeito de atração enrolando
o layout em um
CardScrollView
que contém um card.
Copie a seguinte classe auxiliar no seu projeto:
public class TuggableView extends CardScrollView { private final View mContentView; /** * Initializes a TuggableView that uses the specified layout * resource for its user interface. */ public TuggableView(Context context, int layoutResId) { this(context, LayoutInflater.from(context) .inflate(layoutResId, null)); } /** * Initializes a TuggableView that uses the specified view * for its user interface. */ public TuggableView(Context context, View view) { super(context); mContentView = view; setAdapter(new SingleCardAdapter()); activate(); } /** * Overridden to return false so that all motion events still * bubble up to the activity's onGenericMotionEvent() method after * they are handled by the card scroller. This allows the activity * to handle TAP gestures using a GestureDetector instead of the * card scroller's OnItemClickedListener. */ @Override protected boolean dispatchGenericFocusedEvent(MotionEvent event) { super.dispatchGenericFocusedEvent(event); return false; } /** Holds the single "card" inside the card scroll view. */ private class SingleCardAdapter extends CardScrollAdapter { @Override public int getPosition(Object item) { return 0; } @Override public int getCount() { return 1; } @Override public Object getItem(int position) { return mContentView; } @Override public View getView(int position, View recycleView, ViewGroup parent) { return mContentView; } } }
Modifique o método
onCreate
na sua atividade para mostrar aCardScrollView
que contém seu layout.@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // was: setContentView(R.layout.main_activity); setContentView(new TuggableView(this, R.layout.main_activity)); }