是時候來了解android7了:多窗口支持

這篇文章開始, 我們來了解一下Android 7的一些新特性, 話說今年android 7預覽版本來的比以往都稍早一些, 這樣對于我們開發者來說算是一個好消息, 我們可以有充足的時間來看新版android的一些特性, 讓我們的應用更快的支持到android 7. 前段時間android 7發送了最終預覽版本, 這也表示現在的sdk已經是最終的sdk了, 所以我們從現在開始, 完全可以讓應用支持到android 7了.

今天的這篇文章我們來介紹一下在android 7上最為直觀的一個特性-多窗口支持, 當然也可以叫他分屏模式. 有了這個特性媽媽再也不用擔心我應用間切換的煩惱了, 那什么多窗口模式呢? 其實在很多國產機器上早就已經支持多窗口了, 只不過這次android 7標準化了多窗口模式, 這對我們開發者來說, 可以算是天大的好消息. 廢話那么說, 我們還沒看到多窗口模式什么樣呢? 下面一張圖來體驗一下.


1.png

讓我們的應用支持多窗口模式

如何讓我們的應用支持多窗口模式呢? 其實android 7是默認開啟多窗口模式的, 不過如果你用低于android 7的sdk構建的應用, 會在多窗口模式下發出一個警告. 那如何讓我們的應用禁用多窗口模式呢? 畢竟好多人還是不喜歡讓自己的應用和別人分享屏幕的(比如QQ), 這個也很簡單, 只需要在清單文件的application或者activity中添加 android:resizeableActivity="false" 就ok了(目測, 接下來大多數國產APP中都會有這條屬性).

多窗口模式的一些配置

禁用歸禁用, 但是對于我們開發者來說, 還是要繼續了解一下多窗口模式的, 那接下來我們來看一下, 在多窗口模式中又會多哪些屬性. 在清單文件中我們配置activity的地方, 又多了一個layout節點, 這個節點的屬性不多, 主要是用來配置多窗口模式下的一些屬性的. 下面我們首先來看看如何配置, 然后來說說都是什么作用:

<activity android:name=".MyActivity">
    <layout
          android:defaultHeight="500dp"
          android:defaultWidth="500dp"
          android:gravity="bottom|end"
          android:minimalHeight="200dp"
          android:minimalWidth="200dp" />
</activity>

很簡單,就是多了一個layout節點, 我們來看看他的屬性.

  1. android:defaultHeight 這條是配置多窗口模式下默認的高度.
  2. android:defaultWidth 這條是配置多窗口模式下默認的寬度.
  3. android:gravity 這條是配置多窗口模式下activity的初始位置. (注意:這條語句在我測試過程中發現貌似沒起到作用)
  4. android:minimalHeight 這條是配置多窗口模式下最小的高度. (注意:這條語句在我測試過程中發現配置后直接編譯不了)
  5. android:minimalWidth 這條是配置多窗口模式下最小的寬度. (注意:這條語句在我測試過程中發現配置后直接編譯不了)

其實, 就算我們的應用要支持多窗口模式, 上面的layout節點我們也是完全可以忽略的(而且我感覺大部分情況下是要忽略的)

還是看看生命周期

其實, 多窗口本身還是很簡單的, 我們最關心的還是activity在多窗口模式下的生命周期, 下面我們就用一段demo來看一下在多窗口模式下activity的生命周期.

@Override
protected void onCreate(Bundle savedInstanceState) {
    prntLog("onCreate");
}

@Override
protected void onStart() {
    prntLog("onStart");
    super.onStart();
}

@Override
protected void onResume() {
    prntLog("onResume");
    super.onResume();
}

@Override
protected void onPause() {
    prntLog("onPause");
    super.onPause();
}

@Override
protected void onStop() {
    prntLog("onStop");
    super.onStop();
}

@Override
protected void onDestroy() {
    prntLog("onDestory");
    super.onDestroy();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    prntLog("onSaveInstanceState");
    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    prntLog("onRestoreInstanceState");
    super.onRestoreInstanceState(savedInstanceState);
}

@Override
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
    prntLog("onMultiWindowModeChanged:" + isInMultiWindowMode);
    prntLog("isInMultiWindowMode:" + isInMultiWindowMode());
    super.onMultiWindowModeChanged(isInMultiWindowMode);
}

private void prntLog(String log) {
    Log.d("MainActivity", log);
}

在開始之前, 我們發現有一個回調onMultiWindowModeChanged是我們不太熟悉的, 這個回調是為了多窗口模式新增的一個, 在進入或者退出多窗口模式, 這個回調會執行, 而且, 我們還可以用過isInMultiWindowMode()方法來判斷當前activity是否在多窗口模式下. 接下來, 我們來演示一下生命周期吧.

首先是進入多窗口模式(進入多窗口模式的方法是長按手機上的overview鍵)

