定义Layouts
最后更新于:2022-04-01 01:41:51
> 编写: [roya](https://github.com/RoyaAoki) 原文:[https://developer.android.com/training/wearables/ui/layouts.html](https://developer.android.com/training/wearables/ui/layouts.html)
可穿戴设备使用与手持Android设备同样的布局技术,但需要有具体的约束来设计。不要以一个手持app的角度开发功能和UI以期待提供一个好的体验。关于如何设计优秀的可穿戴apps的更多信息,请阅读[Android Wear Design Guidelines](https://developer.android.com/design/wear/index.html)。
当你为Android Wear apps创建layouts时,你需要同时考虑方形和圆形屏幕的设备。在圆形Android Wear设备上所有放置在靠近屏幕边角的内容会被剪裁掉,所以为方形屏幕设计的layouts不能在圆形设备上很好的工作。对这类问题是示范请查看这个视屏[Full Screen Apps for Android Wear](https://www.youtube.com/watch?v=naf_WbtFAlY)。
举个例子,figure 1展示了下面的layout在圆形和方形屏幕上看起来是怎样的:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-28_55b7247364dd8.png)
**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](https://developer.android.com/reference/android/support/wearable/view/package-summary.html)查看Wearable UI类库。
### 为方形和圆形屏幕指定不同的Layouts
在Wearable UI库中的**WatchViewStub**类允许你为方形和圆形屏幕指定不同的layouts。这个类会在运行时检查屏幕形状后inflates符合的layout。
在你的app中使用这个类以应对不用和的屏幕形状:
- 在你的[activity](# "An activity represents a single screen with a user interface.")'s layout以WatchViewStub为主元素。
- 为方形屏幕指定一个layout解释文件使用rectLayout属性。
- 为圆形屏幕指定一个layout解释文件使用roundLayout属性。
定义你的[activity](# "An activity represents a single screen with a user interface.")'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](# "An activity represents a single screen with a user interface.")中inflate这个layout:
~~~
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wear);
}
~~~
然后为方形和圆形屏幕创建不同的layout描述文件,在这个例子中,你需要创建文件 _res/layout/rect_activity_wear.xml_ 和 _res/layout/round_activity_wear.xml_ 。像创建手持apps的layouts一样定义这些layouts,但同时考虑可穿戴设备的限制。系统会在运行时以屏幕形状inflates适合的layout。
### 取得layout views
你为方形或圆形屏幕定义的layouts在WatchViewStub检查完屏幕形状之前不会被inflated。所以你的app不能立即取得它们的views。为了取得这些views,你需要在你的[activity](# "An activity represents a single screen with a user interface.")中设置一个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](https://developer.android.com/reference/android/widget/FrameLayout.html)允许你定义一个同时适配方形和圆形屏幕的layout。这个类适用于需要根据屏幕形状插入间隔的情况并允许你简单的对齐views在屏幕边缘或中心。
figure 2中,在 **BoxInsetLayout** 里的灰色方形区域会在圆形屏幕里应用所需的窗口间隔后自动放置child views。为了显示在这个区域内,子views需要具体声明附加属性 _layout_box_ 为这些值:
- 一个_top_, _bottom_, _left_, _right_的复合属性。比如 _"left|top"_ 说明子view的左和上边缘如figure 2。
- _all_ 说明子view的内容在灰色方形内如figure 2。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-28_55b7247376090.png)
**Figure 2.**_在圆形屏幕上的窗口间隔_
在方形屏幕上,窗口间隔为0、 _layout_box_ 属性会被忽略。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-07-28_55b7247381f42.png)
**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都被放在有窗口间隔的圆形屏幕里。这行在方形屏幕上没有任何效果。