طراحی کارت

این سند به نحوه پیروی از سبک Glass و اجرای بهترین شیوه های رایج رابط کاربری در هنگام استفاده از GDK می پردازد.

تم شیشه ای

Glass یک تم استاندارد را برای Glassware شما اعمال می کند، بنابراین با بقیه رابط کاربری سازگار می ماند. موضوع دارای ویژگی های زیر است:

  • از تایپ فیس Roboto استفاده می کند
  • فعالیت ها را به صورت تمام صفحه و بدون نوار وضعیت یا نوار عمل نمایش می دهد
  • پس زمینه سیاه و سفید را اعمال می کند

برای اعمال طرح زمینه شیشه ای، طرح زمینه را در مانیفست اندروید خود اعلام نکنید.

اگر یک سبک سفارشی برای بخش‌هایی از Glassware خود دارید و می‌خواهید تم شیشه‌ای پیش‌فرض را برای هر چیز دیگری داشته باشید، از Theme.DeviceDefault با ویژگی parent ارث ببرید:

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

برای اطلاعات بیشتر درباره ایجاد تم، راهنمای برنامه‌نویس اندروید در مورد سبک‌ها و طرح‌های زمینه را ببینید.

کارت های شیشه ای

کلاس CardBuilder با توجه به مجموعه‌ای از ویژگی‌ها، کارت‌هایی با فرم خوب ایجاد می‌کند. هر زمان که ممکن است از طرح‌بندی‌های ارائه‌شده توسط CardBuilder.Layout استفاده کنید تا محتوای شما مانند سایر محتوای Glass به نظر برسد.

برای استفاده از CardBuilder :

  1. یک نمونه از CardBuilder ایجاد کنید و طرح مورد نظر خود را از CardBuilder.Layout به آن بدهید.
  2. ویژگی های کارت، مانند متن، پاورقی و مهر زمانی را تنظیم کنید.
  3. با CardBuilder.getView() برای تبدیل کارت به View Android یا CardBuilder.getRemoteViews() برای تبدیل آن به یک شی RemoteViews تماس بگیرید.
  4. View در فعالیت‌ها، طرح‌بندی‌ها یا در CardScrollView استفاده کنید یا از RemoteViews در LiveCard استفاده کنید.

ویژگی های مشترک رابط کاربری

بسیاری از طرح‌بندی‌های ارائه‌شده توسط CardBuilder از ویژگی‌های مشترک رابط کاربری که در زیر توضیح داده شده است، پشتیبانی می‌کنند. برای لیستی از ویژگی های پشتیبانی شده توسط هر نوع کارت، به مستندات طرح بندی های فردی در CardBuilder.Layout مراجعه کنید.

نماد اسناد

نماد انتساب یک نماد اختیاری 36 × 36 پیکسل است که در گوشه سمت راست پایین کارت و سمت راست مهر زمانی ظاهر می‌شود. این نماد را با فراخوانی CardBuilder.setAttributionIcon() تنظیم کنید تا برنامه شما را شناسایی کند، مخصوصاً در کارت های زنده تا کاربر بتواند به سرعت به منبع اطلاعات آن کارت نگاه کند و ببیند.

نشانگر پشته

نشانگر پشته، که توسط CardBuilder.showStackIndicator() کنترل می شود، یک چین گوشه ای است که در گوشه سمت راست بالای کارت ظاهر می شود. از این به عنوان یک نشانگر بصری استفاده کنید که کارت شما مجموعه ای از کارت های دیگر را نشان می دهد که کاربر می تواند مستقیماً به آنها ضربه بزند.

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

طرح بندی ها

مثال‌های زیر طرح‌بندی‌هایی را نشان می‌دهند که با استفاده از CardBuilder در دسترس هستند.

TEXT و TEXT_FIXED

طرح‌بندی CardBuilder.Layout.TEXT متن کاملی را با یک موزاییک تصویر اختیاری در پس‌زمینه نشان می‌دهد. اندازه متن به صورت پویا تغییر می کند تا به بهترین وجه با فضای موجود مطابقت داشته باشد. CardBuilder.Layout.TEXT_FIXED مشابه است اما متن آن را در اندازه کوچکتر اصلاح می کند.

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

طرح CardBuilder.Layout.COLUMNS یک موزاییک یا نماد تصویر را در سمت چپ کارت و متن را در سمت راست نشان می دهد. متن به صورت پویا اندازه می شود تا به بهترین شکل با فضای موجود مطابقت داشته باشد. برای ثابت نگه داشتن اندازه متن، از 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

