我們都知道,在最新的Android N系統中,加入了一個新的功能,就是多窗口模式。多窗口模式允許我們在屏幕上顯示兩個窗口,每個窗口顯示的內容不同,也就是說,我們可以一遍看電視劇,一邊聊微信。
這里我們通過官方提供的一個Demo來了解一下,作為開發者,怎么給我們的App也適配多窗口模式。
這里給出代碼github地址,需要的話可以clone下來邊看邊了解:
https://github.com/googlecodelabs/getting-ready-for-android-n
根據指導文檔這里分為幾個部分:
1. 多窗口模式的開關
2. 多窗口模式適配
3. 多窗口模式中打開新的窗口處理
我們一個一個來了解下:
1. 多窗口模式的開關
默認情況下,我們的App都是允許多窗口的,但是,如果沒有進行屬性的設置,會系統會拋出一個提示這個應用可能不支持多窗口模式
那么,如果我們的應用要支持這個模式並且不讓這個消息彈出來,要怎么做呢?
很簡單,只需要在Activity聲明的時候加入一個屬性resizeableActivity,並且設置其值為true即可:
<activity android:name=".MainActivity" android:resizeableActivity="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
這個屬性的設置會導致三種情況:
① 如果不聲明這個屬性,那么默認允許進入多窗口模式,但是會有上面圖片的提示(第一次運行的時候)
② 如果聲明了這個屬性,並設置值為true,那么允許進入多窗口模式,並且不會提示
③ 如果聲明了這個屬性,並設置值為false,那么不允許進入多窗口模式,只允許全屏顯示
2. 多窗口模式的適配
當我們允許App進入多窗口模式之后,App只能占據屏幕的一部分,假設我們的App運行的界面如下(官方Demo):
可以看到,在App的上半部分是一個藍色的圖片背景,在上面顯示了當前的天氣狀況,但是如果我們不進行適應,那么進入了多窗口模式之后,這個部分的內容就會幾乎占滿整個窗口,這個時候我們就需要進行一下適配,當進入多窗口模式之后更換掉這一個布局,將內容進行重新排版,以便顯示更多的內容。
默認情況下的布局:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="wrap_content" 4 android:gravity="center_vertical" 5 android:minHeight="?android:attr/listPreferredItemHeight" 6 android:orientation="horizontal" 7 android:background="@drawable/today_touch_selector"> 8 9 <LinearLayout 10 android:layout_height="wrap_content" 11 android:layout_width="0dp" 12 android:layout_weight="7" 13 android:layout_marginTop="16dp" 14 android:layout_marginBottom="16dp" 15 android:layout_marginLeft="60dp" 16 android:orientation="vertical"> 17 18 <TextView 19 android:id="@+id/list_item_date_textview" 20 android:layout_width="match_parent" 21 android:layout_height="wrap_content" 22 android:textAppearance="?android:textAppearanceLarge" 23 android:fontFamily="sans-serif-condensed" 24 android:textColor="@color/white" /> 25 26 <TextView 27 android:id="@+id/list_item_high_textview" 28 android:layout_width="match_parent" 29 android:layout_height="wrap_content" 30 android:textSize="72sp" 31 android:fontFamily="sans-serif-light" 32 android:textColor="@color/white" /> 33 34 <TextView 35 android:id="@+id/list_item_low_textview" 36 android:layout_width="match_parent" 37 android:layout_height="wrap_content" 38 android:textColor="@color/white" 39 android:textSize="36sp" 40 android:layout_marginLeft="8dp"/> 41 </LinearLayout> 42 43 <LinearLayout 44 android:layout_height="wrap_content" 45 android:layout_width="0dp" 46 android:layout_weight="5" 47 android:layout_marginRight="16dp" 48 android:orientation="vertical" 49 android:gravity="center_horizontal|bottom"> 50 51 <ImageView 52 android:id="@+id/list_item_icon" 53 android:layout_width="wrap_content" 54 android:layout_height="wrap_content" 55 android:layout_gravity="center_horizontal"/> 56 57 <TextView 58 android:id="@+id/list_item_forecast_textview" 59 android:layout_width="wrap_content" 60 android:layout_height="wrap_content" 61 android:fontFamily="sans-serif-condensed" 62 android:layout_gravity="center_horizontal" 63 android:textAppearance="?android:textAppearanceLarge" 64 android:textColor="@color/white"/> 65 </LinearLayout>
這里主要看到,根布局中設置了背景圖,這個圖片就是那個我們看到藍色的那一張,里面定義了一些TextView來顯示信息,定義了一個ImageView來顯示天氣的圖標,簡單了解下布局即可。
因為這里用到Fragment,可能直接看工程不會很清晰,我們打開res下的values-sw400dp,然后打開里面的refs.xml文件,內容如下:
<resources> <item type="layout" name="fragment_detail">@layout/fragment_detail_wide</item> <item type="layout" name="list_item_forecast_today">@layout/list_item_forecast_today_big</item> </resources>
我們將光標移動到第二個Item的name屬性的值中,然后按下Alt+F7找到項目中用到這個value的地方:
可以看到,只有一個地方使用了這個value,我們點進去可以看到,這個布局其實是被用在了一個CursorAdapter中,這里應該就知道了,這個布局是被當作一個ListView的頭部來使用。
我們先不管工程是如何實現的,我們只需要知道這個布局會被用在界面中的ListView中的頭部中就可以了。這個時候我們再看看這個folder的文件名values-sw400dp,sw400dp就表明了這個value是在屏幕最短邊大於等於400dp的時候生效(前提是有其他不同的value文件夾)。
因為在多窗口模式的情況下,每個窗口分的大小是允許用戶控制的(可以通過中間的滑動來改變兩個窗口的大小),而當用戶將滑塊向上滑動,有可能會會導致最短邊小於400dp,因此,我們可以在工程的res下創建一個更小的values文件名為values-sw220dp,接着再創建一個布局文件(里面的控件id必須和上面的布局一致,這里Demo中已經給出了一個布局,名字是list_item_forecast),接着在values-sw220dp下創建一個refs.xml的文件,文件內容如下:
<resources> <item type="layout" name="list_item_forecast_today">@layout/list_item_forecast</item> </resources>
運行的效果如下所示,可以看到,當屏幕最短邊大於220dp而小於400dp的時候,會顯示如右圖的布局:
這里還要注意一個問題,如果我們按照上面定義的220dp來命名,那么如果屏幕被繼續向上拉,會導致最小邊小於220dp,這個時候又會恢復到左邊的這個布局,這里解決辦法是把220dp設置的更小(如100dp)即可。
這里補充一下效果:
3. 在多窗口中打開一個Activity
在官方的Demo中,可以通過右上角的菜單中的“Map Location”來打開地圖App,這個時候如果不加以設置,地圖App會在當前的這個小窗口中打開。
那么我們可不可以讓系統在下面的這個窗口打開呢?因為考慮到用戶可以不用跳出我們的App而對地圖App進行操作,谷歌官方也是提供了這個功能,而且比較簡單。
我們找到ForecastFragment.class這個類,定位到206行,代碼如下:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(geoLocation);
很明顯這里是要打開一個Activity,接着我們只需要給這個Intent設置一個標簽,完整代碼如下:
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(geoLocation); intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
這個時候,我們再此運行App並打開地圖App,會發現,地圖App會在另一個窗口中被打開。