1. 程式人生 > >Launcher中批量應用圖示拖拽的實現方法

Launcher中批量應用圖示拖拽的實現方法

-- Junda.huang

筆者最近參與Launcher的定製,其中有一條需求是在編輯模式下實現應用圖示的批量拖拽,實現批量操作。這篇文章主要記錄批量拖拽的實現以及踩過的坑。

原生的Launcher是沒有批量拖拽item這種操作的,如下圖所示。進入編輯模式後,只能對整個頁面進行拖動。


定製的Launcher要求,在編輯介面,可以通過點選選中多個app圖示,然後長按可以對選中的item進行批量拖拽:實現批量移動item。如下圖:


接下來介紹實現方式:

首先,修改編輯模式下item的點選事件(對Launcher.java檔案中的onClick()方法的修改):

if (tag instanceof

ShortcutInfo) {

   if (CustomConfigs.SUPPORT_MULTIDRAG

&& (mWorkspace.isInOverviewMode()

|| mWorkspace.isInOverviewHiddenMode())) {

//編輯模式下,點選item且支援批量拖拽

           markApp(v);

        } else {

           onClickAppShortcut(v);

        }

}

點選未選中item,新增進marklist;點選已選中item,移出marklist:

private void

markApp(View v) {

     if (v instanceof BubbleTextView) {

        BubbleTextView bt = (BubbleTextView) v;

        if (!bt.getSel()) {

           bt.setSel(true);

           mMarkList.add(bt);

        } else {

           bt.setSel(false);

           mMarkList.remove(bt);

        }

     }

   }

完成對item的選擇,然後,長按item進行拖拽(對Launcher.java檔案中,onLongClick()方法的修改):

