Giao diện người dùng

Tài liệu này trình bày cách tuân theo kiểu Glass và triển khai các phương pháp hay nhất thường gặp về giao diện người dùng có thể tối ưu hoá trải nghiệm của người dùng. Nó bao gồm các phần tử sau trên giao diện người dùng:

Chủ đề

Chủ đề Glass mà bạn nên dùng có những đặc điểm sau:

  • Hiển thị các hoạt động ở chế độ toàn màn hình mà không có thanh thao tác.
  • Áp dụng nền đen đồng nhất.
  • Đặt màu sáng hơn cho hiệu ứng cạnh màu.
  • Áp dụng màu văn bản trắng.

Sau đây là các chế độ cài đặt giao diện được đề xuất cho Glass:

 <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
   <item name="android:windowBackground">@android:color/black</item>
   <item name="android:colorEdgeEffect">@android:color/white</item>
   <item name="android:textColor">@android:color/white</item>
 </style>

Bố cục XML

Sau đây là 2 bố cục thẻ cơ bản mà các mảnh của bạn có thể mở rộng:

Bố cục chính

Bố cục này xác định khoảng đệm và chân trang tiêu chuẩn được đề xuất cho thẻ. Đưa quan điểm của riêng bạn vào FrameLayout trống.

Hộp ở giữa chiếm phần lớn bên trong màn hình với kích thước 560 x 240 pixel, có một thanh nhỏ ở dưới cùng với kích thước 560 x 40 pixel.
          Ngoài ra còn có 4 khối nhỏ 40 x 40 pixel, mỗi khối ở một góc

Dưới đây là một ví dụ về bố cục XML:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <FrameLayout
      android:id="@+id/body_layout"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_margin="@dimen/glass_card_margin"
      app:layout_constraintBottom_toTopOf="@id/footer"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent">

    <!-- Put your widgets inside this FrameLayout. -->

  </FrameLayout>

  <!-- The footer view will grow to fit as much content as possible while the
         timestamp view keeps its width. If the footer text is too long, it
         will be ellipsized with a 40dp margin between it and the timestamp. -->

  <TextView
      android:id="@+id/footer"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="@dimen/glass_card_margin"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toStartOf="@id/timestamp"
      app:layout_constraintStart_toStartOf="parent" />

  <TextView
      android:id="@+id/timestamp"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAlignment="viewEnd"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Bố cục cột bên trái

Bố cục này xác định một cột bên trái có chiều rộng bằng 1/3 và một cột bên phải có chiều rộng bằng 2/3 dưới dạng hai lớp FrameLayout mà bạn có thể đặt các khung hiển thị vào. Tham khảo hình ảnh sau đây để xem ví dụ.

Hiển thị một cột bên trái có kích thước 240 x 360 pixel, đẩy bố cục chính sang bên.
          Kích thước của vùng này sẽ được điều chỉnh cho phù hợp, vùng chính có kích thước 330 x 240 pixel, với một thanh nhỏ phía dưới có kích thước 330 x 40 pixel. Hai góc bên phải có 2 ô nhỏ kích thước 40 x 40 pixel và có 4 ô khác kích thước 30 x 40 pixel, 2 ô ở các góc dưới của cột bên trái và 2 ô ở bên trái bố cục chính, 1 ô ở trên cùng và 1 ô ở dưới cùng.

Dưới đây là một ví dụ về bố cục XML:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <FrameLayout
      android:id="@+id/left_column"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:background="#303030"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintWidth_percent=".333">

    <!-- Put widgets for the left column inside this FrameLayout. -->

  </FrameLayout>

  <FrameLayout
      android:id="@+id/right_column"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_marginTop="@dimen/glass_card_two_column_margin"
      android:layout_marginStart="@dimen/glass_card_two_column_margin"
      android:layout_marginBottom="@dimen/glass_card_two_column_margin"
      android:layout_marginEnd="@dimen/glass_card_margin"
      app:layout_constraintBottom_toTopOf="@id/footer"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toEndOf="@id/left_column"
      app:layout_constraintTop_toTopOf="parent">

    <!-- Put widgets for the right column inside this FrameLayout. -->

  </FrameLayout>

  <!-- The footer view will grow to fit as much content as possible while the
         timestamp view keeps its width. If the footer text is too long, it
         will be ellipsized with a 40dp margin between it and the timestamp. -->

  <TextView
      android:id="@+id/footer"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="@dimen/glass_card_margin"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toStartOf="@id/timestamp"
      app:layout_constraintStart_toEndOf="@id/left_column" />

  <TextView
      android:id="@+id/timestamp"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAlignment="viewEnd"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Phương diện chuẩn

