Grâce aux lunettes Glass, vous pouvez créer des interactions riches avec vos cartes, comme le défilement et des animations.
Cartes défilantes dans les activités
L'écran et le pavé tactile des lunettes Glass sont parfaits pour afficher des cartes à faire glisser,
comme dans la chronologie
Glass. Si vous créez une activité, vous pouvez créer
le même type d'effet
CardScrollView
.
- Implémentez un
CardScrollAdapter
de fournir des cartes auCardScrollView
Vous pouvez créer vous-même une hiérarchie des vues standard ou utiliser laCardBuilder
. - Créez un
CardScrollView
qui utilise leCardScrollAdapter
en tant que fournisseur de cartes. - Définissez la vue du contenu de votre activité
CardScrollView
ou afficher laCardScrollView
dans une mise en page.
Voici une implémentation simple qui fait défiler trois fiches:
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);
}
}
}
Interagir avec des cartes défilantes
Depuis
CardScrollView
étend AdapterView
vous pouvez implémenter les écouteurs Android standards.
- Appelez la méthode
setOnItemClickListener()
sur votreCardScrollView
. - Implémentez un
onItemClick()
pour l'événement d'appui.
Extension de l'exemple précédent, qui émet le son d'un appui lorsque vous appuyez sur une carte:
@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);
}
});
}
Animer des cartes défilantes
Trois animations sont disponibles pour le défilement des cartes: Navigation, Insertion et Suppression.
- Implémentez une action d'insertion ou de suppression d'une fiche à une position spécifiée dans l'ensemble de cartes.
- Appeler
animate()
et utilisez une valeur de l'énumérationCardScrollView.Animation
. Pour obtenir une animation plus fluide, supprimez toute référence à
notifyDataSetChanged()
animate()
gère la mise à jour de la vue de votre ensemble de données.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); }
Conseils sur les performances et l'implémentation pour le défilement des cartes
Tenez compte des implications suivantes en termes de conception et de performances lorsque vous créez de défilement des cartes.
Cycle de vie d'une carte
Pour améliorer les performances, une CardScrollView
ne charge qu'un sous-ensemble des fiches
CardScrollAdapter
fournit (généralement celles que l'utilisateur peut voir, et quelques autres).
Pour cette raison, une carte peut être dans l'un des quatre états généraux suivants:
- Dissocié : la vue de défilement de la carte n'a pas besoin de cette fiche pour le moment.
Vous êtes averti par le
onDetachedToWindow()
de la carte si une carte a été associée, puis dissociée. - Associé : la vue de défilement de la carte demande la fiche à l'adaptateur avec
getView()
, car la carte est sur le point d'être "activée". Dans ce cas, vous en êtes informé via la méthodeonAttachedToWindow()
de la carte. - Activé : la fiche est partiellement visible par l'utilisateur, mais l'utilisateur peut la faire défiler.
la vue n'est pas "sélectionnée" la fiche à présenter à l'utilisateur. La
Méthode 'isActivated()'
renvoie
true
dans ce cas. - Sélectionnée : la fiche occupe l'espace de l'utilisateur.
l'intégralité de l'écran. L'appel de
getSelectedView()
renvoie la carte actuellement sélectionnée. La méthodeisSelected()
renvoie "true" dans ce cas.
Si vous animez la vue de votre carte
ou effectuez d'autres opérations coûteuses,
démarrer et arrêter les opérations dans
onAttachedToWindow()
et
onDetachedToWindow()
pour économiser des ressources.
Recyclage de cartes
Lorsqu'une carte est dissociée d'une carte, l'objet de vue associé à la carte peut être recyclée et utilisée par une carte qui est attachée. Recycler les vues avec des informations mises à jour est beaucoup plus efficace que en créant des vues.
Pour que vos cartes puissent être recyclées, mettez en œuvre le
getItemViewType()
,
getViewTypeCount()
,
et getView()
des méthodes
CardScrollAdapter
. Vous allez ensuite utiliser certaines des méthodes pratiques de CardBuilder
.
pour implémenter le recyclage dans votre CardScrollAdapter
,
comme dans l'exemple suivant:
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);
}
Implémenter des ID de carte stables
Lorsqu'une fiche est sélectionnée et présentée aux utilisateurs, il est possible
souhaitez que les modifications apportées à l'adaptateur sous-jacent affectent la carte que les utilisateurs voient
à ce moment précis. Par exemple, si un utilisateur consulte la fiche sélectionnée et qu'une fiche
est supprimée à gauche de cette fiche, celle que l'utilisateur
peut potentiellement décaler vers la gauche, car
CardScrollAdapter
réattribue les identifiants à l'ensemble de données sous-jacent lorsque des modifications se produisent, par défaut.
S'il est logique d'attribuer des identifiants uniques à vos cartes, vous pouvez maintenir
un identifiant cohérent dans l'ensemble de données sous-jacent pour éviter le problème susmentionné.
Pour ce faire, remplacez
hasStableIds()
et renvoyez true
. Cela indique au système que le
CardScrollAdapter
conserve des identifiants stables lors des modifications apportées aux ensembles de données. En outre, implémentez
getItemId()
pour renvoyer l'identifiant unique approprié pour les cartes de votre adaptateur.
L'implémentation par défaut renvoie l'index de position de la carte dans l'adaptateur,
qui est instable par nature.
Vider CardScrollAdapter
Lorsque vous disposez d'un ensemble de données vide pour les adaptateurs, la vue par défaut est la suivante :
un écran noir. Si vous voulez afficher une
vue différente dans ces cas,
n'utilisez pas setEmptyView()
.
Créez plutôt une seule fiche dans votre CardScrollAdapter
.
Commentaires sur le tirage horizontal
De nombreuses immersions intégrées dans les Google Glass donnent un effet de "tirer" en balayant l'écran vers l'arrière n'effectuent pas d'action. Par exemple, vous pouvez voir ces commentaires après avoir pris une photo.
Si votre immersion n'utilise pas de gestes
de balayage horizontal pour effectuer
spécifiques à l'application, fournissent cet effet de tirage en encapsulant votre
à l'intérieur d'une
CardScrollView
qui contient une fiche.
Copiez la classe d'assistance suivante dans votre projet:
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; } } }
Modifiez la méthode
onCreate
dans votre activité pour afficher lesCardScrollView
qui contient votre mise en page.@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // was: setContentView(R.layout.main_activity); setContentView(new TuggableView(this, R.layout.main_activity)); }