Barre de défilement des cartes

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 .

  1. Implémentez un CardScrollAdapter de fournir des cartes au CardScrollView Vous pouvez créer vous-même une hiérarchie des vues standard ou utiliser la CardBuilder .
  2. Créez un CardScrollView qui utilise le CardScrollAdapter en tant que fournisseur de cartes.
  3. Définissez la vue du contenu de votre activité CardScrollView ou afficher la CardScrollView 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.

  1. Appelez la méthode setOnItemClickListener() sur votre CardScrollView.
  2. 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.

  1. Implémentez une action d'insertion ou de suppression d'une fiche à une position spécifiée dans l'ensemble de cartes.
  2. Appeler animate() et utilisez une valeur de l'énumération CardScrollView.Animation.
  3. 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éthode onAttachedToWindow() 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éthode isSelected() 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.

  1. 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;
            }
        }
    }
    
  2. Modifiez la méthode onCreate dans votre activité pour afficher les CardScrollView 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));
    }