Dzięki Google Glass możesz wzbogacać kartę za pomocą interakcji takich jak przewijanie i animacje.
Przewijanie kart w ramach aktywności
Wyświetlacz i touchpad Google Glass idealnie nadają się do wyświetlania kart przesuwanych, np. na osi czasu Glass. Jeśli tworzysz aktywność, możesz utworzyć ten sam typ efektu, korzystając z widżetu CardScrollView
.
- Zaimplementuj
CardScrollAdapter
w celu dostarczenia kart doCardScrollView
. Możesz utworzyć standardową hierarchię widoków samodzielnie lub użyć klasyCardBuilder
. - Utwórz
CardScrollView
, w którym dostawcą kart jestCardScrollAdapter
. - Ustaw widok treści aktywności na
CardScrollView
lub wyświetlCardScrollView
w układzie.
Oto prosta implementacja, która przewija się za pomocą 3 kart:
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);
}
}
}
Interakcja z przewijanymi kartami
Ponieważ CardScrollView
rozszerza AdapterView
, możesz wdrożyć standardowe detektory Androida.
- Wywołaj odziedziczone ustawienie
setOnItemClickListener()
na urządzeniuCardScrollView
. - Zaimplementuj moduł obsługi
onItemClick()
na potrzeby zdarzenia kliknięcia.
Oto rozszerzenie poprzedniego przykładu, w którym po dotknięciu karty odtwarza się dźwięk kliknięcia:
@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);
}
});
}
Animowanie przewijanych kart
Dostępne są 3 animacje dla kart przewijanych: Nawigacja, Wstawianie i Usuwanie.
- Zaimplementuj funkcję wstawiania lub usuwania na karcie w określonym miejscu w zestawie kart.
- Wywołaj
animate()
i użyj wartości z wyliczeniaCardScrollView.Animation
. Aby animacja była płynniejsza, usuń wszelkie odwołania do
notifyDataSetChanged()
. Metodaanimate()
obsługuje aktualizowanie widoku zbioru danych.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); }
Wskazówki dotyczące wydajności i wdrażania przewijanych kart
Tworząc przewijaki kart, pamiętaj o tych kwestiach dotyczących wyglądu i wydajności.
Cykl życia karty
Aby zwiększyć wydajność, CardScrollView
wczytuje tylko podzbiór kart wyświetlanych przez CardScrollAdapter
(zwykle te, które są widoczne dla użytkownika, oraz kilka innych).
Karta może więc mieć jeden z tych 4 stanów:
- Odłączenie – w widoku przewijania karty nie jest obecnie wymagana ta karta.
Jeśli karta została wcześniej podłączona, a następnie odłączona, metoda
onDetachedToWindow()
karty powiadomi Cię o tym. - Załączono – widok przewijania karty prosi o przesłanie karty z adaptera za pomocą
getView()
, ponieważ karta jest bliska aktywacji. W takiej sytuacji otrzymasz powiadomienie za pomocą metody kartyonAttachedToWindow()
. - Aktywna – karta jest częściowo widoczna dla użytkownika, ale widok przewijania karty nie „wybrał” jej wyświetlenia. W tym przypadku metoda 'isActivated()' zwraca
true
. - Wybrana – karta zajmuje cały ekran użytkownika. Wywołanie
getSelectedView()
zwraca obecnie wybraną kartę. W tym przypadku metodaisSelected()
zwraca wartość true.
Jeśli animujesz widok karty lub wykonujesz inne kosztowne operacje, uruchom i zatrzymaj operacje w onAttachedToWindow()
i onDetachedToWindow()
, aby zaoszczędzić zasoby.
Recykling karty
Gdy karta zostanie podłączona do odłączonej, karty z nią powiązane mogą zostać wykorzystane ponownie lub użyte przez dołączoną kartę. Recykling widoków ze zaktualizowanymi informacjami jest znacznie skuteczniejszy niż tworzenie nowych widoków.
Aby skorzystać z recyklingu kart, zaimplementuj metody getItemViewType()
, getViewTypeCount()
i getView()
klasy
CardScrollAdapter
. Następnie możesz skorzystać z niektórych metod komfortowych w klasie CardBuilder
, aby wdrożyć recykling w urządzeniu CardScrollAdapter
, jak w tym przykładzie:
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);
}
Implementowanie stabilnych identyfikatorów kart
Po wybraniu karty, która ma być wyświetlana użytkownikom, możesz nie chcieć zmieniać bazowego adaptera, aby mieć wpływ na kartę wyświetlaną użytkownikom w tej chwili. Jeśli na przykład użytkownik wyświetla wybraną kartę, a jej karta jest usuwana po lewej stronie, karta może zostać przeniesiona do lewej strony, ponieważ w momencie wystąpienia zmian identyfikator CardScrollAdapter
ponownie przypisze identyfikatory do bazowego zbioru danych.
Jeśli w logicznie sensowny sposób przypisujesz unikalnym identyfikatorom karty, możesz utrzymywać spójny identyfikator w podstawowym zbiorze danych, aby zapobiec powyższemu problemowi.
Aby to zrobić, zastąp hasStableIds()
i ustaw true
. Określa to, że system CardScrollAdapter
utrzymuje stabilne identyfikatory w zmianach zbioru danych. Dodatkowo zaimplementuj getItemId()
, aby zwracał odpowiedni unikalny identyfikator kart w adaptera.
Domyślna implementacja zwraca indeks pozycji karty w adapterze, który z natury jest niestabilny.
Pusty komponent CardAdapterAdapter
Jeśli masz puste zbiory danych do adapterów, domyślnym widokiem jest czarny ekran. Jeśli w tych przypadkach chcesz wyświetlić inny widok, nie używaj setEmptyView()
.
Zamiast tego utwórz jedną kartę w CardScrollAdapter
.
Opinia o przeciąganiu w poziomie
Wiele wbudowanych w Google Glass umożliwia korzystanie z funkcji „przeciągania” podczas przesuwania do tyłu i do przodu. Możesz na przykład zobaczyć ten komentarz po przesunięciu zdjęcia.
Jeśli zanurzenie w poziomie nie obsługuje gestów przesuwania w poziomie w celu wykonywania funkcji specyficznych dla aplikacji, dodaj efekt w formie komponentu CardScrollView
, który zawiera jedną kartę.
Skopiuj do projektu tę klasę pomocniczą:
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; } } }
Zmień metodę
onCreate
w swojej aktywności, aby wyświetlićCardScrollView
, który zawiera Twój układ.@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // was: setContentView(R.layout.main_activity); setContentView(new TuggableView(this, R.layout.main_activity)); }