طرح‌بندی CardBuilder.Layout.CAPTION دارای یک موزاییک تصویر در پس‌زمینه و متن شرح مختصر است که در پایین کارت تراز شده است. همچنین می‌توان یک نماد در کنار عنوان قرار داد تا به عنوان مثال، هویت شخصی مرتبط با محتوای کارت را نشان دهد.

شکل 1 : (تصویر پس زمینه توسط photoeverywhere.co.uk ، برش داده شده)
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 دارای یک موزاییک تصویر در پس زمینه با عنوان در مرکز و نماد اختیاری در پایین کارت است. این طرح اغلب برای نشان دادن مخاطبین یا اشتراک گذاری اهداف استفاده می شود. پاورقی و مهر زمانی در این طرح‌بندی پشتیبانی نمی‌شوند.

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

AUTHOR

از طرح بندی CardBuilder.Layout.AUTHOR برای نمایش پیام یا مکالمه ای که تمرکز روی نویسنده است استفاده کنید. از یک موزاییک تصویر در پس‌زمینه، نمادی که به عنوان آواتار نویسنده استفاده می‌شود، و عنوان و عنوان فرعی که در آن می‌توانید اطلاعات شناسایی را فهرست کنید، پشتیبانی می‌کند.

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 شبیه یک منوی استاندارد Glass است. دارای یک نماد و عنوان وسط و یک پاورقی اختیاری است. از این طرح‌بندی برای صفحه‌های تأیید استفاده کنید (مثلاً پس از انتخاب یک آیتم منو، از «حذف» به «حذف شده» منتقل می‌شوید). اگر به یک منوی واقعی نیاز دارید، باید به جای آن از منوی گزینه های استاندارد استفاده کنید.

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 یک طرح XML سفارشی از طرح شما را در قالب استاندارد کارت شیشه ای جاسازی می کند. این به شما امکان می‌دهد یک رابط کاربری سفارشی برای برنامه خود طراحی کنید، اما در صورت نیاز، پاورقی، مهر زمانی، نماد انتساب و نشانگر پشته کارت را به درستی قرار دهید.

پس از فراخوانی CardBuilder.getView() ، از findViewById() روی نتیجه استفاده کنید تا به نماهای داخل طرح بندی تعبیه شده خود دسترسی پیدا کنید. به همین ترتیب، اگر CardBuilder.getRemoteViews() را فراخوانی کنید، می توانید نماهای طرح بندی تعبیه شده خود را با ارسال شناسه آنها به طور مستقیم به متدهای تنظیم کننده 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

برای مثال دقیق تر، پروژه GitHub ApiDemo را ببینید.

ALERT

طرح CardBuilder.Layout.ALERT شامل یک نماد بزرگ در مرکز با پیام اصلی و پاورقی است. از این طرح در یک Dialog برای نمایش یک پیام مهم اطلاعاتی، هشدار یا خطا در Glassware خود استفاده کنید.

مثال زیر اجرای AlertDialog را نشان می‌دهد و وقتی کاربر روی کارت ضربه می‌زند، کارت را حذف می‌کند و تنظیمات WiFi را باز می‌کند:

  1. کلاسی ایجاد کنید که Dialog گسترش دهد.
  2. کارت را با استفاده از CardBuilder با طرح CardBuilder.Layout.ALERT ایجاد کنید و سپس نمای محتوا را با این کارت تنظیم کنید.
  3. (اختیاری) یک GestureDetector برای مدیریت حرکات کاربر در این کارت ایجاد کنید.

    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. (اختیاری) در فعالیت خود، یک OnClickListener برای مدیریت هر جریان اضافی در هنگام ضربه زدن کاربر پیاده سازی کنید. برای اطلاعات بیشتر درباره شروع فعالیت‌های تنظیمات مانند WiFi، به تنظیمات شروع مراجعه کنید.

  5. برای نمایش کارت هشدار با سازنده AlertDialog تماس بگیرید.

    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

در اینجا دو طرح اصلی کارت وجود دارد که اگر کلاس CardBuilder نیازهای شما را برآورده نمی کند، می توانید از آنها استفاده کنید.

طرح اصلی

این طرح، بالشتک و پاورقی استاندارد یک کارت را تعریف می کند. نماهای خود را در RelativeLayout خالی قرار دهید.

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

طرح ستون سمت چپ

این یک ستون سمت چپ 240 پیکسلی و ستون سمت راست 400 پیکسلی را در قالب دو RelativeLayout تعریف می کند که می توانید نماهای خود را در آنها قرار دهید.

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

ابعاد استاندارد

از این فایل در ارتباط با طرح‌بندی‌های قبلی یا طرح‌بندی‌های خود استفاده کنید تا به سبک استاندارد شیشه‌ای پایبند باشید. این فایل را به صورت res/values/dimens.xml در پروژه اندروید خود ایجاد کنید.

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