In diesem Dokument erfahren Sie, wie Sie den Glass-Stil befolgen und gängige Best Practices für die Benutzeroberfläche bei der Verwendung des GDK implementieren.
Glasdesign
Glass wendet ein Standarddesign auf Ihre Glassware an, das zur Benutzeroberfläche passt. Das Thema hat die folgenden Eigenschaften:
- Verwendet die Roboto-Schriftart
- Aktivitäten werden im Vollbildmodus ohne Statusleiste oder Aktionsleiste angezeigt.
- Einfarbiger, schwarzer Hintergrund
Deklarieren Sie in Ihrem Android-Manifest kein Design, um das Glass-Design anzuwenden.
Wenn du für Teile deiner Glassware einen benutzerdefinierten Stil hast und für alles andere das standardmäßige Glass-Design verwenden möchtest, kannst du den Stil von Theme.DeviceDefault
mit dem Attribut parent
übernehmen:
<resources>
<style name="CustomTheme" parent="@android:style/Theme.DeviceDefault">
<!-- Theme customization goes here. -->
</style>
</resources>
Weitere Informationen zum Erstellen von Designs findest du im Android-Entwicklerleitfaden zu Stilen und Designs.
Karten im Glasstil
Mit der Klasse CardBuilder
werden korrekt formatierte Karten anhand einer Reihe von Attributen erstellt. Verwende nach Möglichkeit die von CardBuilder.Layout
bereitgestellten Layouts, damit deine Inhalte wie andere Inhalte in Glass aussehen und sich anfühlen.
Gehe so vor, wenn du CardBuilder
verwenden möchtest:
- Erstellen Sie eine Instanz von
CardBuilder
und verwenden Sie dabei das gewünschte Layout ausCardBuilder.Layout
. - Legen Sie Eigenschaften der Karte wie den Text, die Fußnote und den Zeitstempel fest.
- Rufen Sie
CardBuilder.getView()
auf, um die Karte in ein Android-View
-Objekt zu konvertieren, oderCardBuilder.getRemoteViews()
, um sie in einRemoteViews
-Objekt zu konvertieren. - Verwende
View
in deinen Aktivitäten, Layouts oder in einemCardScrollView
oder dasRemoteViews
in einemLiveCard
.
Allgemeine UI-Funktionen
Viele der von CardBuilder
bereitgestellten Layouts unterstützen die unten beschriebenen allgemeinen Funktionen der Benutzeroberfläche. In der Dokumentation der einzelnen Layouts in CardBuilder.Layout
findest du eine Liste der Funktionen, die von den einzelnen Kartentypen unterstützt werden.
Attributionssymbol
Das Attributionssymbol ist ein optionales 36 × 36-Pixel-Symbol, das in der unteren rechten Ecke einer Karte und rechts vom Zeitstempel angezeigt wird. Du kannst dieses Symbol festlegen, indem du CardBuilder.setAttributionIcon()
aufrufst, um deine Anwendung zu identifizieren. Das gilt insbesondere für Livekarten, damit Nutzer schnell die Quelle der Informationen auf dieser Karte sehen können.
Stack-Anzeige
Der von CardBuilder.showStackIndicator()
gesteuerte Stapelanzeige ist eine umklappbare Ecke, die oben rechts auf einer Karte angezeigt wird. Dies ist ein visueller Indikator dafür, dass die Karte ein Set anderer Karten darstellt, auf die der Nutzer direkt tippen kann.
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();
Layouts
Die folgenden Beispiele zeigen die Layouts, die mit CardBuilder
verfügbar sind.
TEXT
und TEXT_FIXED
Das Layout CardBuilder.Layout.TEXT
zeigt randlosen Text mit einem optionalen Bildmosaik im Hintergrund. Die Größe des Textes wird dynamisch an den verfügbaren Platz angepasst.
CardBuilder.Layout.TEXT_FIXED
ist ähnlich, legt aber den Text in einer kleineren Größe fest.
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
und COLUMNS_FIXED
Das Layout CardBuilder.Layout.COLUMNS
zeigt ein Bildmosaik oder Symbol auf der linken Seite der Karte und Text auf der rechten Seite. Die Größe des Textes wird dynamisch
an den verfügbaren Platz angepasst. Wenn die Textgröße unveränderlich bleiben soll, verwenden Sie 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
Beim Layout CardBuilder.Layout.CAPTION
befindet sich im Hintergrund ein Bildmosaik und am unteren Rand der Karte ist ein kurzer Untertiteltext ausgerichtet. Außerdem kann neben dem Untertitel ein Symbol platziert werden, um beispielsweise die Identität einer Person darzustellen, die mit dem Inhalt der Karte verknüpft ist.
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
Beim Layout CardBuilder.Layout.TITLE
befindet sich im Hintergrund ein Bildmosaik mit einem zentrierten Titel und einem optionalen Symbol am unteren Rand der Karte. Dieses Layout wird häufig verwendet, um Kontakte darzustellen oder Ziele zu teilen. Fußnoten und Zeitstempel werden bei diesem Layout nicht unterstützt.
View view = new CardBuilder(context, CardBuilder.Layout.TITLE)
.setText("TITLE Card")
.setIcon(R.drawable.ic_phone)
.addImage(R.drawable.beach)
.getView();
AUTHOR
Mit dem CardBuilder.Layout.AUTHOR
-Layout können Sie eine Nachricht oder Unterhaltung anzeigen lassen, bei der der Fokus auf dem Autor liegt. Im Hintergrund werden ein Bildmosaik, ein Symbol als Avatar des Autors sowie eine Überschrift und Zwischenüberschrift für Informationen zur Identifizierung unterstützt.
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
Das CardBuilder.Layout.MENU
-Layout sieht aus wie ein standardmäßiges Glass-Menü. Es hat ein zentriertes Symbol, einen Titel und eine optionale Fußnote. Verwenden Sie dieses Layout für Bestätigungsbildschirme (z. B. Wechsel von "Löschen" zu "Gelöscht", nachdem der Nutzer einen Menüpunkt ausgewählt hat). Wenn Sie ein echtes Menü benötigen, sollten Sie stattdessen ein Standardoptionsmenü verwenden.
View view = new CardBuilder(context, CardBuilder.Layout.MENU)
.setText("MENU layout")
.setIcon(R.drawable.ic_phone)
.setFootnote("Optional menu description")
.getView();
EMBED_INSIDE
Mit dem CardBuilder.Layout.EMBED_INSIDE
-Layout wird eine XML-Datei mit benutzerdefiniertem Layout deines eigenen Designs in die standardmäßige Glass-Kartenvorlage eingebettet. Auf diese Weise können Sie eine benutzerdefinierte UI für Ihre Anwendung entwerfen, aber bei Bedarf die Fußnote, den Zeitstempel, das Zuordnungssymbol und den Stapel-Indikator einer Karte korrekt platzieren.
Nachdem Sie CardBuilder.getView()
aufgerufen haben, verwenden Sie findViewById()
für das Ergebnis, um auf die Ansichten innerhalb des eingebetteten Layouts zuzugreifen. Wenn Sie CardBuilder.getRemoteViews()
aufrufen, können Sie die Ansichten des eingebetteten Layouts ändern, indem Sie die IDs direkt an die RemoteViews
-Setter-Methoden übergeben.
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
Ein detaillierteres Beispiel findest du im ApiDemo-Projekt auf GitHub.
ALERT
Das CardBuilder.Layout.ALERT
-Layout enthält ein großes zentriertes Symbol mit einer primären Botschaft und einer Fußnote. Mit diesem Layout in einer Dialog
kannst du wichtige Informationen, Warnungen oder Fehler in deiner Glassware anzeigen.
Das folgende Beispiel zeigt eine Implementierung von AlertDialog
. Die Karte wird geschlossen und die WLAN-Einstellungen werden geöffnet, wenn der Nutzer auf die Karte tippt:
- Erstellen Sie eine Klasse, die
Dialog
erweitert. - Erstelle die Karte mit
CardBuilder
mit dem Layout „CardBuilder.Layout.ALERT
“ und lege dann die Inhaltsansicht mit dieser Karte fest. Optional: Erstellen Sie einen
GestureDetector
für Nutzergesten auf dieser Karte.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); } }
(Optional) Implementieren Sie in Ihrer Aktivität eine
OnClickListener
, um zusätzliche Abläufe zu verarbeiten, wenn der Nutzer auf die Anzeige tippt. Weitere Informationen dazu, wie Sie Einstellungen wie WLAN starten, finden Sie unter Starteinstellungen.Rufen Sie den
AlertDialog
-Konstruktor auf, um die Benachrichtigungskarte aufzurufen.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(); ... } }
XML-Layouts
Hier sind zwei grundlegende Kartenlayouts, die Sie verwenden können, wenn die CardBuilder-Klasse Ihre Anforderungen nicht erfüllt.
Hauptlayout
Mit diesem Layout wird der Standardabstand und die Fußzeile für eine Karte festgelegt. Geben Sie Ihre eigenen Ansichten in das leere RelativeLayout
ein.
<?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>
Layout der linken Spalte
Damit wird eine 240 Pixel große linke und eine 400 Pixel recht große Spalte in Form von zwei RelativeLayout
definiert, in die Sie Ihre Ansichten einfügen können.
<?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>
Standarddimensionen
Verwenden Sie diese Datei in Verbindung mit den vorherigen Layouts oder Ihren eigenen Layouts, um dem Standard Glass-Stil zu entsprechen. Erstellen Sie diese Datei als res/values/dimens.xml
in Ihrem Android-Projekt.
<?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>