
Wear UI
智能手表相對手機(jī)來說,由于使用場景不同,且屏幕較小,所以應(yīng)用的設(shè)計、交互和手機(jī)是有些區(qū)別的。相對來說,布局會更簡潔,更多地使用滑動手勢進(jìn)行操作。
為此,在 Wear OS 上,官方提供了一系列新的控件和交互,通過它們,我們可以很方便地打造出一個適合手表交互的應(yīng)用。
添加依賴
下面用到的控件都來自 Wear 控件庫,需要在 build.gradle 文件中添加以下依賴:
implementation 'com.android.support:wear:28.0.0'
布局
常見的表盤有方形和圓形兩種,使用普通布局的情況下,可能會出現(xiàn)這種情況:
為了使圓形表盤上的內(nèi)容不超出邊界,同時兼容方形表盤,我們可以使用 BoxInsetLayout 這個布局:
<android.support.wear.widget.BoxInsetLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:boxedEdges="all">
<...>
</FrameLayout>
</android.support.wear.widget.BoxInsetLayout>
這樣可以在保證方形表盤不受影響的情況下,圓形布局的內(nèi)容,不會超過顯示邊界:
導(dǎo)航抽屜欄
為了節(jié)省寶貴的顯示空間,通常手表應(yīng)用是沒有標(biāo)題欄的,在使用 ViewPager 的時候,也沒有 TabLayout 的顯示,但因此我們無法很好的確認(rèn)當(dāng)前頁面。
導(dǎo)航欄 WearableNavigationDrawerView 就是用來解決這個問題的,我們先看看它的效果:
從手表頂部向下滑,會出現(xiàn)一個導(dǎo)航欄,顯示當(dāng)前頁面的圖標(biāo)和標(biāo)題。當(dāng)存在多個頁面時,通過左右滑動它來切換頁面。
下面來看看它的用法,我們修改布局文件,使用 WearableDrawerLayout 作為根布局,添加導(dǎo)航欄控件:
<android.support.wear.widget.drawer.WearableNavigationDrawerView
android:id="@+id/navigation_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navigationStyle="multiPage"/>
當(dāng)存在多個頁面時,需要添加 app:navigationStyle="multiPage" 這個屬性。
和 ViewPager 類似,我們需要給它設(shè)置一個適配器,設(shè)置每個頁面的圖標(biāo)和標(biāo)題,像這樣:
class MainDrawerAdapter(context: Context) :
WearableNavigationDrawerView.WearableNavigationDrawerAdapter() {
private val mContext = context
override fun getItemText(pos: Int): CharSequence {
return when (pos) {
0 -> "第一頁"
else -> "第二頁"
}
}
override fun getItemDrawable(pos: Int): Drawable {
return when (pos) {
0 -> ContextCompat.getDrawable(mContext, R.drawable.icon_one)!!
else -> ContextCompat.getDrawable(mContext, R.drawable.icon_two)!!
}
}
override fun getCount(): Int {
return 2
}
}
然后在 Activity 中設(shè)置:
navigation_drawer.setAdapter(MainDrawerAdapter(this))
navigation_drawer.controller.peekDrawer()
navigation_drawer.addOnItemSelectedListener { pos ->
// TODO 切換頁面
}
這里面的 controller.peekDrawer() 是讓導(dǎo)航欄在頂部露出一小部分,提示用戶這里是有東西可以下滑的,也可以調(diào)用 controller.closeDrawer() 完全隱藏導(dǎo)航欄。
操作抽屜欄
當(dāng)需要對當(dāng)前頁面進(jìn)行一些操作的時候,但頁面里又沒有空間再放按鈕了怎么辦?既然可以從頂部下拉出導(dǎo)航欄,要不在底部上拉出一個操作欄?操作欄 WearableActionDrawerView 就是用來做這個的。
通過給操作欄設(shè)置 menu 文件,它會以列表的形式展示可操作項,布局中這么寫:
<android.support.wear.widget.drawer.WearableActionDrawerView
android:id="@+id/action_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:actionMenu="@menu/action_drawer_menu"/>
代碼中使用:
action_drawer.controller.peekDrawer()
action_drawer.setOnMenuItemClickListener { item ->
// TODO 點擊菜單
true
}
和頂部導(dǎo)航欄類似,controller.peekDrawer() 會在底部露出一小部分操作欄,如果當(dāng)前頁面是一個列表,這一部分會在列表滑動時隱藏,在列表到頂部和底部時顯示:
露出部分默認(rèn)會顯示操作欄第一項的圖標(biāo),可以在布局中添加 app:showOverflowInPeek="true",讓它顯示豎直三個點的省略圖標(biāo)。
自定義抽屜欄
導(dǎo)航欄 WearableNavigationDrawerView 和 操作欄 WearableActionDrawerView
用起來很簡單,但是它們的樣式是固定的,一個只能顯示圖標(biāo)加標(biāo)題,一個只能顯示 menu 格式的列表。
這兩個控件都繼承自 WearableDrawerView,所以兩者都可以通過 WearableDrawerView 來實現(xiàn)自定義樣式。下面是一個簡單的自定義底部抽屜欄布局:
<android.support.wear.widget.drawer.WearableDrawerView
android:id="@+id/action_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
app:drawerContent="@+id/drawer_content"
app:peekView="@+id/peek_view">
<FrameLayout
android:id="@+id/drawer_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/layout_bottom_drawer"/>
</FrameLayout>
<FrameLayout
android:id="@+id/peek_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:orientation="horizontal">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/icon_omit"
tools:ignore="ContentDescription"/>
</FrameLayout>
</android.support.wear.widget.drawer.WearableDrawerView>
通過 layout_gravity 來設(shè)置抽屜欄是在頂部還是底部。它包裹了抽屜欄的主視圖 drawer_content 和關(guān)閉時露出部分的視圖 peek_view。這樣我們就可以在 layout_bottom_drawer 中設(shè)置自己想要的布局了,其他用法都和上面是一樣的。
確認(rèn)動畫
當(dāng)處理完某個業(yè)務(wù)之后,我們通常需要給用戶一個處理成功或失敗的提示,在 Wear OS 上,我們可以用一個 Activity 來展示確認(rèn)動畫。
ConfirmationActivity 是官方提供的用來展示確認(rèn)動畫的 Activity。
用起來也很簡單,先在 manifest 文件中注冊:
<manifest>
<application>
...
<activity
android:name="android.support.wearable.activity.ConfirmationActivity">
</activity>
</application>
</manifest>
需要顯示確認(rèn)的時候,通過傳參跳轉(zhuǎn)就好了:
val intent = Intent(this, ConfirmationActivity::class.java)
intent.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.SUCCESS_ANIMATION)
intent.putExtra(ConfirmationActivity.EXTRA_MESSAGE, message)
startActivity(intent)
這里面,EXTRA_ANIMATION_TYPE 是動畫類型,它有以下三個可選項:
- SUCCESS_ANIMATION
- FAILURE_ANIMATION
- OPEN_ON_PHONE_ANIMATION
EXTRA_MESSAGE 則是要顯示的文字內(nèi)容。
環(huán)形進(jìn)度條
CircularProgressLayout 是一個環(huán)形的進(jìn)度條,通常用它包裹一個圓形按鈕:
可以用它來做防誤觸,用戶點擊按鈕后,允許在進(jìn)度條走完之前,點擊取消操作。
我們把它添加到布局中:
<android.support.wear.widget.CircularProgressLayout
android:id="@+id/circular_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
app:backgroundColor="@color/darkblue"
app:colorSchemeColors="@color/lightblue"
app:strokeWidth="4dp">
<ImageView
android:id="@+id/image_view"
android:src="@drawable/cancel"
android:layout_width="40dp"
android:layout_height="40dp" />
</android.support.wear.widget.CircularProgressLayout>
對 CircularProgressLayout 的監(jiān)聽和操作如下:
// 監(jiān)聽進(jìn)度
circular_progress.setOnTimerFinishedListener {
// TODO 進(jìn)度完成
}
// 設(shè)置進(jìn)度總時間
circular_progress.totalTime = 1000
// 開始計時
circular_progress.startTimer()
// 結(jié)束計時
circular_progress.stopTimer()
列表
如果對比方形表盤和圓形表盤的手表,他們的應(yīng)用列表界面是這樣的:
在圓形表盤上,列表是沿著表盤左邊,曲線排列滾動的。這就是列表控件 WearableRecyclerView 實現(xiàn)的效果。
WearableRecyclerView 繼承自 RecyclerView,所以基本用法都是一樣的。
在布局中加入:
<android.support.wear.widget.WearableRecyclerView
android:id="@+id/wearable_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
代碼中設(shè)置:
// 使列表上的第一項和最后一個項在屏幕上垂直居中對齊
wearable_recycler_view.isEdgeItemsCenteringEnabled = true
// 使用 WearableLinearLayoutManager 管理布局
wearable_recycler_view.layoutManager = WearableLinearLayoutManager(this)
如果想自定義別的滾動效果,我們可以通過拓展 WearableLinearLayoutManager.LayoutCallback 來實現(xiàn),這里就不展開說了。