【原始碼剖析】Launcher 8.0 原始碼 25---使用者操作(2)模式切換
模式就是介面,除普通模式外,Launcher還有兩個特殊模式,分別是overView模式和Springloader模式。此處採用狀態模式這種設計模式,共有三個狀態。
overView模式是長按桌面空白處,出現特殊功能,比如設定桌布,新增widget,特殊設定(橫屏開關,負一屏開關等),設定主螢幕(點選home鍵自動移動到的cellLayout),刪除螢幕等。
Springloader模式又叫拖拽模式,使用者想改變CellLayout裡面的佈局,就是通過拖拽圖示,widget等來改變其位置,這個模式叫做拖拽模式。
正常模式,overView模式和SpringLoader模式就構成了正常的Launcher三個核心互動。
點選和滑動構成了普通模式,而長按則是overView模式和SpringLoader模式的起始因素。
Launcher 實現了OnLongClickListener介面。
原始碼如下:
@Override public boolean onLongClick(View v) { //首先進行三種判斷,其實質:如果當前狀態處於其他狀態返回Launcher狀態的途中,或者Launcher的佈局還沒有讀取完成,則不進行後續操作。因為在以上兩種狀態,進行後面的操作會出故障,此外,以上兩種狀態持續時間非常短暫,所以考慮為使用者誤操作且這一瞬間操作無用。 比如說拖拽完圖示後,我們能看到從springload模式進入普通模式的過程,這個過程中,長按桌面是沒有任何作用的。
if (!isDraggingEnabled()) return false; if (isWorkspaceLocked()) return false; if (mState != State.WORKSPACE) return false;
//後面判斷方法和onclick有些類似,一次判斷是點選的哪裡來進行對應處理,首先如果長按的是allapp入口,則開啟allapp。對於allapp按鈕,點選和長按一個效果。Allapp按鈕在Launcher8.0裡是hotseat上面的indicator上面的小三角符號。
if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) || (v == mAllAppsButton && mAllAppsButton != null)) { onLongClickAllAppsButton(v);
return true; } //如果使用者點選的是桌面空白處,則從普通模式進入overView模式,也是手機裡面的長按空白出現下方快捷操作欄的行為,這是最常見的操作。 if (v instanceof Workspace) { if (!mWorkspace.isInOverviewMode()) { if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) { getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, Action.Direction.NONE, ContainerType.WORKSPACE, mWorkspace.getCurrentPage()); showOverviewMode(true); mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); return true; } else { return false; } } else { return false; } } //如果點選的是item,這個item就是Launcher啟動模式裡面loadAndBindWorkspace所load和bind的item。如果點選Launcher就獲取 longClickCellInfo 。具體程式碼還在後面。 CellLayout.CellInfo longClickCellInfo = null; View itemUnderLongClick = null; if (v.getTag() instanceof ItemInfo) { ItemInfo info = (ItemInfo) v.getTag(); longClickCellInfo = new CellLayout.CellInfo(v, info); itemUnderLongClick = longClickCellInfo.cell; mPendingRequestArgs = null; } if (!mDragController.isDragging()) { if (itemUnderLongClick == null) { //如果在overview模式,且長按了頁面,則進入頁面調整模式。長按的頁面(cellLayout)會有視效變化,同時提供頁面(cellLayout)交換的功能。 if (mWorkspace.isInOverviewMode()) { mWorkspace.startReordering(v); getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, Action.Direction.NONE, ContainerType.OVERVIEW); } else {
//如果在overview模式長按空白處,則仍然停留在overview模式。 if (ignoreLongPressToOverview) { return false; } getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, Action.Direction.NONE, ContainerType.WORKSPACE, mWorkspace.getCurrentPage()); showOverviewMode(true); } mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } else {
//如果就是在普通模式長按了item,那麼根據之前獲取的longClickCellInfo進入drag模式。也就是springloader模式。 final boolean isAllAppsButton = !FeatureFlags.NO_ALL_APPS_ICON && isHotseatLayout(v) && mDeviceProfile.inv.isAllAppsButtonRank(mHotseat.getOrderInHotseat( longClickCellInfo.cellX, longClickCellInfo.cellY)); if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) { // User long pressed on an item mWorkspace.startDrag(longClickCellInfo, new DragOptions()); } } } return true; }
以上,Launcher的長按主要是進入overView模式和springloader模式。
overView模式下面能做的事情有,設定主螢幕,刪除螢幕,顯示選項欄等首先在Launcher的啟動流程第四步setupView當中的setupOverviewPanel是對下方選項欄進行定義。
而其中定義了三個按鈕,第一個是wallpapers,其作用是開啟帶有”Intent.ACTION_SET_WALLPAPER”的應用。
第二個是widget列表,其WidgetsContainerView中放有WidgetsRecyclerView。放著當前user下能夠識別的所有widget。根據click原始碼如下,當點選空白處,直接return。而點選到widget上則提示使用者需要長按widget才行。
@Override public void onClick(View v) { // When we have exited widget tray or are in transition, disregard clicks if (!mLauncher.isWidgetsViewVisible() || mLauncher.getWorkspace().isSwitchingState() || !(v instanceof WidgetCell)) return; handleClick(); } public void handleClick() { // Let the user know that they have to long press to add a widget if (mWidgetInstructionToast != null) { mWidgetInstructionToast.cancel(); } CharSequence msg = Utilities.wrapForTts( getContext().getText(R.string.long_press_widget_to_add), getContext().getString(R.string.long_accessible_way_to_add)); mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT); mWidgetInstructionToast.show(); }
如果長按的話,則是進入beginDragging。後面會統一講解各個地方長按的邏輯。到目前可知,allapp長按是進入workspace的drag,而widget長按是進入widget自己的drag。
@Override public boolean onLongClick(View v) { if (!mLauncher.isWidgetsViewVisible()) return false; return handleLongClick(v); } public boolean handleLongClick(View v) { if (!v.isInTouchMode()) return false; if (mLauncher.getWorkspace().isSwitchingState()) return false; if (!mLauncher.isDraggingEnabled()) return false; return beginDragging(v); }
而在folder中的長按則folder自己的長按加上workspace的長按。
當然無論是workspace的長按還是widget的長按最終走入的還是dragControll的長按。
以上就是overviewMode模式的操作,因為overviewMode的操作的實現在Launcher的啟動流程完成。建議本文配合啟動流程的overviewMode建立共同學習。