Android 培训

定义Layouts

编写: roya 原文:https://developer.android.com/training/wearables/ui/layouts.html

可穿戴设备使用与手持Android设备同样的布局技术,但需要有具体的约束来设计。不要以一个手持app的角度开发功能和UI以期待提供一个好的体验。关于如何设计优秀的可穿戴apps的更多信息,请阅读Android Wear Design Guidelines

当你为Android Wear apps创建layouts时,你需要同时考虑方形和圆形屏幕的设备。在圆形Android Wear设备上所有放置在靠近屏幕边角的内容会被剪裁掉,所以为方形屏幕设计的layouts不能在圆形设备上很好的工作。对这类问题是示范请查看这个视屏Full Screen Apps for Android Wear

举个例子,figure 1展示了下面的layout在圆形和方形屏幕上看起来是怎样的:

Figure 1. 为方形屏幕设计的layouts不能在圆形设备上很好工作的示范

<LinearLayout 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"
android:orientation="vertical">

<TextView
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_square" />
</LinearLayout>

text没有正确的显示在圆形屏幕上。

Wearable UI Library为这个问题提供了两种不同的解决方案:

  • 为圆形和方形屏幕定义不同的layouts。你的app会在运行时检查设备屏幕形状后inflates正确的layout。
  • 用一个包含在library里面的特殊layout同时适配方形和圆形设备。这个layout会在不同形状的设备屏幕窗口中插入间隔。

当你希望你的app在不同形状的屏幕上看起来不同时,你可以典型的使用第一种方案。当你希望用一个相似的layout在两种屏幕上且在圆形屏幕上没有视图被边缘剪裁时,你可以使用第二种方案。

添加Wearable UI库

Android Studio会在你使用工程向导时includes你在wear module中的Wearable UI库。为了编译你的工程和这个库,确保 Extras > Google Repository 包已经被安装在Android SDK manager里、以下的wear module依赖被包含在你的build.gradle文件中。

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.google.android.support:wearable:+'
    compile 'com.google.android.gms:play-services-wearable:+'
}

要实现以下的布局方法 'com.google.android.support:wearable' 依赖是必须的。

浏览API reference documentation查看Wearable UI类库。

为方形和圆形屏幕指定不同的Layouts

在Wearable UI库中的WatchViewStub类允许你为方形和圆形屏幕指定不同的layouts。这个类会在运行时姜茶屏幕形状后inflates符合的layout。

在你的app中使用这个类以应对不用和的屏幕形状:

  • 在你的activity's layout以WatchViewStub为主元素。
  • 为方形屏幕指定一个layout解释文件使用rectLayout属性。
  • 为圆形屏幕指定一个layout解释文件使用roundLayout属性。

定义你的activity's layout类似于:

<android.support.wearable.view.WatchViewStub
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/watch_view_stub"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:rectLayout="@layout/rect_activity_wear"
    app:roundLayout="@layout/round_activity_wear">
</android.support.wearable.view.WatchViewStub>

在你的activity中inflate这个layout:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_wear);
}

然后为方形和圆形屏幕创建不同的layout描述文件,在这个例子中,你需要创建文件 res/layout/rect_activity_wear.xmlres/layout/round_activity_wear.xml 。像创建手持apps的layouts一样定义这些layouts,但同时考虑可穿戴设备的限制。系统会在运行时以屏幕形状inflates适合的layout。

取得layout views

你为方形或圆形屏幕定义的layouts在WatchViewStub检查完屏幕形状之前不会被inflated。所以你的app不能立即取得它们的views。为了取得这些views,你需要在你的activity中设置一个listener,当屏幕适配的layout被inflated时会通知这个listener:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_wear);

    WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override public void onLayoutInflated(WatchViewStub stub) {
            // Now you can access your views
            TextView tv = (TextView) stub.findViewById(R.id.text);
            ...
        }
    });
}

使用形状感知的Layout

包含在你的Wearable UI库中的 BoxInsetLayout 继承自 FrameLayout允许你定义一个同时适配方形和圆形屏幕的layout。这个类适用于需要根据屏幕形状插入间隔的情况并允许你简单的对齐views在屏幕边缘或中心。

figure 2中,在 BoxInsetLayout 里的灰色方形区域会在圆形屏幕里应用所需的窗口间隔后自动放置child views。为了显示在这个区域内,子views需要具体声明附加属性 layout_box 为这些值:

  • 一个top, bottom, left, right的复合属性。比如 "left|top" 说明子view的左和上边缘如figure 2。
  • all 说明子view的内容在灰色方形内如figure 2。

Figure 2. 在圆形屏幕上的窗口间隔

在方形屏幕上,窗口间隔为0、 layout_box 属性会被忽略。

Figure 3. 同一个layout定义工作在方形和圆形屏幕上

这个layout在figure 3中展示了在圆形和方形屏幕上使用 BoxInsetLayout

<android.support.wearable.view.BoxInsetLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
*   android:background="@drawable/robot_background"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
*   android:padding="15dp">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
*       android:padding="5dp"
*       app:layout_box="all">

        <TextView
            android:gravity="center"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:text="@string/sometext"
            android:textColor="@color/black" />

        <ImageButton
            android:background="@null"
            android:layout_gravity="bottom|left"
            android:layout_height="50dp"
            android:layout_width="50dp"
            android:src="@drawable/ok" />

        <ImageButton
            android:background="@null"
            android:layout_gravity="bottom|right"
            android:layout_height="50dp"
            android:layout_width="50dp"
            android:src="@drawable/cancel" />
    </FrameLayout>
</android.support.wearable.view.BoxInsetLayout>

注意layout中这些被加*的部分

  • android:padding="15dp"

    这行指定了 BoxInsetLayout 元素的padding。因为在圆形设备商窗口间隔大于15dp,这个padding只工作在方形屏幕上。

  • android:padding="5dp"

    这行指定 FrameLayout 内部的元素padding。这个padding同时生效在方形和圆形屏幕上。在方形屏幕上总的padding是20dp(15+5)、在圆形屏幕上是5dp。

  • app:layout_box="all"

    这行声明 FrameLayout 和它的子views都被放在有窗口间隔的圆形屏幕里。这行在方形屏幕上没有任何效果。