Mit Glass können Sie umfangreiche Interaktionen mit Ihren Karten erstellen, z. B. Scrollen und Animationen.
Karten in Aktivitäten scrollen
Das Glass-Display und das Touchpad eignen sich hervorragend zum Anzeigen von Swipe-Karten, wie auf der Glass-Zeitachse. Wenn Sie eine Aktivität erstellen, können Sie denselben Effekt mit dem Widget CardScrollView
erstellen.
- Implementiere
CardScrollAdapter
, um Karten fürCardScrollView
bereitzustellen. Sie können selbst eine Hierarchie für die Standardansicht erstellen oder die KlasseCardBuilder
verwenden. - Erstellen Sie eine
CardScrollView
, dieCardScrollAdapter
als Anbieter für Karten verwendet. - Lege für die Inhaltsansicht deiner Aktivität den Wert
CardScrollView
fest oder lege denCardScrollView
in einem Layout fest.
Mit dieser einfachen Implementierung können Sie durch die Karten scrollen:
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);
}
}
}
Mit scrollbaren Karten interagieren
Da CardScrollView
AdapterView
erweitert, kannst du die standardmäßigen Android-Listener implementieren.
- Rufen Sie die übernommene
setOnItemClickListener()
auf IhremCardScrollView
auf. - Implementiere einen
onItemClick()
-Handler für das Tippereignis.
Hier ist eine Erweiterung des vorherigen Beispiels, die beim Tippen auf eine Karte einen Nutzungston abspielt:
@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);
}
});
}
Scrollkarten animieren
Es gibt drei Animationen für Karten: Navigation, Einfügen und Löschen.
- Eine Aktion zum Einfügen oder Löschen für eine Karte an einer bestimmten Position im Kartensatz implementieren
- Rufen Sie
animate()
auf und verwenden Sie einen Wert aus der AufzählungCardScrollView.Animation
. Entfernen Sie alle Verweise auf
notifyDataSetChanged()
, um eine flüssigere Animation anzuzeigen. Mit der Methodeanimate()
wird die Dataset-Ansicht aktualisiert.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); }
Leistungs- und Implementierungstipps für scrollbare Karten
Beachten Sie beim Erstellen von Kartenscrollern die folgenden Design- und Leistungsanforderungen.
Kartenlebenszyklus
Zur Steigerung der Leistung lädt ein CardScrollView
nur einen Teil der Karten, die von CardScrollAdapter
bereitgestellt werden. Das sind in der Regel die Karten, die für den Nutzer sichtbar sind, und einige weitere.
Aus diesem Grund kann eine Karte einen der folgenden vier allgemeinen Status haben:
- Losgelöst: Die Karte wird beim Scrollen nicht zum aktuellen Zeitpunkt benötigt.
Sie werden über die Methode
onDetachedToWindow()
der Karte benachrichtigt, wenn eine Karte zuvor angehängt und dann getrennt wurde. - Angehängt: Die Karte zum Scrollen fordert die Karte vom Adapter mit
getView()
an, da die Karte fast aktiviert wird. In diesem Fall werden Sie von deronAttachedToWindow()
-Methode der Karte benachrichtigt. - Aktiviert: Die Karte ist für den Nutzer nur teilweise sichtbar, aber die Karte hat beim Scrollen nicht die Karte angezeigt, die für den Nutzer sichtbar ist. Die Methode 'isActivated()' gibt in diesem Fall
true
zurück. - Ausgewählt: Die Karte nimmt den gesamten Bildschirm des Nutzers ein. Wenn Sie
getSelectedView()
aufrufen, wird die aktuell ausgewählte Karte zurückgegeben. Die MethodeisSelected()
gibt in diesem Fall „true“ zurück.
Wenn Sie die Ansicht der Karte animieren oder andere kostspielige Vorgänge ausführen, starten und beenden Sie die Vorgänge in onAttachedToWindow()
und onDetachedToWindow()
, um Ressourcen zu sparen.
Recycling von Karten
Wenn eine Karte getrennt oder getrennt wird, kann das mit der Karte verknüpfte Ansichtsobjekt recycelt und von einer angehängten Karte verwendet werden. Das Recycling von Ansichten mit aktualisierten Informationen ist viel effizienter als das Erstellen neuer Ansichten.
Implementieren Sie die Methoden getItemViewType()
, getViewTypeCount()
und getView()
der Klasse CardScrollAdapter
, um das Recycling von Karten zu nutzen. Anschließend verwenden Sie einige der Convenience-Methoden in der Klasse CardBuilder
, um Recycling in CardScrollAdapter
zu implementieren. Beispiel:
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);
}
Stabile Karten-IDs implementieren
Wenn eine Karte ausgewählt ist und Nutzern angezeigt wird, möchten Sie möglicherweise nicht, dass sich der zugrunde liegende Adapter auf die Karte auswirkt, die Nutzern in diesem Moment angezeigt wird. Wenn ein Nutzer beispielsweise eine ausgewählte Karte aufruft und links von dieser Karte entfernt wird, kann sich die Karte, die der Nutzer ansieht, nach links verschieben, da die IDs CardScrollAdapter
standardmäßig dem zugrunde liegenden Datensatz neu zugewiesen werden.
Wenn es logisch sinnvoll ist, Ihren Karten eindeutige IDs zuzuweisen, können Sie eine einheitliche ID im zugrunde liegenden Dataset beibehalten, um das oben genannte Problem zu vermeiden.
Überschreiben Sie dazu hasStableIds()
und geben Sie true
zurück. Damit wird festgelegt, dass mit der CardScrollAdapter
stabile IDs bei Änderungen am Dataset beibehalten werden. Implementieren Sie außerdem getItemId()
, um die entsprechende eindeutige ID für die Karten in Ihrem Adapter zurückzugeben.
Die Standardimplementierung gibt den Positionsindex der Karte im Adapter zurück, der von Natur aus instabil ist.
Leerer CardScrollAdapter
Wenn für Adapter kein Datenbestand vorhanden ist, wird standardmäßig ein schwarzer Bildschirm angezeigt. Wenn Sie in diesen Fällen eine andere Ansicht verwenden möchten, verwenden Sie nicht setEmptyView()
.
Erstellen Sie stattdessen in Ihrem CardScrollAdapter
eine einzelne Karte.
Feedback zum horizontalen Ziehen
Viele integrierte Immersionen in Glass geben „Feedback“ beim Zurück- und Wischen, ohne dass eine Aktion ausgeführt wird. Du siehst dieses Feedback beispielsweise, wenn du nach dem Aufnehmen eines Fotos wischst.
Wenn bei Ihrem Immersieren keine horizontalen Wischgesten zum Ausführen anwendungsspezifischer Funktionen verwendet werden, können Sie diesen TUG-Effekt anwenden, indem Sie das Layout innerhalb einer CardScrollView
mit einer Karte umschließen.
Kopieren Sie die folgende Hilfsklasse in Ihr Projekt:
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; } } }
Ändern Sie die
onCreate
-Methode in Ihrer Aktivität, damitCardScrollView
angezeigt wird, das Ihr Layout enthält.@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // was: setContentView(R.layout.main_activity); setContentView(new TuggableView(this, R.layout.main_activity)); }