Sử dụng các bố cục sau cùng với bố cục trước đó hoặc bố cục của riêng bạn để tạo một tệp tuân thủ kiểu tiêu chuẩn của Glass. Tạo tệp này dưới dạng res/values/dimens.xml trong dự án Android của bạn.

<?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">40dp</dimen>

  <!-- The recommended margin between the bottom of the card and the footer. -->
  <dimen name="glass_card_footer_margin">50dp</dimen>

  <!-- The recommended margin for the left column of the two-column card. -->
  <dimen name="glass_card_two_column_margin">30dp</dimen>

</resources>

Bạn nên dùng RecyclerView để tạo trình đơn. Các tệp này phải dựa trên tệp trình đơn Android tiêu chuẩn trong tài nguyên dự án Android Studio. Android cho phép bạn ghi đè quá trình tạo trình đơn tiêu chuẩn và thay thế bằng quá trình triển khai của riêng bạn. Để thực hiện việc này, hãy làm theo các bước sau:

  1. Tạo bố cục bằng RecyclerView và đặt bố cục đó làm khung hiển thị cho Activity.
  2. Đặt RecyclerView và đối tượng chuyển đổi của nó để sử dụng tập hợp các mục trong trình đơn mới tạo.
  3. Ghi đè phương thức onCreateOptionsMenu.
    1. Tăng kích thước trình đơn và thêm phần tử mới vào tập hợp cho từng mục trong trình đơn.
    2. Gọi phương thức notifyDataSetChanged trên trình chuyển đổi.

    Kotlin

        override fun onCreateOptionsMenu(menu: Menu): Boolean {
            val menuResource = intent
                .getIntExtra(EXTRA_MENU_KEY, EXTRA_MENU_ITEM_DEFAULT_VALUE)
            if (menuResource != EXTRA_MENU_ITEM_DEFAULT_VALUE) {
                menuInflater.inflate(menuResource, menu)
                for (i in 0 until menu.size()) {
                    val menuItem = menu.getItem(i)
                    menuItems.add(
                        GlassMenuItem(
                            menuItem.itemId, menuItem.icon,
                            menuItem.title.toString()
                        )
                    )
                    adapter.notifyDataSetChanged()
                }
            }
            return super.onCreateOptionsMenu(menu)
        }
        

    Java

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
          final int menuResource = getIntent()
              .getIntExtra(EXTRA_MENU_KEY, EXTRA_MENU_ITEM_DEFAULT_VALUE);
          if (menuResource != EXTRA_MENU_ITEM_DEFAULT_VALUE) {
            final MenuInflater inflater = getMenuInflater();
            inflater.inflate(menuResource, menu);
    
            for (int i = 0; i < menu.size(); i++) {
              final MenuItem menuItem = menu.getItem(i);
              menuItems.add(
                  new GlassMenuItem(menuItem.getItemId(), menuItem.getIcon(),
                      menuItem.getTitle().toString()));
              adapter.notifyDataSetChanged();
            }
          }
          return super.onCreateOptionsMenu(menu);
        }
        
  4. Sử dụng OnScrollListener cùng với LayoutManagerSnapHelper để xác định lựa chọn nào đã được chọn.
  5. Theo dõi cử chỉ TAP để xử lý sự kiện chọn mục trong trình đơn.
  6. Tạo một Intent có thông tin về mục trong trình đơn đã chọn.
  7. Đặt kết quả cho hoạt động này và kết thúc hoạt động.
  8. Gọi startActivityForResult từ mảnh hoặc hoạt động mà bạn muốn có trình đơn. Sử dụng cử chỉ TAP cho mục đích này.
  9. Ghi đè onActivityResult trong mảnh hoặc hoạt động gọi để xử lý mục trong trình đơn đã chọn.

Nguyên tắc

Sau đây là danh sách các đề xuất về cách thiết lập bố cục trình đơn:

Hình ảnh sau đây là ví dụ về bố cục trình đơn tuỳ chỉnh:

Hình ảnh đơn giản này cho thấy một nền đen với dòng chữ &quot;Bố cục MENU&quot; ở giữa màn hình và biểu tượng điện thoại ở bên cạnh.

Hãy xem Ứng dụng mẫu Thẻ để biết thông tin chi tiết về cách triển khai.

Trang có thể vuốt

Màn hình và bàn di chuột của Glass phối hợp với nhau để hiển thị các thẻ có thể vuốt một cách thuận tiện. Bạn có thể tạo các trang có thể vuốt trong hoạt động của mình bằng API ViewPager tiêu chuẩn của Android.

Hãy xem tài liệu đào tạo về Thao tác vuốt màn hình để biết thêm thông tin về cách sử dụng ViewPager Android để di chuyển qua các thẻ hoặc màn hình.