D/MainActivity: onMultiWindowModeChanged:true
D/MainActivity: isInMultiWindowMode:true
D/MainActivity: onPause
D/MainActivity: onSaveInstanceState
D/MainActivity: onStop
D/MainActivity: onDestory
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onRestoreInstanceState
D/MainActivity: onResume
D/MainActivity: onPause

從log中可以發現, 在進入多窗口模式時, 首先回調的是onMultiWindowModeChanged方法, 然后很令人沮喪的是我們的activity銷毀了,并且調用了onSaveInstanceState方法, 然后activit啟動, 其實就是我們activity重啟了.

那退出多窗口模式呢?

D/MainActivity: onSaveInstanceState
D/MainActivity: onStop
D/MainActivity: onDestory
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onRestoreInstanceState
D/MainActivity: onResume
D/MainActivity: onPause
D/MainActivity: onMultiWindowModeChanged:false
D/MainActivity: isInMultiWindowMode:false
D/MainActivity: onResume

首先是一個配置變化銷毀的過程, 然后是一個恢復的過程, 并且回調了onMultiWindowModeChanged方法, 此時的isInMultiWindowMode
是false.

繼續看生命周期, 如果我們的焦點從一個activity中切換到了和它同處于多窗口模式下的另外一個activity呢?

D/MainActivity: onPause
D/SecondActivity: onResume

此時當前activity會暫停, 新獲取角度的activity回調onResume, 在這里官網還有一個notice, 比如我們之前是在onPause中暫停視頻播放, 在這種情況下, 失去焦點后就暫停了, 顯然這不是很好的用戶體驗, 我們需要把視頻的暫停和繼續放到onStop和onStart中.

啟動activity

現在我們在來學習下如何在多窗口模式下啟動activity. 這樣分兩種情況了, 一種在是當前棧中啟動, 另一種是在新的棧中啟動. 對于第一種情況, 很簡單, 就是在當前窗口中啟動新的activity, 而第二種情況, 我們可以指定在同級窗口下啟動, 只需要給intent設置一個FLAG_ACTIVITY_LAUNCH_ADJACENT flag就ok.

例如下面的代碼:

Intent intent = new Intent(this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

上面的代碼我們會在另外一個窗口啟動新的activity


2.png

另外, 我們還可以制定新啟動的activity的大小.

Rect bounds = new Rect(500, 300, 100, 0);
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchBounds(bounds);

Intent intent = new Intent(this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT|Intent.FLAG_ACTIVITY_NEW_TASK);
ActivityCompat.startActivity(this, intent, options.toBundle());

跨activity拖拽

從android 4.0開始, android就已經支持activity內的內容拖拽了, 現在在多窗口模式下, android增強了拖拽功能, 另它在多窗口模式下可以在activity間實現內容的拖拽, 不過在activity間也僅限于內容的拖拽, 對view的跨activity拖拽還是不可以的. 現在我們在MainActivity和SecondActivity之前來模擬一下跨activity拖拽內容.

// MainActivity
Button view = (Button) findViewById(R.id.button);
view.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View view) {
        ClipData data = ClipData.newPlainText(view.getClass().getName(),
                ((Button) view).getText());
        View.DragShadowBuilder builder = new View.DragShadowBuilder(view);
        view.startDragAndDrop(data, builder, view, View.DRAG_FLAG_GLOBAL);
        return true;
    }
});

這里我們監聽button的長按事件, 在長按事件中, 首先我們用button的文本構建一個ClipData對象. 然后調用view.startDragAndDrop方法來啟動拖拽. 這里要注意一下最后一個參數View.DRAG_FLAG_GLOBAL, 這個flag表示我們可以跨activity進行拖拽.

接著我們來看看SecondActivity如何處理拖拽事件.

final TextView content = (TextView) findViewById(R.id.content);
findViewById(R.id.container).setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View view, DragEvent dragEvent) {
    switch (dragEvent.getAction()) {
        case DragEvent.ACTION_DRAG_STARTED:
            prntLog("drag started");
            break;
        case DragEvent.ACTION_DRAG_ENTERED:
            prntLog("drag entered");
            break;
        case DragEvent.ACTION_DROP:
            ClipData.Item item = dragEvent.getClipData().getItemAt(0);
            content.setText(item.getText());
            break;
        case DragEvent.ACTION_DRAG_ENDED:
            prntLog("drag entered");
            break;
    }
    return true;
}
});

這里首先我們拿到根布局(這里就先不要糾結根布局到底是誰了, 這里的根布局指的是content_view的根布局), 然后給它設置OnDragListener的監聽, 在ACTION_DROP時候我們通過dragEvent.getClipData().getItemAt(0)拿到拖拽的item, 然后通過getText()方法獲取到內容, 并且設置到TextView上顯示.

來看看效果:


3.gif

ok, 到現在為止android 7的多窗口模式我們就介紹完了, 這些內容大家有點印象就可以, 畢竟在我們日常的工作中基本一個android:resizeableActivity="false"就可以了.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容