久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    Android N App分屏模式完全解析(下)

     android之情殤 2017-05-28


    轉(zhuǎn)載地址:http://unclechen./2016/03/12/Android-N-App%E5%88%86%E5%B1%8F%E6%A8%A1%E5%BC%8F%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90-%E4%B8%8B%E7%AF%87/


    上篇中,介紹了什么是App分屏模式,以及如何設(shè)置我們的App來進(jìn)入分屏模式。這次我們看一下,作為開發(fā)者,我們應(yīng)該如何讓自己的App進(jìn)入分屏模式,當(dāng)App進(jìn)入分屏模式時,我們注意哪些問題。

    簡單地說,我認(rèn)為除了保證分屏?xí)rApp功能、性能正常以外,我們需要重點學(xué)習(xí) 如何在分屏模式下打開新的Activity 以及 如何實現(xiàn)跨App/Activity的拖拽功能

    用分屏模式運行你的App

    Android N中新增了一些方法來支持App的分屏模式。同時在分屏模式下,也禁用了App一些特性。

    分屏模式下被禁用的特性

    • 自定義系統(tǒng)UI,例如分屏模式下無法隱藏系統(tǒng)的狀態(tài)欄。
    • 無法根據(jù)屏幕方向來旋轉(zhuǎn)App的界面,也就是說android:screenOrientation屬性會被系統(tǒng)忽略。

    分屏模式的通知回調(diào)、查詢App是否處于分屏狀態(tài)

    最新的Android N SDK中,Activity類中增加了下面的方法。

    • inMultiWindow():返回值為boolean,調(diào)用此方法可以知道App是否處于分屏模式。
    • inPictureInPicture():返回值為boolean,調(diào)用此方法可以知道App是否處于畫中畫模式。

    注意:畫中畫模式其實是一個特殊的分屏模式,如果mActivity.inPictureInPicture()返回true,那么mActivity.inMultiWindow()一定也是返回true

    • onMultiWindowChanged(boolean inMultiWindow):當(dāng)Activity進(jìn)入或者退出分屏模式時,系統(tǒng)會回調(diào)這個方法來通知開發(fā)者。回調(diào)的參數(shù)inMultiWindow為boolean類型,如果inMultiWindow為true,表示Activity進(jìn)入分屏模式;如果inMultiWindow為false,表示退出分屏模式。
    • onPictureInPictureChanged(boolean inPictureInPicture):當(dāng)Activity進(jìn)入畫中畫模式時,系統(tǒng)會回調(diào)這個方法。回調(diào)參數(shù)inPictureInPicturetrue時,表示進(jìn)入了畫中畫模式;inPictureInPicturefalse時,表示退出了畫中畫模式。

    Fragment類中,同樣增加了以上支持分屏模式的方法,例如Fragment.inMultiWindow()

    如何進(jìn)入畫中畫模式

    調(diào)用Activity類的enterPictureInPicture()方法,可以使得我們的App進(jìn)入畫中畫模式。如果運行的設(shè)備不支持畫中畫模式,調(diào)用這個方法將不會有任何效果。更多畫中畫模式的資料,請參考picture-in-picture

    在分屏模式下打開新的Activity

    當(dāng)你打開一個新的Activity時,只需要給Intent添加Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT,系統(tǒng)將嘗試將它設(shè)置為與當(dāng)前的Activity共同以分屏的模式顯示在屏幕上。

    注意:這里只是嘗試,但這不一定是100%生效的,前一篇博客里也說過,假如新打開的Activity的android:resizeableActivity屬性設(shè)置為false,就會禁止分屏瀏覽這個Activity。所以系統(tǒng)只是嘗試去以分屏模式打開一個新的Activity,如果條件不滿足,將不會生效!此外,我實際用Android N Preview SDK實踐的時候發(fā)現(xiàn)這個FLAG實際得值是FLAG_ACTIVITY_LAUNCH_ADJACENT,并非是FLAG_ACTIVITY_LAUNCH_TO_ADJACENT

    當(dāng)滿足下面的條件,系統(tǒng)會讓這兩個Activity進(jìn)入分屏模式:

    • 當(dāng)前Activity已經(jīng)進(jìn)入到分屏模式。
    • 新打開的Activity支持分屏瀏覽(即android:resizeableActivity=true)。

    此時,給新打開的Activity,設(shè)置intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); 才會有效果。

    two-acts

    建議參考官方的Sample:MultiWindow Playground Sample

    那么為何還需要添加FLAG_ACTIVITY_NEW_TASK?看一下官方解釋:

    注意:在同一個Activity返回棧中,打開一個新的Activity時,這個Activity將會繼承上一個Activity所有和分屏模式有關(guān)的屬性。如果你想要在一個獨立的窗口以分屏模式打開一個新的Activity,那么必須新建一個Activity返回棧。

    此外,如果你的設(shè)備支持自由模式(官方名字叫freeform,暫且就這么翻譯它,其實我認(rèn)為這算也是一種尺寸更自由的分屏模式,上一篇博客里提到過如果設(shè)備廠商支持用戶可以自由改變Activity的尺寸,那么就相當(dāng)于支持自由模式,這將比普通的分屏模式更加自由),打開一個Activity時,還可通過ActivityOptions.setLaunchBounds()來指定新的Activity的尺寸和在屏幕中的位置。同樣,這個方法也需要你的Activity已經(jīng)處于分屏模式時,調(diào)用它才會生效。

    支持拖拽

    上一篇博客里也提到過,現(xiàn)在我們可以實現(xiàn)在兩個分屏模式的Activity之間拖動內(nèi)容了。Android N Preview SDK中,View已經(jīng)增加支持Activity之間拖動的API。具體的類和方法,可以參考N Preview SDK Reference,主要用到下面幾個新的接口:

    • View.startDragAndDrop():View.startDrag() 的替代方法,需要傳遞View.DRAG_FLAG_GLOBAL來實現(xiàn)跨Activity拖拽。如果需要將URI權(quán)限傳遞給接收方Activity,還可以根據(jù)需要設(shè)置View.DRAG_FLAG_GLOBAL_URI_READ或者View.DRAG_FLAG_GLOBAL_URI_WRITE
    • View.cancelDragAndDrop():由拖拽的發(fā)起方調(diào)用,取消當(dāng)前進(jìn)行中的拖拽。
    • View.updateDragShadow():由拖拽的發(fā)起方調(diào)用,可以給當(dāng)前進(jìn)行的拖拽設(shè)置陰影。
    • android.view.DropPermissions:接收方App所得到的權(quán)限列表。
    • Activity.requestDropPermissions():傳遞URI權(quán)限時,需要調(diào)用這個方法。傳遞的內(nèi)容存儲在DragEvent中的ClipData里。返回值為前面的android.view.DropPermissions

    下面是我自己寫的一個demo,實現(xiàn)了在分屏模式下,把一個Activity中ImageView中保存的內(nèi)容到另外一個Activity中進(jìn)行顯示。實際應(yīng)用中,可以還可以傳遞圖片的url或者Bitmap對象。

    drag-drop

    上圖是一個最基本的例子,實現(xiàn)了把MainActivity中的圖片保存的內(nèi)容,拖拽到SecondActivity中。實現(xiàn)步驟如下:

    在MainActivity中,發(fā)起拖拽。

    // 1.首先我們在分屏模式下,打開自己App中的SecondActivity
    findViewById(R.id.launch_second_activity).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
            });
            
    // 2.然后我們在MainActivity中發(fā)出拖拽事件
    imageView = (ImageView) findViewById(R.id.img);
            /** 拖拽的發(fā)送方Activity和ImageView */
            imageView.setTag("I'm a ImageView from MainActivity");
            imageView.setOnTouchListener(new View.OnTouchListener() {
    
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                        /** 構(gòu)造一個ClipData,將需要傳遞的數(shù)據(jù)放在里面 */
                        ClipData.Item item = new ClipData.Item((CharSequence) view.getTag());
                        String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
                        ClipData dragData = new ClipData(view.getTag().toString(), mimeTypes, item);
                        View.DragShadowBuilder shadow = new View.DragShadowBuilder(imageView);
                        /** startDragAndDrop是Android N SDK中的新方法,替代了以前的startDrag,flag需要設(shè)置為DRAG_FLAG_GLOBAL */
                        view.startDragAndDrop(dragData, shadow, null, View.DRAG_FLAG_GLOBAL);
                        return true;
                    } else {
                        return false;
                    }
                }
            });
    

    SecondActivity中,接收這個拖拽的結(jié)果,在ACTION_DROP事件中,把結(jié)果顯示出來。

    dropedText = (TextView) findViewById(R.id.text_drop);
            dropedText.setOnDragListener(new View.OnDragListener() {
                @Override
                public boolean onDrag(View view, DragEvent dragEvent) {
                    switch (dragEvent.getAction()) {
                        case DragEvent.ACTION_DRAG_STARTED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_STARTED");
                            break;
    
                        case DragEvent.ACTION_DRAG_ENTERED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_ENTERED");
                            break;
    
                        case DragEvent.ACTION_DRAG_EXITED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_EXITED");
                            break;
    
                        case DragEvent.ACTION_DRAG_LOCATION:
                            break;
    
                        case DragEvent.ACTION_DRAG_ENDED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_ENDED");
                            break;
    
                        case DragEvent.ACTION_DROP:
                            Log.d(TAG, "ACTION_DROP event");
                            /** 3.在這里顯示接收到的結(jié)果 */
                            dropedText.setText(dragEvent.getClipData().getItemAt(0).getText());
                            break;
    
                        default:
                            break;
                    }
    
                    return true;
                }
            });
    

    這里實現(xiàn)的關(guān)鍵在新增加的startDragAndDrop方法,看下官方的API文檔:

    start-drag

    清楚地提到了,發(fā)出的DragEvent能夠被所有可見的View對象接收到,所以在分屏模式下,SecondActivity可以監(jiān)聽View的onDrag事件,于是我們監(jiān)聽它!

    接著,我們看下DragEvent.ACTION_DROP事件發(fā)生的條件:

    drop-event

    當(dāng)被拖拽的View的陰影進(jìn)入到接收方View的坐標(biāo)區(qū)域,如果此時用戶松手,那么接收方View就可以接收到這個Drop事件。一目了然,我們通過拖拽ImageView到圖上的灰色區(qū)域,松手,便可以觸發(fā)DragEvent.ACTION_DROP,把數(shù)據(jù)傳到SecondActivity中了。

    其實還有更復(fù)雜的一些情況,需要調(diào)用requestDropPermissions,后續(xù)我再進(jìn)一步實踐一下。

    這個demo的地址在這里,先分享出來,后面我再接著完善它。

    在分屏模式下測試你的App

    無論你是否將自己的App適配到了Android N,或者是支持分屏模式,都應(yīng)該找個Android N的設(shè)備,來測試一下自己的App在分屏模式下會變成什么樣。

    設(shè)置你的測試設(shè)備

    如果你有一臺運行Android N的設(shè)備,它是默認(rèn)支持分屏模式的。

    如果你的App不是用Android N Preview SDK打包的

    如果你的App是用低于Android N Preview SDK打包的,且你的Activity支持橫豎屏切換。那么當(dāng)用戶在嘗試使用分屏模式時,系統(tǒng)會強(qiáng)制將你的App進(jìn)入分屏模式。(我在第一篇博客里提到過這個,Android N Preview的介紹視頻中,很多Google家的App都可以進(jìn)入分屏模式,但是打開它們的xml一看,其實targetSDKVersion = 23

    因此,如果你的App/Activity支持橫豎屏切換,那么你應(yīng)該嘗試一下讓自己的App分屏,看看當(dāng)系統(tǒng)強(qiáng)制改變你的App尺寸時,用戶是否還可以接受這種體驗。如果你的App/Activity不支持橫豎屏切換,那么你可以確認(rèn)一下,看看當(dāng)嘗試進(jìn)入分屏?xí)r,你的App是不是仍然能夠保持全屏模式。

    如果你給App設(shè)置了支持分屏模式

    如果你使用了Android N Preview SDK來開發(fā)自己的App,那么應(yīng)該按照下面的要點檢查一下自己的App。

    • 啟動App,長按系統(tǒng)導(dǎo)航欄右下角的小方塊(Google官方把這個叫做Overview Button),確保你的App可以進(jìn)入分屏模式,且尺寸改變后仍然能正常工作。
    • 啟動任務(wù)管理器(即單擊右下角的小方塊),然后長按你App的標(biāo)題欄,將它拖動到屏幕上的高亮區(qū)域。確保你的App可以進(jìn)入分屏模式,且尺寸改變后仍然能正常工作。

    這兩點在上一篇博客中介紹過,讓自己的App進(jìn)入分屏模式有三種方法。第三種方法,就是在打開自己的App時,用手指從右下角的小方塊向上滑動,這樣也可以使得正在瀏覽的App進(jìn)入分屏模式。這種方法目前屬于實驗性功能,正式版不一定保留。

    • 當(dāng)你的App進(jìn)入分屏后,通過拖動兩個App中間的分欄上面的小白線,從而改變App的尺寸,觀察App中各個UI元素是否正常顯示。
    • 如果你給自己的App/Activity設(shè)置了最小尺寸,可以嘗試在改變App尺寸時,低于這個最小尺寸,觀察App是不是會回到設(shè)定好的最小尺寸。
    • 在進(jìn)行上面幾項測試時,請同時驗證自己的App功能和性能是否正常,并注意一下自己的App在更新UI時是否花費了太長的時間。

    這幾項測試,其實主要強(qiáng)調(diào)的是,我們的App可以順利的進(jìn)入/退出分屏模式,且改變App的尺寸時,UI依然可以也非常順滑。

    這里我想多說一句,如果進(jìn)入了分屏模式,要注意下App彈出的對話框,因為屏幕被兩個App分成兩塊之后,對話框也是可以彈出兩個的。這時對話框上的UI元素可能就會變得比較小了,如果我們的代碼是寫死的大小,例如對話框是一個WebView,就需要特別注意了,搞不好顯示出來就缺了一塊了,這里需要我們做好適配。

    測試清單

    關(guān)于功能、性能方面測試,還可以按照下面的操作來進(jìn)行。

    • 讓App進(jìn)入,再退出分屏模式,確保此時App功能正常。
    • 讓App進(jìn)入分屏模式,激活屏幕上的另外一個App,讓自己的App進(jìn)入可見、paused狀態(tài)。舉了例子來講,如果你的App是一個視頻播放器,那么當(dāng)用戶點擊了屏幕上另外一個App時,你的App不應(yīng)該停止播放視頻,即使此時你的Activity/Fragment已經(jīng)接到了onPaused()回調(diào)。
    • 讓App進(jìn)入分屏模式,拖動分欄上的小白線,改變App的尺寸。請在豎屏(兩個App一上一下布局)和橫屏(兩個App一左一右布局)模式下分別進(jìn)行改變尺寸的操作。確保App不會崩潰,各項功能正常,且UI的刷新沒有花費太多時間。
    • 在短時間內(nèi)、多次、迅速地改變App尺寸,確保App沒有崩潰,且沒有發(fā)生內(nèi)存泄露。關(guān)于內(nèi)存使用方面的更詳細(xì)注意事項,請參考Investigating Your RAM Usage
    • 在不同的窗口設(shè)置的情況下,正常使用App,確保App功能正常,文字仍然可讀,其他的UI元素也沒有變得太小,用戶仍然可以舒適地操作App。

    這幾項測試,其實主要是說當(dāng)App在分屏模式下運行時,仍然可以保持性能的穩(wěn)定,不會Crash也不會OOM。

    如果你給App設(shè)置了禁止分屏模式

    如果你給App/Activity設(shè)置了android:resizableActivity="false",你應(yīng)該試試當(dāng)用戶在Android N的設(shè)備上,嘗試分屏瀏覽你的App時,它是否仍然能保持全屏模式。

    以上就是參考Google最新的multi-window進(jìn)行的實踐,總結(jié)下,我認(rèn)為有3點比較重要:

    1. 如何讓自己的App/Activity順利的進(jìn)入和退出分屏模式,可以參考處理運行時改變這一章。
    2. 如何在分屏模式下打開新的Activity,可以參考Google官方的MultiWindow Playground Sample
    3. 如何實現(xiàn)跨App/Activity的拖拽功能,可以參考Drag and Drop這一章。

    關(guān)于App分屏模式的學(xué)習(xí)就到這里了,歡迎大家一起交流。我們還發(fā)揮更多的想象力,比如是否可以利用跨應(yīng)用拖拽實現(xiàn)更方便操作,更好的用戶體驗。


    轉(zhuǎn)載地址:http://unclechen./2016/03/12/Android-N-App%E5%88%86%E5%B1%8F%E6%A8%A1%E5%BC%8F%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90-%E4%B8%8B%E7%AF%87/


    上篇中,介紹了什么是App分屏模式,以及如何設(shè)置我們的App來進(jìn)入分屏模式。這次我們看一下,作為開發(fā)者,我們應(yīng)該如何讓自己的App進(jìn)入分屏模式,當(dāng)App進(jìn)入分屏模式時,我們注意哪些問題。

    簡單地說,我認(rèn)為除了保證分屏?xí)rApp功能、性能正常以外,我們需要重點學(xué)習(xí) 如何在分屏模式下打開新的Activity 以及 如何實現(xiàn)跨App/Activity的拖拽功能

    用分屏模式運行你的App

    Android N中新增了一些方法來支持App的分屏模式。同時在分屏模式下,也禁用了App一些特性。

    分屏模式下被禁用的特性

    • 自定義系統(tǒng)UI,例如分屏模式下無法隱藏系統(tǒng)的狀態(tài)欄。
    • 無法根據(jù)屏幕方向來旋轉(zhuǎn)App的界面,也就是說android:screenOrientation屬性會被系統(tǒng)忽略。

    分屏模式的通知回調(diào)、查詢App是否處于分屏狀態(tài)

    最新的Android N SDK中,Activity類中增加了下面的方法。

    • inMultiWindow():返回值為boolean,調(diào)用此方法可以知道App是否處于分屏模式。
    • inPictureInPicture():返回值為boolean,調(diào)用此方法可以知道App是否處于畫中畫模式。

    注意:畫中畫模式其實是一個特殊的分屏模式,如果mActivity.inPictureInPicture()返回true,那么mActivity.inMultiWindow()一定也是返回true

    • onMultiWindowChanged(boolean inMultiWindow):當(dāng)Activity進(jìn)入或者退出分屏模式時,系統(tǒng)會回調(diào)這個方法來通知開發(fā)者。回調(diào)的參數(shù)inMultiWindow為boolean類型,如果inMultiWindow為true,表示Activity進(jìn)入分屏模式;如果inMultiWindow為false,表示退出分屏模式。
    • onPictureInPictureChanged(boolean inPictureInPicture):當(dāng)Activity進(jìn)入畫中畫模式時,系統(tǒng)會回調(diào)這個方法。回調(diào)參數(shù)inPictureInPicturetrue時,表示進(jìn)入了畫中畫模式;inPictureInPicturefalse時,表示退出了畫中畫模式。

    Fragment類中,同樣增加了以上支持分屏模式的方法,例如Fragment.inMultiWindow()

    如何進(jìn)入畫中畫模式

    調(diào)用Activity類的enterPictureInPicture()方法,可以使得我們的App進(jìn)入畫中畫模式。如果運行的設(shè)備不支持畫中畫模式,調(diào)用這個方法將不會有任何效果。更多畫中畫模式的資料,請參考picture-in-picture

    在分屏模式下打開新的Activity

    當(dāng)你打開一個新的Activity時,只需要給Intent添加Intent.FLAG_ACTIVITY_LAUNCH_TO_ADJACENT,系統(tǒng)將嘗試將它設(shè)置為與當(dāng)前的Activity共同以分屏的模式顯示在屏幕上。

    注意:這里只是嘗試,但這不一定是100%生效的,前一篇博客里也說過,假如新打開的Activity的android:resizeableActivity屬性設(shè)置為false,就會禁止分屏瀏覽這個Activity。所以系統(tǒng)只是嘗試去以分屏模式打開一個新的Activity,如果條件不滿足,將不會生效!此外,我實際用Android N Preview SDK實踐的時候發(fā)現(xiàn)這個FLAG實際得值是FLAG_ACTIVITY_LAUNCH_ADJACENT,并非是FLAG_ACTIVITY_LAUNCH_TO_ADJACENT

    當(dāng)滿足下面的條件,系統(tǒng)會讓這兩個Activity進(jìn)入分屏模式:

    • 當(dāng)前Activity已經(jīng)進(jìn)入到分屏模式。
    • 新打開的Activity支持分屏瀏覽(即android:resizeableActivity=true)。

    此時,給新打開的Activity,設(shè)置intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); 才會有效果。

    two-acts

    建議參考官方的Sample:MultiWindow Playground Sample

    那么為何還需要添加FLAG_ACTIVITY_NEW_TASK?看一下官方解釋:

    注意:在同一個Activity返回棧中,打開一個新的Activity時,這個Activity將會繼承上一個Activity所有和分屏模式有關(guān)的屬性。如果你想要在一個獨立的窗口以分屏模式打開一個新的Activity,那么必須新建一個Activity返回棧。

    此外,如果你的設(shè)備支持自由模式(官方名字叫freeform,暫且就這么翻譯它,其實我認(rèn)為這算也是一種尺寸更自由的分屏模式,上一篇博客里提到過如果設(shè)備廠商支持用戶可以自由改變Activity的尺寸,那么就相當(dāng)于支持自由模式,這將比普通的分屏模式更加自由),打開一個Activity時,還可通過ActivityOptions.setLaunchBounds()來指定新的Activity的尺寸和在屏幕中的位置。同樣,這個方法也需要你的Activity已經(jīng)處于分屏模式時,調(diào)用它才會生效。

    支持拖拽

    上一篇博客里也提到過,現(xiàn)在我們可以實現(xiàn)在兩個分屏模式的Activity之間拖動內(nèi)容了。Android N Preview SDK中,View已經(jīng)增加支持Activity之間拖動的API。具體的類和方法,可以參考N Preview SDK Reference,主要用到下面幾個新的接口:

    • View.startDragAndDrop():View.startDrag() 的替代方法,需要傳遞View.DRAG_FLAG_GLOBAL來實現(xiàn)跨Activity拖拽。如果需要將URI權(quán)限傳遞給接收方Activity,還可以根據(jù)需要設(shè)置View.DRAG_FLAG_GLOBAL_URI_READ或者View.DRAG_FLAG_GLOBAL_URI_WRITE
    • View.cancelDragAndDrop():由拖拽的發(fā)起方調(diào)用,取消當(dāng)前進(jìn)行中的拖拽。
    • View.updateDragShadow():由拖拽的發(fā)起方調(diào)用,可以給當(dāng)前進(jìn)行的拖拽設(shè)置陰影。
    • android.view.DropPermissions:接收方App所得到的權(quán)限列表。
    • Activity.requestDropPermissions():傳遞URI權(quán)限時,需要調(diào)用這個方法。傳遞的內(nèi)容存儲在DragEvent中的ClipData里。返回值為前面的android.view.DropPermissions

    下面是我自己寫的一個demo,實現(xiàn)了在分屏模式下,把一個Activity中ImageView中保存的內(nèi)容到另外一個Activity中進(jìn)行顯示。實際應(yīng)用中,可以還可以傳遞圖片的url或者Bitmap對象。

    drag-drop

    上圖是一個最基本的例子,實現(xiàn)了把MainActivity中的圖片保存的內(nèi)容,拖拽到SecondActivity中。實現(xiàn)步驟如下:

    在MainActivity中,發(fā)起拖拽。

    // 1.首先我們在分屏模式下,打開自己App中的SecondActivity
    findViewById(R.id.launch_second_activity).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
            });
            
    // 2.然后我們在MainActivity中發(fā)出拖拽事件
    imageView = (ImageView) findViewById(R.id.img);
            /** 拖拽的發(fā)送方Activity和ImageView */
            imageView.setTag("I'm a ImageView from MainActivity");
            imageView.setOnTouchListener(new View.OnTouchListener() {
    
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                        /** 構(gòu)造一個ClipData,將需要傳遞的數(shù)據(jù)放在里面 */
                        ClipData.Item item = new ClipData.Item((CharSequence) view.getTag());
                        String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
                        ClipData dragData = new ClipData(view.getTag().toString(), mimeTypes, item);
                        View.DragShadowBuilder shadow = new View.DragShadowBuilder(imageView);
                        /** startDragAndDrop是Android N SDK中的新方法,替代了以前的startDrag,flag需要設(shè)置為DRAG_FLAG_GLOBAL */
                        view.startDragAndDrop(dragData, shadow, null, View.DRAG_FLAG_GLOBAL);
                        return true;
                    } else {
                        return false;
                    }
                }
            });
    

    SecondActivity中,接收這個拖拽的結(jié)果,在ACTION_DROP事件中,把結(jié)果顯示出來。

    dropedText = (TextView) findViewById(R.id.text_drop);
            dropedText.setOnDragListener(new View.OnDragListener() {
                @Override
                public boolean onDrag(View view, DragEvent dragEvent) {
                    switch (dragEvent.getAction()) {
                        case DragEvent.ACTION_DRAG_STARTED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_STARTED");
                            break;
    
                        case DragEvent.ACTION_DRAG_ENTERED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_ENTERED");
                            break;
    
                        case DragEvent.ACTION_DRAG_EXITED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_EXITED");
                            break;
    
                        case DragEvent.ACTION_DRAG_LOCATION:
                            break;
    
                        case DragEvent.ACTION_DRAG_ENDED:
                            Log.d(TAG, "Action is DragEvent.ACTION_DRAG_ENDED");
                            break;
    
                        case DragEvent.ACTION_DROP:
                            Log.d(TAG, "ACTION_DROP event");
                            /** 3.在這里顯示接收到的結(jié)果 */
                            dropedText.setText(dragEvent.getClipData().getItemAt(0).getText());
                            break;
    
                        default:
                            break;
                    }
    
                    return true;
                }
            });
    

    這里實現(xiàn)的關(guān)鍵在新增加的startDragAndDrop方法,看下官方的API文檔:

    start-drag

    清楚地提到了,發(fā)出的DragEvent能夠被所有可見的View對象接收到,所以在分屏模式下,SecondActivity可以監(jiān)聽View的onDrag事件,于是我們監(jiān)聽它!

    接著,我們看下DragEvent.ACTION_DROP事件發(fā)生的條件:

    drop-event

    當(dāng)被拖拽的View的陰影進(jìn)入到接收方View的坐標(biāo)區(qū)域,如果此時用戶松手,那么接收方View就可以接收到這個Drop事件。一目了然,我們通過拖拽ImageView到圖上的灰色區(qū)域,松手,便可以觸發(fā)DragEvent.ACTION_DROP,把數(shù)據(jù)傳到SecondActivity中了。

    其實還有更復(fù)雜的一些情況,需要調(diào)用requestDropPermissions,后續(xù)我再進(jìn)一步實踐一下。

    這個demo的地址在這里,先分享出來,后面我再接著完善它。

    在分屏模式下測試你的App

    無論你是否將自己的App適配到了Android N,或者是支持分屏模式,都應(yīng)該找個Android N的設(shè)備,來測試一下自己的App在分屏模式下會變成什么樣。

    設(shè)置你的測試設(shè)備

    如果你有一臺運行Android N的設(shè)備,它是默認(rèn)支持分屏模式的。

    如果你的App不是用Android N Preview SDK打包的

    如果你的App是用低于Android N Preview SDK打包的,且你的Activity支持橫豎屏切換。那么當(dāng)用戶在嘗試使用分屏模式時,系統(tǒng)會強(qiáng)制將你的App進(jìn)入分屏模式。(我在第一篇博客里提到過這個,Android N Preview的介紹視頻中,很多Google家的App都可以進(jìn)入分屏模式,但是打開它們的xml一看,其實targetSDKVersion = 23

    因此,如果你的App/Activity支持橫豎屏切換,那么你應(yīng)該嘗試一下讓自己的App分屏,看看當(dāng)系統(tǒng)強(qiáng)制改變你的App尺寸時,用戶是否還可以接受這種體驗。如果你的App/Activity不支持橫豎屏切換,那么你可以確認(rèn)一下,看看當(dāng)嘗試進(jìn)入分屏?xí)r,你的App是不是仍然能夠保持全屏模式。

    如果你給App設(shè)置了支持分屏模式

    如果你使用了Android N Preview SDK來開發(fā)自己的App,那么應(yīng)該按照下面的要點檢查一下自己的App。

    • 啟動App,長按系統(tǒng)導(dǎo)航欄右下角的小方塊(Google官方把這個叫做Overview Button),確保你的App可以進(jìn)入分屏模式,且尺寸改變后仍然能正常工作。
    • 啟動任務(wù)管理器(即單擊右下角的小方塊),然后長按你App的標(biāo)題欄,將它拖動到屏幕上的高亮區(qū)域。確保你的App可以進(jìn)入分屏模式,且尺寸改變后仍然能正常工作。

    這兩點在上一篇博客中介紹過,讓自己的App進(jìn)入分屏模式有三種方法。第三種方法,就是在打開自己的App時,用手指從右下角的小方塊向上滑動,這樣也可以使得正在瀏覽的App進(jìn)入分屏模式。這種方法目前屬于實驗性功能,正式版不一定保留。

    • 當(dāng)你的App進(jìn)入分屏后,通過拖動兩個App中間的分欄上面的小白線,從而改變App的尺寸,觀察App中各個UI元素是否正常顯示。
    • 如果你給自己的App/Activity設(shè)置了最小尺寸,可以嘗試在改變App尺寸時,低于這個最小尺寸,觀察App是不是會回到設(shè)定好的最小尺寸。
    • 在進(jìn)行上面幾項測試時,請同時驗證自己的App功能和性能是否正常,并注意一下自己的App在更新UI時是否花費了太長的時間。

    這幾項測試,其實主要強(qiáng)調(diào)的是,我們的App可以順利的進(jìn)入/退出分屏模式,且改變App的尺寸時,UI依然可以也非常順滑。

    這里我想多說一句,如果進(jìn)入了分屏模式,要注意下App彈出的對話框,因為屏幕被兩個App分成兩塊之后,對話框也是可以彈出兩個的。這時對話框上的UI元素可能就會變得比較小了,如果我們的代碼是寫死的大小,例如對話框是一個WebView,就需要特別注意了,搞不好顯示出來就缺了一塊了,這里需要我們做好適配。

    測試清單

    關(guān)于功能、性能方面測試,還可以按照下面的操作來進(jìn)行。

    • 讓App進(jìn)入,再退出分屏模式,確保此時App功能正常。
    • 讓App進(jìn)入分屏模式,激活屏幕上的另外一個App,讓自己的App進(jìn)入可見、paused狀態(tài)。舉了例子來講,如果你的App是一個視頻播放器,那么當(dāng)用戶點擊了屏幕上另外一個App時,你的App不應(yīng)該停止播放視頻,即使此時你的Activity/Fragment已經(jīng)接到了onPaused()回調(diào)。
    • 讓App進(jìn)入分屏模式,拖動分欄上的小白線,改變App的尺寸。請在豎屏(兩個App一上一下布局)和橫屏(兩個App一左一右布局)模式下分別進(jìn)行改變尺寸的操作。確保App不會崩潰,各項功能正常,且UI的刷新沒有花費太多時間。
    • 在短時間內(nèi)、多次、迅速地改變App尺寸,確保App沒有崩潰,且沒有發(fā)生內(nèi)存泄露。關(guān)于內(nèi)存使用方面的更詳細(xì)注意事項,請參考Investigating Your RAM Usage
    • 在不同的窗口設(shè)置的情況下,正常使用App,確保App功能正常,文字仍然可讀,其他的UI元素也沒有變得太小,用戶仍然可以舒適地操作App。

    這幾項測試,其實主要是說當(dāng)App在分屏模式下運行時,仍然可以保持性能的穩(wěn)定,不會Crash也不會OOM。

    如果你給App設(shè)置了禁止分屏模式

    如果你給App/Activity設(shè)置了android:resizableActivity="false",你應(yīng)該試試當(dāng)用戶在Android N的設(shè)備上,嘗試分屏瀏覽你的App時,它是否仍然能保持全屏模式。

    以上就是參考Google最新的multi-window進(jìn)行的實踐,總結(jié)下,我認(rèn)為有3點比較重要:

    1. 如何讓自己的App/Activity順利的進(jìn)入和退出分屏模式,可以參考處理運行時改變這一章。
    2. 如何在分屏模式下打開新的Activity,可以參考Google官方的MultiWindow Playground Sample
    3. 如何實現(xiàn)跨App/Activity的拖拽功能,可以參考Drag and Drop這一章。

    關(guān)于App分屏模式的學(xué)習(xí)就到這里了,歡迎大家一起交流。我們還發(fā)揮更多的想象力,比如是否可以利用跨應(yīng)用拖拽實現(xiàn)更方便操作,更好的用戶體驗。


      本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評論

      發(fā)表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 男人又大又硬又粗视频| 亚洲综合成人av在线| 国产精品二区中文字幕| 67194熟妇在线观看线路| 人妻丰满AV无码中文字幕| av中文字幕一区二区| 国产精品无码一区二区三区电影| 深夜在线观看免费av| 少妇愉情理伦片BD| 2021亚洲国产精品无码| 成人国产精品日本在线观看| 中文字幕av无码不卡| 中文人妻AV大区中文不卡 | 天天影视网色香欲综合网| 公喝错春药让我高潮| 夜鲁夜鲁很鲁在线视频 视频| 国内精品久久久久久久小说| 男人猛进出女人下面视频| 欧美XXXX色视频在线观看| 亚洲 都市 无码 校园 激情| 人妻少妇不满足中文字幕| 国产AV午夜精品一区二区三区| 久久综合伊人77777| 国产精品无码久久综合网| 成人啪精品视频网站午夜| 国产精品免费久久久久影院| 2021AV在线无码最新| 精品国产中文字幕懂色| 国产精品国产三级国产AV主播| 99久久婷婷国产综合精品青草漫画| 无码精品人妻一区二区三区免费看 | 老子影院午夜精品无码| 人妻少妇456在线视频| 亚洲av成人无码天堂| 丰满人妻被黑人猛烈进入| 2020年最新国产精品正在播放| 又粗又黑又大的吊AV| 亚洲另类无码一区二区三区| 欧美极品色午夜在线视频| 无套内谢少妇一二三四| 亚洲AV中文无码字幕色最新|