사용자 인터페이스

이 문서에서는 Glass 스타일을 따르는 방법과 사용자 환경을 최적화할 수 있는 일반적인 UI 권장사항을 구현하는 방법을 설명합니다. 다음과 같은 UI 요소를 다룹니다.

테마

권장되는 Glass 테마는 다음과 같은 특징이 있습니다.

  • 작업 모음 없이 활동을 전체 화면으로 표시합니다.
  • 검은색 단색 배경을 적용합니다.
  • 색상 가장자리 효과의 색상 라이터를 설정합니다.
  • 흰색 텍스트 색상을 적용합니다.

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>

XML 레이아웃

프래그먼트가 확장할 수 있는 두 가지 기본 카드 레이아웃은 다음과 같습니다.

기본 레이아웃

이 레이아웃은 카드에 권장되는 표준 패딩과 바닥글을 정의합니다. 빈 FrameLayout에 자체 뷰를 배치합니다.

가운데 상자는 560x240픽셀로 화면 내부의 대부분을 차지하며, 하단에는 560x40픽셀의 작은 막대가 있습니다.
          각 모서리에 40x40 픽셀 크기의 작은 블록 4개도 있음

다음은 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>

왼쪽 열 레이아웃

이 레이아웃은 뷰를 배치할 수 있는 두 개의 FrameLayout 클래스 형태로 너비의 왼쪽 1/3과 오른쪽 2/3 너비를 정의합니다. 예시를 보려면 다음 사진을 참조하세요.

왼쪽 레이아웃을 240x360픽셀로 표시하며, 기본 레이아웃을 밀어냅니다.
          크기가 가볍게 조정되기 때문에 기본 영역은 330x240픽셀이고 작은 하단 표시줄은 330x40픽셀입니다. 오른쪽 두 모서리에는 크기가 작은 40x40픽셀 상자 두 개가 있고 다른 30x40픽셀 상자 4개(왼쪽 열의 왼쪽 하단에 2개, 기본 레이아웃의 왼쪽 모서리에 각각 2개, 상단에 1개, 하단에 1개)가 있습니다.

다음은 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>

표준 측정기준

이전 레이아웃 또는 자체 레이아웃과 함께 다음을 사용하여 Glass 스타일을 표준으로 하는 파일을 만드세요. Android 프로젝트에서 이 파일을 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">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>

RecyclerView를 사용하여 메뉴를 빌드하는 것이 좋습니다. Android 스튜디오 프로젝트 리소스의 표준 Android 메뉴 파일을 기반으로 해야 합니다. Android에서는 표준 메뉴 생성을 재정의하고 이를 구현으로 대체할 수 있습니다. 방법은 다음과 같습니다.

  1. RecyclerView을 사용하여 레이아웃을 만들고 Activity의 뷰로 설정합니다.
  2. 새로 만든 메뉴 항목 컬렉션을 사용하도록 RecyclerView 및 어댑터를 설정합니다.
  3. onCreateOptionsMenu 메서드를 재정의합니다.
    1. 메뉴를 펼치고 각 메뉴 항목의 컬렉션에 새 요소를 추가합니다.
    2. 어댑터에서 notifyDataSetChanged 메서드를 호출합니다.

    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)
        }
        

    자바

        @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. OnScrollListenerLayoutManagerSnapHelper과 함께 사용하여 어떤 옵션이 선택되었는지 확인합니다.
  5. 메뉴 항목 선택 이벤트를 처리하는 TAP 동작을 수신합니다.
  6. 선택한 메뉴 항목에 관한 정보가 포함된 Intent를 만듭니다.
  7. 이 활동의 결과를 설정하고 완료합니다.
  8. 메뉴를 표시하려는 프래그먼트나 활동에서 startActivityForResult를 호출합니다. 이를 위해 TAP 동작을 사용합니다.
  9. 선택한 프래그먼트 항목을 처리하도록 호출 프래그먼트 또는 활동의 onActivityResult를 재정의합니다.

가이드라인

다음은 메뉴 레이아웃을 설정하는 방법에 관한 제안사항 목록입니다.

다음 이미지는 맞춤설정된 메뉴 레이아웃의 예입니다.

이 간단한 이미지는 화면 중앙에 &#39;MENU 레이아웃&#39;이 있고 옆에는 전화 기호가 있는 검은색 배경입니다.

구현 세부정보는 카드 샘플 앱을 검토하세요.

스와이프할 수 있는 페이지

Glass 디스플레이와 터치패드를 함께 사용하여 스와이프할 수 있는 카드를 편리하게 표시할 수 있습니다. 표준 Android ViewPager API를 사용하여 활동에 스와이프할 수 있는 페이지를 빌드할 수 있습니다.

Android ViewPager를 사용하여 카드나 화면을 스크롤하는 방법에 관한 자세한 내용은 화면 슬라이드 교육 문서를 참고하세요.