Con Glass, puedes crear interacciones enriquecidas con tus tarjetas, como el desplazamiento y animaciones.
Tarjetas con desplazamiento en actividades
La pantalla y el panel táctil de Glass son ideales para mostrar tarjetas deslizables,
como en la línea de tiempo de Glass. Si estás creando una actividad, puedes crear
el mismo tipo de efecto con la
CardScrollView
widget.
- Implementa un
CardScrollAdapter
para suministrarles tarjetasCardScrollView
Puedes compilar una jerarquía de vistas estándar por tu cuenta o usar laCardBuilder
. - Crea un
CardScrollView
que utiliza elCardScrollAdapter
como proveedor de tarjetas. - Configura la vista de contenido de tu actividad como la
CardScrollView
o mostrar laCardScrollView
en un diseño.
Esta es una implementación simple que permite desplazarse por tres tarjetas:
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);
}
}
}
Interacción con tarjetas desplazables
Desde
CardScrollView
extiende AdapterView
puedes implementar los objetos de escucha estándar de Android.
- Llama a la infraestructura heredada
setOnItemClickListener()
en tuCardScrollView
. - Implementa un
onItemClick()
para el evento de toque.
Esta es una extensión del ejemplo anterior que reproduce un sonido de toque cuando presionas una tarjeta:
@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);
}
});
}
Cómo animar tarjetas de desplazamiento
Hay tres animaciones disponibles para las tarjetas de desplazamiento: Navegación, Inserción y Eliminación.
- Implementa una acción de insertar o borrar en una tarjeta en una posición especificada del conjunto de tarjetas.
- Llamada
animate()
y usa un valor de la enumCardScrollView.Animation
. Para mostrar una animación más fluida, quita las referencias a
notifyDataSetChanged()
Laanimate()
controla la actualización de la vista de conjuntos de datos.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); }
Sugerencias de implementación y rendimiento para las tarjetas desplazables
Ten en cuenta las siguientes implicaciones de diseño y rendimiento cuando crees manuscritos de tarjetas.
Ciclo de vida de la tarjeta
Para aumentar el rendimiento, una CardScrollView
solo carga un subconjunto de las tarjetas que se
CardScrollAdapter
proporciona (en general, los que son visibles para el usuario y algunos más).
Debido a esto, una tarjeta puede estar en cualquiera de estos cuatro estados generales:
- Desconectada: La vista de desplazamiento de la tarjeta no necesita esta tarjeta en este momento.
Recibirás una notificación del
onDetachedToWindow()
de la tarjeta si una tarjeta se adjuntó y, luego, se desvinculó. - Attached: La vista de desplazamiento de tarjetas solicita la tarjeta del adaptador con
getView()
, porque la tarjeta está a punto de "activarse" Cuando eso suceda, el métodoonAttachedToWindow()
de la tarjeta te notificará. - Activada: La tarjeta es parcialmente visible para el usuario, pero se desplaza la tarjeta.
vista no se ha "seleccionado" la tarjeta que se mostrará al usuario. El
Método 'isActivated()'
muestra
true
en este caso. - Seleccionada: La tarjeta está ocupando el nombre del usuario.
en toda la pantalla. Si llamas a
getSelectedView()
, se mostrará la tarjeta seleccionada actualmente. El métodoisSelected()
muestra true en este caso.
Si quieres animar la vista de tu tarjeta o
realizar otras operaciones costosas,
iniciar y detener las operaciones en
onAttachedToWindow()
y
onDetachedToWindow()
para ahorrar recursos.
Reciclaje de tarjetas
Cuando una tarjeta pasa de estar conectada a desconectada, el objeto View asociado la tarjeta se puede reciclar y usar con una tarjeta que se va a adjuntar. Reciclar vistas con información actualizada es mucho más eficiente que creando nuevas vistas.
Para aprovechar el reciclaje de tarjetas, implementa el
getItemViewType()
:
getViewTypeCount()
,
y getView()
métodos del
CardScrollAdapter
. Luego, puedes usar algunos de los métodos prácticos en CardBuilder
.
para implementar el reciclaje en tu CardScrollAdapter
,
como en el siguiente ejemplo:
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);
}
Cómo implementar IDs de tarjetas estables
Cuando se selecciona una tarjeta y se muestra a los usuarios, es posible que no
Si quieres que los cambios en el adaptador subyacente afecten la tarjeta que ven los usuarios
en ese momento. Por ejemplo, si un usuario está viendo una tarjeta seleccionada y una
se quita a la izquierda de esa tarjeta, la tarjeta a la que
que está viendo se puede desplazar hacia la izquierda
CardScrollAdapter
reasigna los IDs al conjunto de datos subyacente cuando se producen cambios, de forma predeterminada.
Si, lógicamente, tiene sentido asignar IDs únicos a tus tarjetas, puedes mantener
un ID coherente en el conjunto de datos subyacente para evitar el problema antes mencionado.
Para ello, anula
hasStableIds()
y muestra true
. Esto le especifica al sistema que
CardScrollAdapter
mantiene IDs estables en los cambios
de los conjuntos de datos. Además, implementa
getItemId()
para mostrar el ID único apropiado para las tarjetas en tu adaptador.
La implementación predeterminada muestra el índice de posición de la tarjeta en el adaptador.
lo que es inherentemente inestable.
CardSlideAdapter vacío
Cuando tienes un conjunto de datos vacío para los adaptadores, la vista predeterminada muestra
una pantalla negra. Si quieres mostrar una vista diferente en estos casos,
No uses setEmptyView()
.
En su lugar, crea una sola tarjeta en tu CardScrollAdapter
.
Respuesta de arrastre horizontal
Muchas de las inmersiones integradas en Glass permiten hacer "tirar" comentarios al deslizar hacia atrás y hacia adelante no realizan ninguna acción. Por ejemplo, puedes ver este feedback cuando deslizar después de tomar una foto.
Si tu inmersión no usa gestos de deslizamiento horizontal para realizar
específicas de la aplicación, proporciona este efecto de ajuste con la unión de
dentro de un
CardScrollView
que contiene una tarjeta.
Copia la siguiente clase auxiliar en tu proyecto:
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; } } }
Modifica el método
onCreate
en tu actividad para mostrar elCardScrollView
que contiene tu diseño.@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // was: setContentView(R.layout.main_activity); setContentView(new TuggableView(this, R.layout.main_activity)); }