Kart Tasarımı

Bu dokümanda, Glass stilinin nasıl izleneceği ve GDK kullanılırken kullanıcı arayüzüyle ilgili en iyi uygulamaların nasıl kullanıldığı açıklanmaktadır.

Cam teması

Glass, Glassware'inize standart bir tema uygular, böylece kullanıcı arayüzünün geri kalanıyla tutarlı kalır. Tema aşağıdaki özelliklere sahiptir:

  • Roboto yazı tipi kullanır
  • Durum çubuğu veya işlem çubuğu olmadan etkinlikleri tam ekran olarak gösterir
  • Düz, siyah arka plan için geçerlidir

Glass temasını uygulamak için Android Manifest'inizde tema belirtmeyin.

Glassware'in parçaları için özel bir stiliniz varsa ve geri kalan her şey için varsayılan Glass temasını kullanmak istiyorsanız Theme.DeviceDefault özelliğini parent özelliğiyle aktarın:

<resources>
    <style name="CustomTheme" parent="@android:style/Theme.DeviceDefault">
        <!-- Theme customization goes here. -->
    </style>
</resources>

Tema oluşturma hakkında daha fazla bilgi için Stiller ve Temalar'a göz atarak Android geliştirici kılavuzunu inceleyin.

Cam tarzı kartlar

CardBuilder sınıfı bir dizi özelliğe göre iyi biçimlendirilmiş kartlar oluşturur. İçeriğinizin diğer içeriklerle birlikte görünmesi için CardBuilder.Layout tarafından sağlanan düzenleri mümkün olduğunca kullanın.

CardBuilder uygulamasını kullanmak için:

  1. CardBuilder.Layout üzerinden istediğiniz düzeni sağlayarak CardBuilder örneğini oluşturun.
  2. Metin, dipnot ve zaman damgası gibi kart özelliklerini ayarlayın.
  3. Kartı Android'e dönüştürmek için CardBuilder.getView()'i View, CardBuilder.getRemoteViews() ise RemoteViews nesneye dönüştürmek için arayın.
  4. View öğelerini etkinliklerinizde, düzenlerinizde veya bir CardScrollView içinde ya da RemoteViews simgesini LiveCard içinde kullanın.

Genel kullanıcı arayüzü özellikleri

CardBuilder tarafından sağlanan düzenlerin çoğu, aşağıda açıklanan ortak kullanıcı arayüzü özelliklerini destekler. Her kart türü tarafından desteklenen özelliklerin listesi için CardBuilder.Layout sayfasındaki her bir düzenin dokümanlarına bakın.

İlişkilendirme simgesi

İlişkilendirme simgesi, bir kartın sağ alt köşesinde ve zaman damgasının sağ tarafında görünen isteğe bağlı 36 × 36 piksel simgesidir. Özellikle canlı kartlarda uygulamanızı tanımlamak için CardBuilder.setAttributionIcon() simgesini çağırarak bu simgeyi ayarlayın. Böylece kullanıcılar bu karttaki bilgilerin kaynağını hızlı bir şekilde görebilir ve görebilir.

Yığın göstergesi

CardBuilder.showStackIndicator() tarafından kontrol edilen yığın göstergesi, kartın sağ üst köşesinde görünen bir köşe katlamadır. Bu öğeyi, kartınızın doğrudan kullanıcının dokunabileceği diğer kartlardan oluşan bir grubu temsil ettiğini gösteren görsel bir gösterge olarak kullanın.

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

Düzenler

Aşağıdaki örneklerde CardBuilder kullanılarak kullanılabilecek düzenler gösterilmektedir.

TEXT ve TEXT_FIXED

CardBuilder.Layout.TEXT düzeni, arka plan üzerinde isteğe bağlı bir resim mozaiğiyle tam çerçeve metni gösterir. Metin, mevcut alana en uygun şekilde dinamik olarak yeniden boyutlandırılır. CardBuilder.Layout.TEXT_FIXED benzerdir ancak metnini daha küçük bir boyuta sabitler.

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 ve COLUMNS_FIXED

CardBuilder.Layout.COLUMNS düzeninde, kartın sol tarafında bir resim mozaiği veya simgesi, sağ tarafında ise metin gösterilir. Metin, mevcut alana en uygun şekilde dinamik olarak boyutlandırılır. Metin boyutunu sabit tutmak için CardBuilder.Layout.COLUMNS_FIXED kullanın.

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

CardBuilder.Layout.CAPTION düzeninde, arka planda resim mozaiği ve kartın alt kısmına hizalanmış kısa bir altyazı metni bulunur. Altyazının yanına, örneğin, kart içeriğiyle ilişkilendirilmiş bir kişinin kimliğini temsil eden bir simge de yerleştirilebilir.