if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {

    if (CustomConfigs.SUPPORT_MULTIDRAG

&& (mWorkspace.isInOverviewMode()

|| mWorkspace.isInOverviewHiddenMode())

        && mMarkList.size() > 0) {

        closeFolder();

         if (itemUnderLongClick instanceof FolderIcon || itemUnderLongClick instanceof LauncherAppWidgetHostView){

  cleanMark();                     

mWorkspace.startDrag(longClickCellInfo);

                 } else {   

//編輯模式下長按app item,且marklist不為空,進入批量拖拽        

mWorkspace.startMutilDrag(longClickCellInfo, mMarkList);

                 }

              …

}

具體拖拽實現(Workspace.java檔案):

void startMutilDrag(ViewstartView, List<BubbleTextView> list) {

mDragList = newArrayList<CellInfo>();    

//將marklist中的item逐個移至draglist:

for (BubbleTextView b :list) {

if (!b.equals(startView)) {

   CellLayout.CellInfo ci = genCellInfo((ShortcutInfo) b.getTag());

   ci.cell = b;

   mDragList.add(ci);

   }

}

CellLayout.CellInfo sci =genCellInfo((ShortcutInfo) startView.getTag());

sci.cell = startView;

//將長按的item新增在draglist首位

mDragList.add(0, sci);

int[] sloc = new int[2];

mLauncher.getDragLayer().getLocationInDragLayer(startView, sloc);

for (finalCellInfo ci : mDragList) {

   final View b =ci.cell;

   if (b.equals(startView)) {

//根據長按的item,生成互動過程中跟隨手指的view以及其他操作,此處邏輯與原生一致      

beginDragShared(startView, this, false);

mDragController.getDragObject().dragList =mDragList;

CellLayout cl = (CellLayout) b.getParent().getParent();

if (cl.getParent().getParent().getParent()instanceof Folder) {

   Folder folder = (Folder) cl.getParent()

.getParent().getParent();

//拖拽時,將長按的item,暫時移出launcher

   folder.mInfo.remove((ShortcutInfo)b.getTag());

   folder.mInfo.checked = false;

} else {

//拖拽時,將長按的item,暫時移出launcher

    cl.removeView(b);

}

} else {

if (b.getParent() != null &&b.getParent().getParent() != null) {

CellLayout cl = (CellLayout)b.getParent().getParent();

if (cl.getParent().getParent().getParent()instanceof Folder) {

     Folder folder = (Folder) cl.getParent().getParent().getParent();

     folder.mInfo.remove((ShortcutInfo)b.getTag());

//拖拽時,先將選中的item,暫時移出launcher

folder.mInfo.checked = false;

} else {

//拖拽時,先將選中的item,暫時移出launcher

   cl.removeView(b);

}

      ……

}

最後,將item拖拽到目的Celllayout,完成拖拽,批量放置,為每個item尋找位置,(item(Workspace.java檔案中,onDrop()方法):

ArrayList<ItemInfo>items = new ArrayList<ItemInfo>();

ArrayList<Integer>screens = new ArrayList<Integer>();

public void onDrop(final DragObject d) {

  CellLayout dropTargetLayout = mDropToLayout;

  if (dropTargetLayout != null) {

  …

     int snapScreen =WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE;

     boolean resizeOnDrop = false;

        if (d.dragSource != this){

            final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],

(int) mDragViewVisualCenter[1] };

        onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);

        } else if(mDragList != null){     

//拖拽的item被放置在workspace上,而且draglist不為空,此時批量移動item

      handleMultiDrop(d,dropTargetLayout);

        }

}

批量放置item具體實現:

private void handleMultiDrop(DragObject d, CellLayout target) {

//如果是放置在已有item上,新建資料夾,並將item加入其中

   if (!mInScrollArea && createUserFolder(d, target)) {

       return;

}

//如果是放置在已有folder上,item加入該資料夾

   if (addToExistFolders(d, target)) {

      return;

   }

//item放置在workspace空白處

//從放置的那個頁面開始為給個item尋找空位進行放置

int now = indexOfChild(mDropToLayout);

   if (now < 0) {

         now = indexOfChild(getCurrentDropLayout());

   }

   Set<Integer> traversedCellLayout = new LinkedHashSet<Integer>();

   boolean isNoSpace = false;

   for (CellInfo ci : mDragList) {

      traversedCellLayout.add(now);

      if (ci.cell.getParent() != null) {

         CellLayout cl = (CellLayout) ci.cell.getParent().getParent();

         if (cl.getParent().getParent().getParent() instanceof Folder) {

            Folder folder = (Folder) cl.getParent().getParent().getParent();

            folder.mInfo.remove((ShortcutInfo) ci.cell.getTag());

            folder.mInfo.checked = false;

         } else {

            cl.removeView(ci.cell);

            if (traversedCellLayout.contains(indexOfChild(cl))) {

                  now = indexOfChild(cl);

                 }

            }

         }

         int[] cellXY = new int[2];

         boolean find = false;

         while (!find) {

            CellLayout cl = (CellLayout)getChildAt(now);

            find = cl.findCellForSpan(cellXY, 1, 1);

            if (find) {

               ci.screenId = getIdForScreen(cl);

               if (ci.screenId == EXTEND_SCREEN_ID) {

                   ci.screenId =commitExtendScreen();

                   addExtraExtendScreen();

                 }

               ci.cellX = cellXY[0];

               ci.cellY = cellXY[1];

               //重新將item添加回workspace

               addInScreen(ci.cell, ci.container, ci.screenId, cellXY[0],

                    cellXY[1], ci.spanX, ci.spanY);

               ItemInfo item = (ItemInfo) ci.cell.getTag();

                           ItemInfo item = (ItemInfo) ci.cell.getTag();

//            //LauncherModel.moveItemInDatabase(getContext(),item,

//                 Favorites.CONTAINER_DESKTOP,//ci.screenId, cellXY[0],

//                  cellXY[1]);

               item.cellX =cellXY[0];

               item.cellY =cellXY[1];

               items.add(item);

               screens.add((int) ci.screenId);          } else {

               // There no more space in TargetLayout

               isNoSpace = true;

               //

               if (now <getChildCount()-1) {

                  now++;

               } else {

                  //TODO: need to check max

                  if (getChildCount()>= CustomConfigs.WORKSPACE_MAX_PAGE) {

                    now = 0;

                  } else {

                    long newId =LauncherAppState.getLauncherProvider().generateNewScreenId();

                    insertNewWorkspaceScreen(newId);

                    int index =getPageIndexForScreenId(newId);

                    // Update the page indicator marker

                    if(getPageIndicator() != null) {

                       getPageIndicator().updateMarker(index,getPageIndicatorMarker(index));

                    }

                    // Update the model for the new screen

                     mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);

                    now++;

                  }

               }

            }

         }

     }

//放置完成後,再一次性地批量更新資料庫,將新的位置資訊做儲存

LauncherModel.moveItemsInDatabase(mLauncher,items, Favorites.CONTAINER_DESKTOP, screens);

}

主要踩過的坑:

1.完成對item的選擇後拖拽時,DragView在遠離手指的地方。原因是先選中第一頁幾個應用,再長按第二頁的應用,選中的第一頁的應用個數在移除後使得第二頁長按的那個應用排列到第一頁,出現DragView離手指一個folder頁面的距離。先生成DragView然後再remove,也就是需要把startView放在draglist的第一位即可。mDragList.add(0,sci);

2.在適配低配置平臺的時候,批量拖拽後Launcher有概率被系統殺掉,原因是拖拽後,佔用資源過多。經排查發現,在為每個item尋找到空位後,都馬上將新的座標儲存到資料庫導致。解決辦法是,在找到空位後,先將item顯示在workspace中,全部完成之後,再統一修改資料庫。

相關推薦

Launcher批量應用圖示實現方法

-- Junda.huang 筆者最近參與Launcher的定製,其中有一條需求是在編輯模式下實現應用圖示的批量拖拽,實現批量操作。這篇文章主要記錄批量拖拽的實現以及踩過的坑。 原生的Launcher是沒有批量拖拽item這種操作的,如下圖所示。進入編輯模式後,只能對整

AndroidDrag and Drop功能的使用1-----基本實現

Android中的拖拽功能是有自帶的api的;(很多時候會誤以為要自定義控制元件,所以我放到了,自定義目錄下) 參考文件: http://www.android-doc.com/guide/topics/ui/drag-drop.html 我寫了一個例子分析: 效果圖: 思路: 1主要

關於MFC任意物件的功能的實現(COleDataSource, COleDropTarget)

    拖拽功能的實現是一個全域性的功能實現,也就是沒有程序之隔,是一個類似windows的檔案拖拽管理和開啟的功能。而下面說記錄的是關於任意內容的全域性拖拽的實現細節。關於相關函式和物件的具體描述可以直接MSDN檢視,這裡就不對其進行詳細的簡介。     大體的實現可

winform 無邊框窗體實現

sed style windows part fse use left clas void using System; using System.Collections.Generic; using System.ComponentModel; using Syst

pc端移動端實現

ack spa listen prev odi nth 獲取 lock top #div1 { width: 100px; height: 100px; background: red; position: absolute; }

js 實現面向對象

oct utf-8 xhtml bsp AC name java prototype new // JavaScript Document /*構造函數*/ function Drag(id){ this.disX = 0;

vue的移動app項目,自定義指令的問題

喜歡 end direct 需要 不支持 rect 兼容 left dir 使用vue的都知道vue有一個自定義指令,我比較喜歡的就是拖拽的自定義指令,感覺挺方便的! //組件內的拖拽指令 directives: { //組建內自定義指令 drag: {

WIN32API 圖示功能的基本配置方法

基本的方法就是通過微軟官網提供的事列來完成整個操作過程, 微軟連結:https://docs.microsoft.com/en-us/windows/desktop/controls/using-image-lists; https://docs.microsoft.com/en-us/windows/d

手工在Dash增加應用圖示

點選Dash或啟動器中的圖示可以啟動一個應用,很方便,尤其是一些常用的應用程式,固定在啟動器上,用的時候隨手一點就啟動了。 本文介紹手工在Dash中新增應用圖示。使用的時Ubuntu16.04。 Linux的一個有點就是所有的系統配置都以檔案的方式儲存在系統磁碟中,而且絕大多數都是可以通過文

AndroidDrag and Drop功能的使用2-----交換佈局中子控制元件的位置

Android中的拖拽功能是有自帶的api的;(很多時候會誤以為要自定義控制元件,所以我放到了,自定義目錄下) 參考文件: http://www.android-doc.com/guide/topics/ui/drag-drop.html 我寫了一個例子分析: 效果圖: 思路: 1

簡單實現方法 sortable.js

最近做BI專案頻繁用到拖拽,心累呀,後來發現了一款好用的拖拽外掛  sortable.js 真心好用,使用也特別方便,不依賴jq,可以在vue、ng、react中使用 <ul id="foo"> <li>老子天下第一</li> <

Unity2D物體的

public class testButton : MonoBehaviour { public bool isMouseDown = false; private Vector3 la

VC 樹控制元件的實現 MFC

只需要將你的樹控制元件型別改成CXTreeCtrl,並將以下標頭檔案:XTreeCtrl.h和實現檔案:XTreeCtrl.cpp包含進你的工程。 然後在void CXTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)這個函式中

王爽 組合語言 實驗7 定址方式在結構化資料訪問應用,用棧實現

assume cs:codesg data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db

利用JavaFx開發RIA桌面應用-檔案

1 背景 給JavaFx中的TextField控制元件新增檔案拖拽功能,即實現將檔案或資料夾拖拽至TeuxtField中,TextField顯示出相應的路徑地址。 2 監聽器 在JavaFX中關於拖放操作,可以設定這麼幾種事件監聽器: se

vue模塊實現示例代碼

off lan 現在 簡單 comm etl nbsp xhtml www 正巧在之前面試中遇到問實現拖拽效果 當時面試的時候簡單回答了實現的方式與邏輯。 現在閑來無事,把這個東西實現了一下。 原理很簡單,寫的很方便。 數據驅動,建立一個數組,數組初始長度為1 拖

C#事件的動態調用實現方法

ear too new std 實現 bject multicast using pad 本文實例講述了C#動態調用事件的方法。一般來說,傳統的思路是,通過Reflection.EventInfo獲得事件的信息,然後使用GetRaiseMethod方法獲得事件被觸發後調用

linux批量創文件夾的方法

方法 use done 五個 clas test blog one user 1,命令方法touch 456{1,2,3,4,5} 會在目錄中生成(4561,4562,4563,4564,4565)五個目錄文件mkdir 456{1,2,3,4,5} 會在目錄中生成(456

Java常見的比較器的實現方法

ati 算法 equals equal util get stat 不想 sort 在Java中經常會涉及到對象數組的排序問題,那麽就涉及到對象之間的比較問題。通常對象之間的比較可以從兩個方面去看:第一個方面:對象的地址是否一樣,也就是是否引用自同一個對象。這種方式可以直接

在mybatis同一個方法執行多個SQL語句實現方法

  一、oracle資料      <delete id="delete" parameterType="upc.cbs.HtxxlrEntity"> begin    delete from PC_CBS_CONTRA