Conception de cartes

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 :

  1. Créez une instance de CardBuilder en lui attribuant la mise en page souhaitée à partir de CardBuilder.Layout
  2. Définissez les propriétés de la carte, telles que le texte, la note de bas de page et le code temporel.
  3. Appeler CardBuilder.getView() la convertir en carte Android View ou CardBuilder.getRemoteViews() pour la convertir en RemoteViews .
  4. Utilisez le View dans vos activités, vos mises en page ou dans un CardScrollView, ou utilisez les RemoteViews dans une LiveCard.

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.

<ph type="x-smartling-placeholder">
</ph>
Figure 1: (image de fond créée par photoeverywhere.co.uk, recadrée)
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();

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:

  1. Créez une classe qui étend Dialog.
  2. Créez la fiche à l'aide de CardBuilder avec la mise en page CardBuilder.Layout.ALERT, puis définissez la vue de contenu avec cette fiche.
  3. (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);
        }
    }
    
  4. (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émarrage

  5. Appelez 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>