Şekil 1: (photoeverywhere.co.uk tarafından kırpılmış arka plan resmi, kırpılmış)
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

CardBuilder.Layout.TITLE düzeninde, arka uçta ortalanmış bir başlık ve isteğe bağlı bir simge bulunan arka plan üzerinde resim mozaiği bulunur. Bu düzen genellikle kişileri temsil etmek veya hedefleri paylaşmak için kullanılır. Dipnot ve zaman damgası bu düzende desteklenmez.

View view = new CardBuilder(context, CardBuilder.Layout.TITLE)
    .setText("TITLE Card")
    .setIcon(R.drawable.ic_phone)
    .addImage(R.drawable.beach)
    .getView();

AUTHOR

Mesajın veya konuşmanın odakta yazar olduğu bir yeri görüntülemek için CardBuilder.Layout.AUTHOR düzenini kullanın. Arka planda resim mozaiği, yazarın avatarı olarak kullanılan bir simge ve tanımlayıcı bilgileri listeleyebileceğiniz bir başlık ve alt başlık desteklenir.

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

CardBuilder.Layout.MENU düzeni, standart bir cam menüsüne benzer. Ortalanmış bir simgesi, başlığı ve isteğe bağlı bir dipnotu vardır. Onay ekranları için bu düzeni kullanın (örneğin, kullanıcı bir menü öğesini seçtikten sonra "Silme"den "Silindi"ye geçiş). Gerçek bir menüye ihtiyacınız varsa bunun yerine standart seçenekler menüsünü kullanmanız gerekir.

View view = new CardBuilder(context, CardBuilder.Layout.MENU)
    .setText("MENU layout")
    .setIcon(R.drawable.ic_phone)
    .setFootnote("Optional menu description")
    .getView();

EMBED_INSIDE

CardBuilder.Layout.EMBED_INSIDE düzeni, standart Glass kartı şablonuna kendi tasarımınızın özel bir düzen XML'ini yerleştirir. Bu şekilde, uygulamanız için özel bir kullanıcı arayüzü tasarlayabilirsiniz. Ancak gerekirse dipnot, zaman damgası, ilişkilendirme simgesi ve yığın göstergesinin doğru şekilde yerleştirildiğini görebilirsiniz.

Yerleştirilmiş düzeninizdeki görünümlere erişmek için CardBuilder.getView() yöntemini çağırdıktan sonra sonuçta findViewById() kullanın. Benzer şekilde, CardBuilder.getRemoteViews() yöntemini çağırırsanız bu yerleşik kimliklerin görünümlerini, kimliklerini doğrudan RemoteViews ayarlanmış yöntemlere ileterek değiştirebilirsiniz.

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

Daha ayrıntılı bir örnek için GitHub ApiDemo projesine göz atın.

ALERT

CardBuilder.Layout.ALERT düzeninde birincil mesaj ve dipnot içeren büyük, ortalanmış bir simge bulunur. Glassware'inizde önemli bir bilgilendirme mesajı, uyarı veya hata göstermek için bu düzeni Dialog içinde kullanın.

Aşağıdaki örnekte AlertDialog uygulaması gösterilmektedir ve kullanıcı karta dokunduğunda kart kapatılıp kablosuz ayarları açılır:

  1. Dialog sayfasını kapsayan bir sınıf oluşturun.
  2. CardBuilder.Layout.ALERT düzeninde CardBuilder aracını kullanarak kartı oluşturun ve ardından bu kartla içerik görünümünü ayarlayın.
  3. (İsteğe bağlı) Bu karttaki kullanıcı hareketlerini işlemek için GestureDetector oluşturun.

    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. (İsteğe bağlı) Etkinliğinizde, kullanıcı dokunduğunda ek akışları yönetmek için bir OnClickListener uygulayın. Kablosuz gibi ayar etkinliklerini başlatma hakkında daha fazla bilgiyi Başlangıç ayarları'nda bulabilirsiniz.

  5. Uyarı kartını görüntülemek için AlertDialog oluşturucuyu arayın.

    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 düzenleri

CardBuilder sınıfı ihtiyaçlarınızı karşılamıyorsa kullanabileceğiniz iki temel kart düzeni aşağıda verilmiştir.

Ana düzen

Bu düzen, bir kart için standart dolguyu ve altbilgiyi tanımlar. Boş görüntülemeleri RelativeLayout içine yerleştirin.

<?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>

Sol sütun düzeni

Bu özellik, 240 piksel sol ve 400 piksellik sağ sütunlar olmak üzere görünümleri yerleştirebileceğiniz iki RelativeLayout tanımlar.

<?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>

Standart boyutlar

Standart cam stiline uymak için bu dosyayı önceki düzenlerle veya kendi düzenlerinizle birlikte kullanın. Bu dosyayı Android projenizde res/values/dimens.xml olarak oluşturun.

<?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>