Ce document explique comment suivre le style de Google Glass. et implémenter les bonnes pratiques courantes pour l'interface utilisateur lors de l'utilisation du GDK.
Thème Glass
Google Glass applique un thème standard à votre appareil. reste cohérent avec le reste de l'interface utilisateur. La a les caractéristiques suivantes:
- Utilise la police de caractères Roboto
- Affiche les activités en plein écran sans barre d'état ni barre d'action.
- S'applique à un arrière-plan uni noir
Pour appliquer le thème Glass, ne déclarez pas de thème dans votre fichier manifeste Android.
Si vous disposez d'un style personnalisé pour certaines parties de vos lunettes Glassware
et souhaitez utiliser le thème Google Glass par défaut pour tout le reste,
hériter de Theme.DeviceDefault
avec l'attribut parent
:
<resources>
<style name="CustomTheme" parent="@android:style/Theme.DeviceDefault">
<!-- Theme customization goes here. -->
</style>
</resources>
Consultez le guide du développeur Android sur Styles et thèmes pour en savoir plus sur la création de thèmes.
Cartes en verre
CardBuilder
crée des cartes bien formées sur la base d'un ensemble de propriétés. Utiliser les mises en page
fourni par CardBuilder.Layout
autant que possible pour que votre contenu ressemble à celui d'autres contenus sur
Verre.
Pour utiliser CardBuilder
:
- Créez une instance de
CardBuilder
en lui attribuant la mise en page souhaitée à partir deCardBuilder.Layout
- Définissez les propriétés de la carte, telles que le texte, la note de bas de page et le code temporel.
- Appeler
CardBuilder.getView()
la convertir en carte AndroidView
ouCardBuilder.getRemoteViews()
pour la convertir enRemoteViews
. - Utilisez le
View
dans vos activités, vos mises en page ou dans unCardScrollView
, ou utilisez lesRemoteViews
dans uneLiveCard
.
Fonctionnalités courantes de l'interface utilisateur
De nombreuses mises en page fournies par CardBuilder
sont compatibles avec l'interface utilisateur courante
les fonctionnalités décrites ci-dessous. Consultez la documentation des mises en page individuelles dans
CardBuilder.Layout
pour obtenir la liste des fonctionnalités compatibles avec chaque type de fiche.
Icône d'attribution
L'icône d'attribution est une icône facultative de 36 × 36 pixels qui apparaît sur
en bas à droite d'une fiche
et à droite de l'horodatage. Définir
en appelant
CardBuilder.setAttributionIcon()
pour identifier votre application, en particulier sur les cartes actives, afin qu'un utilisateur puisse rapidement
jetez un coup d’œil et voyez la source
des informations sur cette carte.
Indicateur de pile
L'indicateur de pile, contrôlé par
CardBuilder.showStackIndicator()
,
est un pli d’angle qui apparaît dans le coin supérieur droit d’une carte. Utiliser en tant que
un indicateur visuel indiquant que votre carte représente un groupe d'autres cartes
l'utilisateur peut exploiter directement.
View view = new CardBuilder(context, CardBuilder.Layout.TEXT)
.setText("A stack indicator can be added to the corner of a card...")
.setAttributionIcon(R.drawable.ic_smile)
.showStackIndicator(true)
.getView();
Mises en page
Les exemples suivants illustrent les mises en page disponibles avec les
CardBuilder
TEXT
et TEXT_FIXED
CardBuilder.Layout.TEXT
affiche du texte à fond perdu avec
avec une mosaïque d'images en arrière-plan. Le texte est redimensionné de façon dynamique pour s'adapter au mieux
l'espace disponible.
CardBuilder.Layout.TEXT_FIXED
est similaire, mais fixe son texte à une taille plus petite.
View view1 = new CardBuilder(context, CardBuilder.Layout.TEXT)
.setText("This is the TEXT layout. The text size will adjust dynamically.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.getView();
View view2 = new CardBuilder(context, CardBuilder.Layout.TEXT)
.setText("You can also add images to the background of a TEXT card.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.addImage(R.drawable.image1)
.addImage(R.drawable.image2)
.addImage(R.drawable.image3)
.addImage(R.drawable.image4)
.addImage(R.drawable.image5)
.getView();
View view3 = new CardBuilder(context, CardBuilder.Layout.TEXT_FIXED)
.setText("This is the TEXT_FIXED layout. The text size is always the same.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.getView();
COLUMNS
et COLUMNS_FIXED
La
CardBuilder.Layout.COLUMNS
affiche une mosaïque d'images ou une icône sur la
du côté gauche de la carte et
du texte sur le côté droit. La taille du texte est dynamique
pour s'adapter au mieux
à l'espace disponible. Pour que la taille du texte reste fixe, utilisez
CardBuilder.Layout.COLUMNS_FIXED
View view1 = new CardBuilder(context, CardBuilder.Layout.COLUMNS)
.setText("This is the COLUMNS layout with dynamic text.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.addImage(R.drawable.image1)
.addImage(R.drawable.image2)
.addImage(R.drawable.image3)
.addImage(R.drawable.image4)
.addImage(R.drawable.image5)
.getView();
View view2 = new CardBuilder(context, CardBuilder.Layout.COLUMNS)
.setText("You can even put a centered icon on a COLUMNS card instead of a mosaic.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.setIcon(R.drawable.ic_wifi)
.getView();
View view3 = new CardBuilder(context, CardBuilder.Layout.COLUMNS_FIXED)
.setText("This is the COLUMNS_FIXED layout. The text size is always the same.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.addImage(R.drawable.image1)
.addImage(R.drawable.image2)
.addImage(R.drawable.image3)
.addImage(R.drawable.image4)
.addImage(R.drawable.image5)
.getView();
CAPTION
La
CardBuilder.Layout.CAPTION
La mise en page comporte une mosaïque d'images en arrière-plan.
et un bref texte de légende
alignés au bas de la fiche. Une icône peut également être
placé à côté d'une légende pour représenter, par exemple, l'identité d'une personne
associées au contenu de la fiche.
View view1 = new CardBuilder(context, CardBuilder.Layout.CAPTION)
.setText("The caption layout.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.addImage(R.drawable.beach)
.setAttributionIcon(R.drawable.ic_smile)
.getView();
View view2 = new CardBuilder(context, CardBuilder.Layout.CAPTION)
.setText("The caption layout with an icon.")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.addImage(R.drawable.beach)
.setIcon(R.drawable.ic_avatar)
.setAttributionIcon(R.drawable.ic_smile)
.getView();
TITLE
La
CardBuilder.Layout.TITLE
La mise en page comporte une mosaïque d'images en arrière-plan.
avec un titre centré et une icône facultative en bas de la fiche. Cette mise en page
est souvent utilisé pour représenter des contacts ou des cibles de partage. La note de bas de page et le code temporel
non compatible avec cette mise en page.
View view = new CardBuilder(context, CardBuilder.Layout.TITLE)
.setText("TITLE Card")
.setIcon(R.drawable.ic_phone)
.addImage(R.drawable.beach)
.getView();
AUTHOR
Utilisez les
CardBuilder.Layout.AUTHOR
mise en page pour afficher un message ou une conversation
en mettant l'accent sur l'auteur. Il prend en charge une mosaïque
d'images en arrière-plan,
une icône utilisée comme avatar de l'auteur, et un titre et un sous-titre où vous pouvez
de lister les
informations d'identification.
View view = new CardBuilder(context, CardBuilder.Layout.AUTHOR)
.setText("The AUTHOR layout lets you display a message or conversation "
+ " with a focus on the author.")
.setIcon(R.drawable.ic_avatar)
.setHeading("Joe Lastname")
.setSubheading("Mountain View, California")
.setFootnote("This is the footnote")
.setTimestamp("just now")
.getView();
MENU
La
CardBuilder.Layout.MENU
qui ressemble à un menu
Glass standard. Il comporte une
une icône et un titre centrés et une note de bas de page facultative. Utilisez cette mise en page pour
écrans de confirmation (passage de "Suppression" à "Supprimé" une fois que l'utilisateur
sélectionne un élément de menu, par exemple). Si vous avez besoin d'un vrai menu, vous devez utiliser un
le menu d'options standard à la place.
View view = new CardBuilder(context, CardBuilder.Layout.MENU)
.setText("MENU layout")
.setIcon(R.drawable.ic_phone)
.setFootnote("Optional menu description")
.getView();
EMBED_INSIDE
La
CardBuilder.Layout.EMBED_INSIDE
La mise en page intègre un code XML de mise en page personnalisé de votre propre conception dans l'application Glass standard.
modèle de fiche. Cela vous permet de concevoir une UI personnalisée pour votre application,
placer correctement la note de bas de page, l'horodatage, l'icône d'attribution et
de pile s'ils sont nécessaires.
Après l'appel
CardBuilder.getView()
,
utiliser
findViewById()
du résultat pour accéder aux vues de votre mise en page intégrée. De même, si vous
appel
CardBuilder.getRemoteViews()
,
vous pouvez manipuler les vues de votre mise en page intégrée en transmettant leurs ID directement
dans le
RemoteViews
méthodes setter.
View view = new CardBuilder(context, CardBuilder.Layout.EMBED_INSIDE)
.setEmbeddedLayout(R.layout.food_table)
.setFootnote("Foods you tracked")
.setTimestamp("today")
.getView();
TextView textView1 = (TextView) view.findViewById(R.id.text_view_1);
textView1.setText("Water");
// ...and so on
Pour un exemple plus détaillé, consultez la documentation Projet ApiDemo.
ALERT
La
CardBuilder.Layout.ALERT
contient une grande icône centrée avec un
message principal et note de bas de page. Utilisez cette mise en page dans une
Dialog
jusqu'à
afficher un message d'information important, un avertissement ou une erreur dans votre appareil Glassware.
L'exemple suivant montre une implémentation de AlertDialog
et ignore le
et ouvre les paramètres Wi-Fi lorsque l'utilisateur appuie dessus:
- Créez une classe qui étend
Dialog
. - Créez la fiche à l'aide de
CardBuilder
avec la mise en pageCardBuilder.Layout.ALERT
, puis définissez la vue de contenu avec cette fiche. (Facultatif) Créez un
GestureDetector
pour gérer les gestes des utilisateurs sur cette carte.public class AlertDialog extends Dialog { private final DialogInterface.OnClickListener mOnClickListener; private final AudioManager mAudioManager; private final GestureDetector mGestureDetector; /** * Handles the tap gesture to call the dialog's * onClickListener if one is provided. */ private final GestureDetector.BaseListener mBaseListener = new GestureDetector.BaseListener() { @Override public boolean onGesture(Gesture gesture) { if (gesture == Gesture.TAP) { mAudioManager.playSoundEffect(Sounds.TAP); if (mOnClickListener != null) { // Since Glass dialogs do not have buttons, // the index passed to onClick is always 0. mOnClickListener.onClick(AlertDialog.this, 0); } return true; } return false; } }; public AlertDialog(Context context, int iconResId, int textResId, int footnoteResId, DialogInterface.OnClickListener onClickListener) { super(context); mOnClickListener = onClickListener; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mGestureDetector = new GestureDetector(context).setBaseListener(mBaseListener); setContentView(new CardBuilder(context, CardBuilder.Layout.ALERT) .setIcon(iconResId) .setText(textResId) .setFootnote(footnoteResId) .getView()); } /** Overridden to let the gesture detector handle a possible tap event. */ @Override public boolean onGenericMotionEvent(MotionEvent event) { return mGestureDetector.onMotionEvent(event) || super.onGenericMotionEvent(event); } }
(Facultatif) Dans votre activité, implémentez une
OnClickListener
pour gérer tout flux supplémentaire lorsque l'utilisateur appuie dessus. Pour en savoir plus sur des activités de paramétrage telles que le Wi-Fi, consultez Paramètres de démarrageAppelez le constructeur
AlertDialog
pour afficher la fiche d'alerte.public class MyActivity extends Activity { ... private final DialogInterface.OnClickListener mOnClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int button) { // Open WiFi Settings startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); } }; @Override protected void onCreate(Bundle bundle) { ... new AlertDialog(context, R.drawable.ic_cloud_sad_150, R.string.alert_text, R.string.alert_footnote_text, mOnClickListener).show(); ... } }
Mises en page XML
Voici deux mises en page de cartes de base que vous pouvez utiliser si la classe CardBuilder le fait ne répondent pas à vos besoins.
Mise en page principale
Cette mise en page définit la marge intérieure et le pied de page standards d'une fiche. Mettez la vôtre
vues dans le champ RelativeLayout
vide.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:id="@+id/body_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/glass_card_body_height"
android:layout_marginLeft="@dimen/glass_card_margin"
android:layout_marginTop="@dimen/glass_card_margin"
android:layout_marginRight="@dimen/glass_card_margin"
tools:ignore="UselessLeaf"
>
<!-- Put your widgets inside this RelativeLayout. -->
</RelativeLayout>
<LinearLayout
android:id="@+id/footer_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_marginLeft="@dimen/glass_card_margin"
android:layout_marginBottom="@dimen/glass_card_footer_margin"
android:layout_marginRight="@dimen/glass_card_margin"
android:orientation="horizontal"
>
<!-- The footer view will grow to fit as much content as possible while the
timestamp view keeps a fixed width. If the footer text is too long, it
will be ellipsized with a 40px margin between it and the timestamp. -->
<TextView
android:id="@+id/footer"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/glass_card_margin"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
</LinearLayout>
</FrameLayout>
Disposition en colonnes de gauche
Ce champ définit une colonne de gauche de 240 pixels et une colonne de droite de 400 pixels sous la forme de deux éléments RelativeLayout
.
dans lesquels vous pouvez
mettre votre point de vue.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:id="@+id/left_column"
android:layout_width="@dimen/glass_card_left_column_width"
android:layout_height="match_parent"
>
<!-- Put widgets for the left column inside this RelativeLayout. -->
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/glass_card_body_height"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/glass_card_two_column_margin"
android:layout_marginRight="@dimen/glass_card_margin"
android:layout_marginTop="@dimen/glass_card_margin"
android:layout_toRightOf="@+id/left_column"
tools:ignore="UselessLeaf"
>
<!-- Put widgets for the right column inside this RelativeLayout. -->
</RelativeLayout>
<LinearLayout
android:id="@+id/footer_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_gravity="bottom|left"
android:layout_marginBottom="@dimen/glass_card_footer_margin"
android:layout_marginLeft="@dimen/glass_card_two_column_margin"
android:layout_marginRight="@dimen/glass_card_margin"
android:layout_toRightOf="@+id/left_column"
android:orientation="horizontal"
>
<!--
The footer view will grow to fit as much content as possible while the
timestamp view keeps a fixed width. If the footer text is too long, it
will be ellipsized with a 40px margin between it and the timestamp.
-->
<TextView
android:id="@+id/footer"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/glass_card_margin"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
</LinearLayout>
</RelativeLayout>
Dimensions standards
Utilisez ce fichier conjointement avec les mises en page précédentes ou vos propres mises en page pour
pour respecter le style d'affichage standard. Créer ce fichier en tant que
res/values/dimens.xml
dans votre projet Android.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- The recommended margin for the top, left, and right edges of a card. -->
<dimen name="glass_card_margin">40px</dimen>
<!-- The recommended margin between the bottom of the card and the footer. This is
an adjusted value so that the baseline of the text in the footer sits 40px
from the bottom of the card, matching the other margins. -->
<dimen name="glass_card_footer_margin">33px</dimen>
<!-- The recommended margin for the left column of the two-column card. -->
<dimen name="glass_card_two_column_margin">30px</dimen>
<!-- The maximum height of the body content inside a card. -->
<dimen name="glass_card_body_height">240px</dimen>
<!-- The width of the left column in the two-column layout. -->
<dimen name="glass_card_left_column_width">240px</dimen>
</resources>