菏泽网站建设 梧桐树,二次开发创造作用,爱站网能不能挖掘关键词,网页设计实验报告小结基于Android13 Launcher3,原生系统如果把图标从Workspace拖动到Hotseat里则Workspace就没有了#xff0c;需求是执行拖拽动作后#xff0c;图标同时保留在原位置。
实现效果如下#xff1a; 实现思路#xff1a;
1.如果在workspace中拖动#xff0c;则保留原来“改变图标…基于Android13 Launcher3,原生系统如果把图标从Workspace拖动到Hotseat里则Workspace就没有了需求是执行拖拽动作后图标同时保留在原位置。
实现效果如下 实现思路
1.如果在workspace中拖动则保留原来“改变图标位置”的功能
2.如果拖拽到Hotseat则添加到Hotseat的同时也在原来位置复制一个一样的View
3.每次改变都要存到数据库以保存当前状态
思路非常简单但是要找适当的位置添加适当的代码不简单。需要读懂原生代码。
分析了源代码后发现应该参考Workspace.java的onDrop与onDropExternal代码来实现。
step1: 读懂代码后添加注释中文为添加的注释和添加onDropToHotseat()的调用
Overridepublic void onDrop(final DragObject d, DragOptions options) {mDragViewVisualCenter d.getVisualCenter(mDragViewVisualCenter);CellLayout dropTargetLayout mDropToLayout;Log.d(drop,onDrop!);// We want the point to be mapped to the dragTarget.if (dropTargetLayout ! null) {mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);}boolean droppedOnOriginalCell false;boolean snappedToNewPage false;boolean resizeOnDrop false;Runnable onCompleteRunnable null;if (d.dragSource ! this || mDragInfo null) {//从别的地方AllApp等拖到worksapce的 startfinal int[] touchXY new int[] { (int) mDragViewVisualCenter[0],(int) mDragViewVisualCenter[1] };onDropExternal(touchXY, dropTargetLayout, d);Log.d(drop,onDropExternal!);//从别的地方AllApp等拖到worksapce的 end} else {//从workspace拖到workspace startfinal View cell mDragInfo.cell;boolean droppedOnOriginalCellDuringTransition false;if (dropTargetLayout ! null !d.cancelled) {//有地方可放且没有取消拖动 start// Move internallyboolean hasMovedLayouts (getParentCellLayoutForView(cell) ! dropTargetLayout);boolean hasMovedIntoHotseat mLauncher.isHotseatLayout(dropTargetLayout);Log.d(drop,hasMovedIntoHotseat :hasMovedIntoHotseat);int container hasMovedIntoHotseat ?LauncherSettings.Favorites.CONTAINER_HOTSEAT :LauncherSettings.Favorites.CONTAINER_DESKTOP;int screenId (mTargetCell[0] 0) ?mDragInfo.screenId : getIdForScreen(dropTargetLayout);int spanX mDragInfo ! null ? mDragInfo.spanX : 1;int spanY mDragInfo ! null ? mDragInfo.spanY : 1;// First we find the cell nearest to point at which the item is// dropped, without any consideration to whether there is an item there.mTargetCell findNearestArea((int) mDragViewVisualCenter[0], (int)mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);float distance dropTargetLayout.getDistanceFromWorkspaceCellVisualCenter(mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);// If the item being dropped is a shortcut and the nearest drop// cell also contains a shortcut, then create a folder with the two shortcuts.if (createUserFolderIfNecessary(cell, container,dropTargetLayout, mTargetCell, distance, false, d)|| addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,distance, d, false)) {mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);return;}// Aside from the special case where were dropping a shortcut onto a shortcut,// we need to find the nearest cell location that is vacantItemInfo item d.dragInfo;int minSpanX item.spanX;int minSpanY item.spanY;if (item.minSpanX 0 item.minSpanY 0) {minSpanX item.minSpanX;minSpanY item.minSpanY;}droppedOnOriginalCell item.screenId screenId item.container container item.cellX mTargetCell[0] item.cellY mTargetCell[1];droppedOnOriginalCellDuringTransition droppedOnOriginalCell mIsSwitchingState;// When quickly moving an item, a user may accidentally rearrange their// workspace. So instead we move the icon back safely to its original position.boolean returnToOriginalCellToPreventShuffling !isFinishedSwitchingState() !droppedOnOriginalCellDuringTransition !dropTargetLayout.isRegionVacant(mTargetCell[0], mTargetCell[1], spanX, spanY);int[] resultSpan new int[2];if (returnToOriginalCellToPreventShuffling) {mTargetCell[0] mTargetCell[1] -1;} else {//让目的地Layout重新布局一下顺序腾出drop的位置mTargetCell dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],(int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);}boolean foundCell mTargetCell[0] 0 mTargetCell[1] 0;// if the widget resizes on dropif (foundCell (cell instanceof AppWidgetHostView) (resultSpan[0] ! item.spanX || resultSpan[1] ! item.spanY)) {resizeOnDrop true;item.spanX resultSpan[0];item.spanY resultSpan[1];AppWidgetHostView awhv (AppWidgetHostView) cell;WidgetSizes.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],resultSpan[1]);}if (foundCell) {//目的地有空出位置 startint targetScreenIndex getPageIndexForScreenId(screenId);int snapScreen getLeftmostVisiblePageForIndex(targetScreenIndex);// On large screen devices two pages can be shown at the same time, and snap// isnt needed if the source and target screens appear at the same timeif (snapScreen ! mCurrentPage !hasMovedIntoHotseat) {snapToPage(snapScreen);snappedToNewPage true;}final ItemInfo info (ItemInfo) cell.getTag();/*这一段实现把cell从原来的父View中remove掉添加到目的layout里去 start*/if (hasMovedLayouts) {// Reparent the view 这段非常关键重新安排父View startLog.d(drop,drop to different layout!!);//表示放在了不同的layout里CellLayout parentCell getParentCellLayoutForView(cell);if (parentCell ! null) {parentCell.removeView(cell);//如果注释这句就会报错说明view不能有两个parent} else if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {d.dragView.detachContentView(/* reattachToPreviousParent */ false);} else if (FeatureFlags.IS_STUDIO_BUILD) {throw new NullPointerException(mDragInfo.cell has null parent);}addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],info.spanX, info.spanY);//假如我们在此调用getParentCellLayoutForView(cell);得到的parentCell就是目的layout了// Reparent the view 这段非常关键重新安排父View end//added by Kevin.Ye for create keep dragObject when dropped to Hotseatif(hasMovedIntoHotseat)onDropToHotseat(d);//end}/*这一段实现把cell从原来的父View中remove掉添加到目的layout里去 end*/// update the items position after drop/*把目的地位置作为这个cell的位置 start*/CellLayout.LayoutParams lp (CellLayout.LayoutParams) cell.getLayoutParams();lp.cellX lp.tmpCellX mTargetCell[0];lp.cellY lp.tmpCellY mTargetCell[1];lp.cellHSpan item.spanX;lp.cellVSpan item.spanY;lp.isLockedToGrid true;/*把目的地位置作为这个cell的位置 end*/if (container ! LauncherSettings.Favorites.CONTAINER_HOTSEAT cell instanceof LauncherAppWidgetHostView) {//这段处理的是widgetfinal CellLayout cellLayout dropTargetLayout;// We post this call so that the widget has a chance to be placed// in its final locationfinal LauncherAppWidgetHostView hostView (LauncherAppWidgetHostView) cell;AppWidgetProviderInfo pInfo hostView.getAppWidgetInfo();if (pInfo ! null pInfo.resizeMode ! AppWidgetProviderInfo.RESIZE_NONE !options.isAccessibleDrag) {onCompleteRunnable () - {if (!isPageInTransition()) {AppWidgetResizeFrame.showForWidget(hostView, cellLayout);}};}}//更新到数据库里去mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId,lp.cellX, lp.cellY, item.spanX, item.spanY);} else {//没有找到位置drop startif (!returnToOriginalCellToPreventShuffling) {onNoCellFound(dropTargetLayout, d.dragInfo, d.logInstanceId);}if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {d.dragView.detachContentView(/* reattachToPreviousParent */ true);}// If we cant find a drop location, we return the item to its original positionCellLayout.LayoutParams lp (CellLayout.LayoutParams) cell.getLayoutParams();mTargetCell[0] lp.cellX;mTargetCell[1] lp.cellY;CellLayout layout (CellLayout) cell.getParent().getParent();layout.markCellsAsOccupiedForView(cell);}//没有找到位置 end} else {//处理取消drag start// When drag is cancelled, reattach content view back to its original parent.if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {d.dragView.detachContentView(/* reattachToPreviousParent */ true);}//处理取消drag end}final CellLayout parent (CellLayout) cell.getParent().getParent();if (d.dragView.hasDrawn()) {//拖动View已经绘图 statif (droppedOnOriginalCellDuringTransition) {//过渡的过程中拖到原来的位置 start// Animate the item to its original position, while simultaneously exiting// spring-loaded mode so the page meets the icon where it was picked up.final RunnableList callbackList new RunnableList();final Runnable onCompleteCallback onCompleteRunnable;mLauncher.getDragController().animateDragViewToOriginalPosition(/* onComplete */ callbackList::executeAllAndDestroy, cell,SPRING_LOADED.getTransitionDuration(mLauncher, true /* isToState */));mLauncher.getStateManager().goToState(NORMAL, /* delay */ 0,onCompleteCallback null? null: forSuccessCallback(() - callbackList.add(onCompleteCallback)));mLauncher.getDropTargetBar().onDragEnd();parent.onDropChild(cell);return;}//过渡的过程中拖到原来的位置 endfinal ItemInfo info (ItemInfo) cell.getTag();boolean isWidget info.itemType LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET|| info.itemType LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;if (isWidget) {//桌面小组件drop到新位置int animationType resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :ANIMATE_INTO_POSITION_AND_DISAPPEAR;animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false);} else {//图标动画移动到新位置,但如果没有drop到目的地则会回到原来的位置int duration snappedToNewPage ? ADJACENT_SCREEN_DROP_DURATION : -1;mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,this);}} else {d.deferDragViewCleanupPostAnimation false;cell.setVisibility(VISIBLE);}parent.onDropChild(cell);mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY,onCompleteRunnable null ? null : forSuccessCallback(onCompleteRunnable));mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId).log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED);}if (d.stateAnnouncer ! null !droppedOnOriginalCell) {d.stateAnnouncer.completeAction(R.string.item_moved);}}
step2:同样在Workspace.java中添加增加的接口 onDropToHotseat(DragObject d) /** Added by Kevin.Ye* when a shortcut was dropped to Hotseat,we create a new one in original position* */private void onDropToHotseat(DragObject d){ItemInfo info d.dragInfo;WorkspaceItemInfo newItemInfo null;View view;switch (info.itemType) {case ITEM_TYPE_APPLICATION:case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:case LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION:if (info instanceof WorkspaceItemFactory) {// Came from all apps -- make a copynewItemInfo ((WorkspaceItemFactory) info).makeWorkspaceItem(mLauncher);//d.dragInfo info;}if (info instanceof WorkspaceItemInfo) {// Came from all apps prediction row -- make a copynewItemInfo new WorkspaceItemInfo((WorkspaceItemInfo) info);//d.dragInfo info;}view mLauncher.createShortcut((WorkspaceItemInfo) info);break;case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:view FolderIcon.inflateFolderAndIcon(R.layout.folder_icon, mLauncher, (ViewGroup) getChildAt(0),(FolderInfo) info);break;default:throw new IllegalStateException(Unknown item type: info.itemType);}//final ContentResolver cr getContext().getContentResolver();//newItemInfo.id LauncherSettings.Settings.call(cr, LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt(LauncherSettings.Settings.EXTRA_VALUE);if(newItemInfo null)return;newItemInfo.id ItemInfo.NO_ID;//this is very important,otherwise it wont be add new shortcut in database marked by Kevin.YeLog.d(drop,info.id:info.id newItemInfo.id:newItemInfo.id);// Add the item to DB before adding to screen ensures that the container and other// values of the info is properly updated.Log.d(drop,new shortcut container:newItemInfo.container screenId:newItemInfo.screenId cellX:newItemInfo.cellX cellY:newItemInfo.cellY);//info.id ItemInfo.NO_ID;//it is very important as we need to add new one to database not movemLauncher.getModelWriter().addOrMoveItemInDatabase(newItemInfo, newItemInfo.container, newItemInfo.screenId, newItemInfo.cellX, newItemInfo.cellY);addInScreen(view, newItemInfo.container, newItemInfo.screenId, newItemInfo.cellX, newItemInfo.cellY,newItemInfo.spanX, newItemInfo.spanY);}