Desain Kartu

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 tetap konsisten dengan seluruh antarmuka pengguna. Tujuan memiliki karakteristik berikut:

  • Menggunakan typeface Roboto
  • Menampilkan aktivitas dalam layar penuh tanpa status bar atau panel tindakan
  • Menerapkan latar belakang solid dan hitam

Untuk menerapkan tema Glass, jangan deklarasikan tema dalam Manifes Android Anda.

Jika Anda memiliki gaya kustom untuk komponen Glassware dan menginginkan tema Glass {i>default<i} untuk yang lainnya, mewarisi 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 informasi selengkapnya tentang cara membuat tema.

Kartu bergaya kaca

CardBuilder membuat kartu yang tersusun dengan baik berdasarkan serangkaian properti. Menggunakan tata letak disediakan oleh CardBuilder.Layout jika memungkinkan, sehingga konten Anda terlihat dan terasa seperti konten lain di Kaca.

Untuk menggunakan CardBuilder:

  1. Buat instance CardBuilder, berikan tata letak yang Anda inginkan dari CardBuilder.Layout.
  2. Setel properti kartu, seperti teks, catatan kaki, dan stempel waktu.
  3. Panggil CardBuilder.getView() untuk mengonversi kartu ke Android View, atau CardBuilder.getRemoteViews() untuk mengubahnya menjadi RemoteViews .
  4. Gunakan View dalam aktivitas, tata letak, atau CardScrollView, atau gunakan RemoteViews di LiveCard.

Fitur UI umum

Banyak tata letak yang disediakan oleh CardBuilder mendukung antarmuka pengguna umum fitur yang dijelaskan di bawah ini. Lihat dokumentasi masing-masing tata letak di CardBuilder.Layout untuk mengetahui daftar fitur yang didukung oleh setiap jenis kartu.

Ikon atribusi

Ikon atribusi adalah ikon piksel 36 × 36 opsional yang muncul di sudut kanan bawah kartu dan di sebelah kanan tanda waktu. Setel ini ikon dengan memanggil CardBuilder.setAttributionIcon() untuk mengidentifikasi aplikasi Anda, terutama pada kartu {i>live<i} sehingga pengguna dapat dengan cepat secara sekilas dan melihat sumber informasi pada kartu tersebut.

Indikator stack

Indikator tumpukan, dikontrol oleh CardBuilder.showStackIndicator(), adalah lipatan sudut yang muncul di sudut kanan atas sebuah kartu. Gunakan ini sebagai indikator visual bahwa kartu Anda mewakili seikat kartu lain yang yang dapat diakses secara 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

CardBuilder.Layout.TEXT tata letak menampilkan teks penuh dari sisi ke sisi dengan mozaik gambar di latar belakang. Teks berubah ukurannya secara dinamis agar sesuai dengan atau ukuran ruang yang tersedia. CardBuilder.Layout.TEXT_FIXED serupa 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

Tujuan CardBuilder.Layout.COLUMNS yang memperlihatkan mosaik atau ikon pada sisi kiri kartu dan teks di sisi kanan. Teks berukuran dinamis yang paling sesuai dengan ruang yang tersedia. Untuk menjaga ukuran teks tetap, 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

Tujuan CardBuilder.Layout.CAPTION tata letak memiliki mosaik gambar di latar belakang dan teks singkat rata di bagian bawah kartu. Ikon juga bisa berupa ditempatkan di samping teks untuk, misalnya, identitas seseorang yang terkait dengan konten kartu.

Gambar 1: (gambar latar oleh photoeverywhere.co.uk, dipangkas)
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

Tujuan CardBuilder.Layout.TITLE tata letak 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 CardBuilder.Layout.AUTHOR tata letak untuk menampilkan pesan atau percakapan yang fokusnya adalah pada penulis. Alat ini mendukung mosaik gambar di latar belakang, ikon yang digunakan sebagai avatar penulis, dan {i>heading<i} dan {i>subheading <i}di mana Anda dapat daftar informasi identifikasi.

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();

Tujuan CardBuilder.Layout.MENU terlihat seperti menu Glass standar. Alat ini memiliki ikon dan judul di tengah, dan catatan kaki opsional. Gunakan tata letak ini untuk layar konfirmasi (bertransisi dari "Menghapus" menjadi "Dihapus" setelah pengguna memilih item menu, misalnya). Jika Anda membutuhkan menu yang nyata, 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

Tujuan CardBuilder.Layout.EMBED_INSIDE menyematkan XML tata letak khusus dari desain Anda sendiri ke dalam Glass template kartu. Hal ini memungkinkan Anda mendesain UI kustom untuk aplikasi Anda tetapi tetap penempatan yang benar untuk catatan kaki, stempel waktu, ikon atribusi, dan indikator tumpukan jika diperlukan.

Setelah menelepon CardBuilder.getView(), penggunaan findViewById() pada hasilnya untuk mengakses tampilan di dalam tata letak tersemat Anda. Demikian juga, jika Anda panggilan telepon CardBuilder.getRemoteViews(), Anda bisa memanipulasi tampilan tata letak tersemat dengan meneruskan ID-nya langsung ke dalam RemoteViews metode penyetel.

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 GitHub Project ApiDemo.

ALERT

Tujuan CardBuilder.Layout.ALERT berisi ikon besar yang berada di tengah dengan pesan utama dan catatan kaki. Gunakan tata letak ini dalam Dialog ke menampilkan pesan informasi, peringatan, atau error penting di Glassware Anda.

Contoh berikut menunjukkan implementasi AlertDialog dan menutup dan membuka setelan Wi-Fi saat pengguna mengetuk kartu:

  1. Buat class yang memperluas Dialog.
  2. Buat kartu menggunakan CardBuilder dengan tata letak CardBuilder.Layout.ALERT, lalu setel tampilan konten dengan kartu ini.
  3. (Opsional) Buat GestureDetector untuk menangani gestur pengguna di 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);
        }
    }
    
  4. (Opsional) Dalam aktivitas Anda, implementasikan OnClickListener untuk menangani alur tambahan saat pengguna mengetuk. Untuk mengetahui informasi selengkapnya tentang memulai aktivitas pengaturan seperti Wi-Fi, melihat Memulai setelan.

  5. Panggil konstruktor AlertDialog untuk menampilkan kartu peringatan.

    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 melakukan tidak memenuhi kebutuhan Anda.

Tata letak utama

Tata letak ini mendefinisikan padding dan footer standar untuk kartu. Letakkan milik Anda tampilan dalam 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 sebelah kiri

Ini menentukan kolom kiri 240 px dan kolom kanan 400 px dalam bentuk dua RelativeLayout dan Anda dapat menempatkan tampilan Anda.

<?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 untuk mematuhi standar gaya Glass. Buat file ini sebagai res/values/dimens.xml di 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>