Dokumen ini membahas cara mengikuti gaya Glass dan menerapkan praktik terbaik UI umum saat menggunakan GDK.
Tema kaca
Glass menerapkan tema standar ke Glassware Anda, sehingga akan tetap konsisten dengan antarmuka pengguna lainnya. Tema memiliki karakteristik berikut:
- Menggunakan jenis huruf Roboto
- Menampilkan aktivitas layar penuh tanpa status bar atau panel tindakan
- Menerapkan latar belakang hitam dan solid
Untuk menerapkan tema Glass, jangan deklarasikan tema di Manifes Android Anda.
Jika Anda memiliki gaya kustom untuk bagian dari Glassware
dan ingin tema Glass default untuk lainnya,
warisi dari Theme.DeviceDefault
dengan atribut parent
:
<resources>
<style name="CustomTheme" parent="@android:style/Theme.DeviceDefault">
<!-- Theme customization goes here. -->
</style>
</resources>
Lihat panduan developer Android tentang Gaya dan Tema untuk mengetahui informasi selengkapnya tentang cara membuat tema.
Kartu bergaya kaca
Class CardBuilder
membuat kartu yang diformat dengan baik berdasarkan kumpulan properti. Gunakan tata letak
yang disediakan oleh CardBuilder.Layout
jika memungkinkan sehingga konten Anda terlihat dan terasa seperti konten lain di
Kacamata.
Untuk menggunakan CardBuilder
:
- Buat instance
CardBuilder
, dengan tata letak yang diinginkan dariCardBuilder.Layout
. - Tetapkan properti kartu, seperti teks, catatan kaki, dan stempel waktu.
- Panggil
CardBuilder.getView()
untuk mengonversi kartu ke AndroidView
, atauCardBuilder.getRemoteViews()
untuk mengonversinya menjadi objekRemoteViews
. - Gunakan
View
di aktivitas, tata letak, atau diCardScrollView
, atau gunakanRemoteViews
diLiveCard
.
Fitur UI umum
Banyak tata letak yang disediakan oleh CardBuilder
mendukung fitur antarmuka pengguna
umum yang dijelaskan di bawah ini. Lihat dokumentasi setiap tata letak di
CardBuilder.Layout
untuk mengetahui daftar fitur yang didukung oleh setiap jenis kartu.
Ikon atribusi
Ikon atribusi adalah ikon opsional 36 × 36 piksel yang muncul di
sudut kanan bawah kartu dan di sebelah kanan stempel waktu. Tetapkan ikon
ini dengan memanggil
CardBuilder.setAttributionIcon()
untuk mengidentifikasi aplikasi Anda, terutama pada kartu live sehingga pengguna dapat dengan cepat
melihat sekilas dan melihat sumber informasi pada kartu tersebut.
Indikator tumpukan
Indikator stack, yang dikontrol oleh
CardBuilder.showStackIndicator()
,
adalah lipatan sudut yang muncul di pojok kanan atas kartu. Gunakan ini sebagai
indikator visual bahwa kartu Anda mewakili paket kartu lain yang
dapat diketuk langsung oleh pengguna.
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();
Tata letak
Contoh berikut menunjukkan tata letak yang tersedia menggunakan
CardBuilder
.
TEXT
dan TEXT_FIXED
Tata letak CardBuilder.Layout.TEXT
menampilkan teks full-bleed dengan mosaik
gambar opsional di latar belakang. Ukuran teks berubah secara dinamis agar sesuai
dengan ruang yang tersedia.
CardBuilder.Layout.TEXT_FIXED
mirip tetapi memperbaiki teksnya ke ukuran yang lebih kecil.
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
dan COLUMNS_FIXED
Tata letak
CardBuilder.Layout.COLUMNS
menampilkan mosaik atau ikon gambar di
sisi kiri kartu dan teks di sisi kanan. Teks diubah ukurannya secara dinamis
agar sesuai dengan ruang yang tersedia. Agar ukuran teks tetap sama, gunakan
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
Tata letak CardBuilder.Layout.CAPTION
memiliki mosaik gambar di latar belakang dan teks singkat yang diratakan di bagian bawah kartu. Ikon juga dapat ditempatkan di samping teks untuk mewakili, misalnya, identitas orang yang terkait dengan konten kartu.
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
Tata letak
CardBuilder.Layout.TITLE
memiliki mosaik gambar di latar belakang
dengan judul di tengah dan ikon opsional di bagian bawah kartu. Tata letak ini
sering digunakan untuk mewakili kontak atau target berbagi. Catatan kaki dan stempel waktu
tidak didukung pada tata letak ini.
View view = new CardBuilder(context, CardBuilder.Layout.TITLE)
.setText("TITLE Card")
.setIcon(R.drawable.ic_phone)
.addImage(R.drawable.beach)
.getView();
AUTHOR
Gunakan tata letak CardBuilder.Layout.AUTHOR
untuk menampilkan pesan atau percakapan yang menjadi fokus penulis. Fitur ini mendukung mosaik gambar di latar belakang,
ikon yang digunakan sebagai avatar penulis, serta tajuk dan subjudul tempat Anda
dapat mencantumkan informasi identitas.
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
Tata letak
CardBuilder.Layout.MENU
terlihat seperti menu Glass standar. Kartu memiliki
ikon dan judul yang dipusatkan dan catatan kaki opsional. Gunakan tata letak ini untuk
layar konfirmasi (misalnya, transisi dari "Menghapus" ke "Dihapus" setelah pengguna
memilih item menu). Jika memerlukan menu sungguhan, Anda harus menggunakan
menu opsi standar.
View view = new CardBuilder(context, CardBuilder.Layout.MENU)
.setText("MENU layout")
.setIcon(R.drawable.ic_phone)
.setFootnote("Optional menu description")
.getView();
EMBED_INSIDE
Tata letak
CardBuilder.Layout.EMBED_INSIDE
menyematkan XML tata letak kustom desain Anda sendiri ke dalam template kartu
Glass standar. Dengan begitu, Anda dapat mendesain UI kustom untuk aplikasi Anda, tetapi tetap
memiliki penempatan catatan kaki, stempel waktu, ikon atribusi, dan
indikat kartu yang benar jika diperlukan.
Setelah memanggil
CardBuilder.getView()
,
gunakan
findViewById()
pada hasil untuk mengakses tampilan di dalam tata letak sematan Anda. Demikian pula, jika
memanggil
CardBuilder.getRemoteViews()
,
Anda dapat memanipulasi tampilan tata letak sematan dengan meneruskan ID-nya
langsung ke metode penyetel
RemoteViews
.
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
Untuk contoh yang lebih detail, lihat project ApiDemo GitHub.
ALERT
Tata letak
CardBuilder.Layout.ALERT
berisi ikon besar di tengah dengan
pesan utama dan catatan kaki. Gunakan tata letak ini di
Dialog
untuk
menampilkan pesan informasi, peringatan, atau error penting di Glassware Anda.
Contoh berikut menunjukkan implementasi AlertDialog
dan menutup
kartu serta membuka setelan Wi-Fi saat pengguna mengetuk kartu:
- Buat class yang memperluas
Dialog
. - Buat kartu menggunakan
CardBuilder
dengan tata letakCardBuilder.Layout.ALERT
, lalu setel tampilan konten dengan kartu ini. (Opsional) Buat
GestureDetector
untuk menangani gestur pengguna pada kartu ini.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); } }
(Opsional) Dalam aktivitas Anda, terapkan
OnClickListener
untuk menangani alur tambahan saat pengguna mengetuk. Untuk mengetahui informasi cara memulai aktivitas setelan seperti Wi-Fi, lihat Setelan awal.Panggil konstruktor
AlertDialog
untuk menampilkan kartu pemberitahuan.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(); ... } }
Tata letak XML
Berikut adalah dua tata letak kartu dasar yang dapat Anda gunakan jika class CardBuilder tidak memenuhi kebutuhan Anda.
Tata letak utama
Tata letak ini menentukan padding dan footer standar untuk kartu. Tempatkan tampilan Anda
sendiri di RelativeLayout
yang kosong.
<?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>
Tata letak kolom kiri
Ini menentukan kolom kiri 240 px dan kolom kanan 400 px dalam bentuk dua RelativeLayout
tempat Anda dapat memasukkan tampilan.
<?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>
Dimensi standar
Gunakan file ini bersama dengan tata letak sebelumnya atau tata letak Anda sendiri untuk
mematuhi gaya Glass standar. Buat file ini sebagai
res/values/dimens.xml
dalam project Android Anda.
<?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>