Launcher App拖拽流程
2015-09-09 18:34
288 查看
1,App所在位置是源source,拖拽的目的地是:Target;source和target都是接口
Target接口:主要有四个方法要去实现:
顾名思义:onDrop:就是在放下后做的操作;
onDragEnter:进入之后的操作;
onDragOver:在目标体之上做的操作;
onDragExit:退出之后的操作;
Source接口:主要有一个方法要实现:
/**
* A callback made back to the source after an item from this source has been dropped on a
* DropTarget.
*/
void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success);
顾名思义:就是放下完成之后要处理的事情;
App在Workspace上面拖动,所以Workspace既是源也是目的,Workspace实现了这两个接口
public class Workspace extends SmoothPagedView implements DropTarget, DragSource, DragScroller,
当长按一个app是会调用Launcher的onlongclick方法:
这个方法就是首先生成一个和隐藏掉的图标一样的图标,将生成的Drawable交给DragController处理,调用 mDragController.startDrag();
如果站到位置之后会返回一个target,通过Target判断DropTarget 的状态是在哪一个状态四个状态就是Target接口的四个方法;
如果是这四种状态,它们会不停的切换状态,当你放下时会调用mDragController的drop()方法,
这个方法会通过findDropTarget()方法得到一个DropTarget,如果DropTarget不等于空mDragObject.dragComplete = true;说明拖拽完成,调用dropTarget.onDragExit(mDragObject);,判断如果dropTarget.acceptDrop(mDragObject),Target接不接受这个view。方法如下:
这个方法是返回一个boolean值,首先会判断source是不是自己,是自己就直接返回true,不是自己就是继续做判断,会去找位置调用
找到位置之后 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
会得到一个boolean值foundCell ,
判断是否在hotseat位置,是否在Allapp的按钮上就是进入主页面的按钮上;
最终会到 dropTarget的Ondrop方法
到workspace的ondrop方法看看(在桌面拖动,所以会调用workspace的ondrop方法,那个Target就是Workspace),
方法蛮长的,我们只看重点:
createUserFolderIfNecessary顾名思义就是两个应用是否合成文件夹;进去里面看看
方法有点长,也只看重点 boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
就是判断是否是在应用的上面,就是说,你放下的dragview下面是否是ShortcutInfo,而且你手放下的view也是ShortcutInfo,就合成文件夹 FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);合成文件夹返回true,
继续回到workspace的ondrop方法如果不是创建文件夹;继续往下
addToExistingFolderIfNecessary 顾名思义:既是加入到已经存在的文件夹
这个方法就是判断下面的view是否是文件夹,就进入到文件夹的Ondrop方法进行对addItem(item);
是否接受应用,文件夹是否没有销毁,条件成立之后返回true;就加入到文件夹了
继续ondrop方法:
如果桌面有位置就会 addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY);然后对数据的操作 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX,lp.cellY, item.spanX, item.spanY);
放下完成之后会调用source的onDropCompleted方法做一系列拖拽完成的操作;
会把隐藏的view移除掉
拖拽完成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Target接口:主要有四个方法要去实现:
/** * Handle an object being dropped on the DropTarget * * @param source DragSource where the drag started * @param x X coordinate of the drop location * @param y Y coordinate of the drop location * @param xOffset Horizontal offset with the object being dragged where the original * touch happened * @param yOffset Vertical offset with the object being dragged where the original * touch happened * @param dragView The DragView that's being dragged around on screen. * @param dragInfo Data associated with the object being dragged * */ void onDrop(DragObject dragObject); void onDragEnter(DragObject dragObject); void onDragOver(DragObject dragObject); void onDragExit(DragObject dragObject);
顾名思义:onDrop:就是在放下后做的操作;
onDragEnter:进入之后的操作;
onDragOver:在目标体之上做的操作;
onDragExit:退出之后的操作;
Source接口:主要有一个方法要实现:
/**
* A callback made back to the source after an item from this source has been dropped on a
* DropTarget.
*/
void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success);
顾名思义:就是放下完成之后要处理的事情;
App在Workspace上面拖动,所以Workspace既是源也是目的,Workspace实现了这两个接口
public class Workspace extends SmoothPagedView implements DropTarget, DragSource, DragScroller,
当长按一个app是会调用Launcher的onlongclick方法:
final View itemUnderLongClick = longClickCellInfo.cell; boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress(); if (allowLongPress && !mDragController.isDragging()) { if (itemUnderLongClick == null) { // User long pressed on empty space mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); // Disabling reordering until we sort out some issues. if (mWorkspace.isInOverviewMode()) { mWorkspace.startReordering(v); } else { mWorkspace.enterOverviewMode(); } } else { if (!(itemUnderLongClick instanceof Folder)) { // User long pressed on an item mWorkspace.startDrag(longClickCellInfo); } } }
最终会进入workspace的startDrag方法会把信息传递过来;
void startDrag(CellLayout.CellInfo cellInfo) { View child = cellInfo.cell; // Make sure the drag was started by a long press as opposed to a long click. if (!child.isInTouchMode()) { return; } mDragInfo = cellInfo; child.setVisibility(INVISIBLE); CellLayout layout = (CellLayout) child.getParent().getParent(); layout.prepareChildForDrag(child); child.clearFocus(); child.setPressed(false); final Canvas canvas = new Canvas(); // The outline is used to visualize where the item will land if dropped mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING); beginDragShared(child, this); }
当开始拖拽的时候:手按下的view会child.setVisibility(INVISIBLE);隐藏掉; 同时会绘制图标的边框线 createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
private Bitmap createDragOutline(View v, Canvas canvas, int padding) { final int outlineColor = getResources().getColor(R.color.outline_color); final Bitmap b = Bitmap.createBitmap( v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); canvas.setBitmap(b); drawDragView(v, canvas, padding, true); mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor); canvas.setBitmap(null); return b; }
绘制完成之后 beginDragShared(child, this);开始拖拽,手下的view传递过去,同时还需要一个源;
public void beginDragShared(View child, DragSource source) { // The drag bitmap follows the touch point around on the screen final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING); final int bmpWidth = b.getWidth(); final int bmpHeight = b.getHeight(); float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY); int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2); int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2 - DRAG_BITMAP_PADDING / 2); LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); Point dragVisualizeOffset = null; Rect dragRect = null; if (child instanceof BubbleTextView || child instanceof PagedViewIcon) { int iconSize = grid.iconSizePx; int top = child.getPaddingTop(); int left = (bmpWidth - iconSize) / 2; int right = left + iconSize; int bottom = top + iconSize; dragLayerY += top; // Note: The drag region is used to calculate drag layer offsets, but the // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2); dragRect = new Rect(left, top, right, bottom); } else if (child instanceof FolderIcon) { int previewSize = grid.folderIconSizePx; dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize); } // Clear the pressed state if necessary if (child instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) child; icon.clearPressedOrFocusedBackground(); } mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale); if (child.getParent() instanceof ShortcutAndWidgetContainer) { mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent(); } b.recycle(); }
这个方法就是首先生成一个和隐藏掉的图标一样的图标,将生成的Drawable交给DragController处理,调用 mDragController.startDrag();
/** * Starts a drag. * * @param b The bitmap to display as the drag image. It will be re-scaled to the * enlarged size. * @param dragLayerX The x position in the DragLayer of the left-top of the bitmap. * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap. * @param source An object representing where the drag originated * @param dragInfo The data associated with the object that is being dragged * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or * {@link #DRAG_ACTION_COPY} * @param dragRegion Coordinates within the bitmap b for the position of item being dragged. * Makes dragging feel more precise, e.g. you can clip out a transparent border */ public void startDrag(Bitmap b, int dragLayerX, int dragLayerY, DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion, float initialDragViewScale) { if (PROFILE_DRAWING_DURING_DRAG) { android.os.Debug.startMethodTracing("Launcher"); } // Hide soft keyboard, if visible if (mInputMethodManager == null) { mInputMethodManager = (InputMethodManager) mLauncher.getSystemService(Context.INPUT_METHOD_SERVICE); } mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0); for (DragListener listener : mListeners) { listener.onDragStart(source, dragInfo, dragAction); } final int registrationX = mMotionDownX - dragLayerX; final int registrationY = mMotionDownY - dragLayerY; final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left; final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top; mDragging = true; mDragObject = new DropTarget.DragObject(); mDragObject.dragComplete = false; mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft); mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop); mDragObject.dragSource = source; mDragObject.dragInfo = dragInfo; final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX, registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale); if (dragOffset != null) { dragView.setDragVisualizeOffset(new Point(dragOffset)); } if (dragRegion != null) { dragView.setDragRegion(new Rect(dragRegion)); } mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); dragView.show(mMotionDownX, mMotionDownY); handleMoveEvent(mMotionDownX, mMotionDownY); }
mDragController.startDrag()的方法主要是做隐藏键盘,注册DragController的一个接口,生成DragView就是把生成的Drawable转化成DragView,将DragView的坐标传给 handleMoveEvent(mMotionDownX, mMotionDownY)方法,同过获得的坐标DragView就可以移动 mDragObject.dragView.move(x, y);然后通过传过来的坐标在Target上找位置
private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) { final Rect r = mRectTemp; final ArrayList<DropTarget> dropTargets = mDropTargets; final int count = dropTargets.size(); for (int i=count-1; i>=0; i--) { DropTarget target = dropTargets.get(i); if (!target.isDropEnabled()) continue; target.getHitRectRelativeToDragLayer(r); mDragObject.x = x; mDragObject.y = y; if (r.contains(x, y)) { dropCoordinates[0] = x; dropCoordinates[1] = y; mLauncher.getDragLayer().mapCoordInSelfToDescendent((View) target, dropCoordinates); return target; } } return null;
如果站到位置之后会返回一个target,通过Target判断DropTarget 的状态是在哪一个状态四个状态就是Target接口的四个方法;
private void checkTouchMove(DropTarget dropTarget) { if (dropTarget != null) { if (mLastDropTarget != dropTarget) { if (mLastDropTarget != null) { mLastDropTarget.onDragExit(mDragObject); } dropTarget.onDragEnter(mDragObject); } dropTarget.onDragOver(mDragObject); } else { if (mLastDropTarget != null) { mLastDropTarget.onDragExit(mDragObject); } } mLastDropTarget = dropTarget; }
如果是这四种状态,它们会不停的切换状态,当你放下时会调用mDragController的drop()方法,
private void drop(float x, float y) { final int[] coordinates = mCoordinatesTemp; final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); mDragObject.x = coordinates[0]; mDragObject.y = coordinates[1]; boolean accepted = false; if (dropTarget != null) { mDragObject.dragComplete = true; dropTarget.onDragExit(mDragObject); if (dropTarget.acceptDrop(mDragObject)) { dropTarget.onDrop(mDragObject); accepted = true; } } mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, false, accepted); }
这个方法会通过findDropTarget()方法得到一个DropTarget,如果DropTarget不等于空mDragObject.dragComplete = true;说明拖拽完成,调用dropTarget.onDragExit(mDragObject);,判断如果dropTarget.acceptDrop(mDragObject),Target接不接受这个view。方法如下:
/** * {@inheritDoc} */ public boolean acceptDrop(DragObject d) { // If it's an external drop (e.g. from All Apps), check if it should be accepted CellLayout dropTargetLayout = mDropToLayout; if (d.dragSource != this) { // Don't accept the drop if we're not over a screen at time of drop if (dropTargetLayout == null) { return false; } if (!transitionStateShouldAllowDrop()) return false; mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, mDragViewVisualCenter); // We want the point to be mapped to the dragTarget. if (mLauncher.isHotseatLayout(dropTargetLayout)) { mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter); } else { mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null); } int spanX = 1; int spanY = 1; if (mDragInfo != null) { final CellLayout.CellInfo dragCellInfo = mDragInfo; spanX = dragCellInfo.spanX; spanY = dragCellInfo.spanY; } else { final ItemInfo dragInfo = (ItemInfo) d.dragInfo; spanX = dragInfo.spanX; spanY = dragInfo.spanY; } int minSpanX = spanX; int minSpanY = spanY; if (d.dragInfo instanceof PendingAddWidgetInfo) { minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX; minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY; } mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout, mTargetCell); float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell); if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout, mTargetCell, distance, true)) { return true; } if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout, mTargetCell, distance)) { return true; } int[] resultSpan = new int[2]; mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP); boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0; // Don't accept the drop if there's no room for the item if (!foundCell) { // Don't show the message if we are dropping on the AllApps button and the hotseat // is full boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout); if (mTargetCell != null && isHotseat) { Hotseat hotseat = mLauncher.getHotseat(); if (hotseat.isAllAppsButtonRank( hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) { return false; } } mLauncher.showOutOfSpaceMessage(isHotseat); return false; } }
这个方法是返回一个boolean值,首先会判断source是不是自己,是自己就直接返回true,不是自己就是继续做判断,会去找位置调用
private int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, CellLayout layout, int[] recycle) { return layout.findNearestArea( pixelX, pixelY, spanX, spanY, recycle); }
找到位置之后 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
会得到一个boolean值foundCell ,
if (!foundCell) { // Don't show the message if we are dropping on the AllApps button and the hotseat // is full boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout); if (mTargetCell != null && isHotseat) { Hotseat hotseat = mLauncher.getHotseat(); if (hotseat.isAllAppsButtonRank( hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) { return false; } } mLauncher.showOutOfSpaceMessage(isHotseat); return false; }
判断是否在hotseat位置,是否在Allapp的按钮上就是进入主页面的按钮上;
最终会到 dropTarget的Ondrop方法
if (dropTarget.acceptDrop(mDragObject)) { dropTarget.onDrop(mDragObject); accepted = true; }
到workspace的ondrop方法看看(在桌面拖动,所以会调用workspace的ondrop方法,那个Target就是Workspace),
public void onDrop(final DragObject d) { mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, mDragViewVisualCenter); CellLayout dropTargetLayout = mDropToLayout; // We want the point to be mapped to the dragTarget. if (dropTargetLayout != null) { if (mLauncher.isHotseatLayout(dropTargetLayout)) { mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter); } else { mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null); } } int snapScreen = -1; 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 (mDragInfo != null) { final View cell = mDragInfo.cell; Runnable resizeRunnable = null; if (dropTargetLayout != null && !d.cancelled) { // Move internally boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout); boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout); long container = hasMovedIntoHotseat ? LauncherSettings.Favorites.CONTAINER_HOTSEAT : LauncherSettings.Favorites.CONTAINER_DESKTOP; long 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.getDistanceFromCell(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 (!mInScrollArea && createUserFolderIfNecessary(cell, container, dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) { stripEmptyScreens(); return; } if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, distance, d, false)) { stripEmptyScreens(); return; } // Aside from the special case where we're dropping a shortcut onto a shortcut, // we need to find the nearest cell location that is vacant ItemInfo item = (ItemInfo) d.dragInfo; int minSpanX = item.spanX; int minSpanY = item.spanY; if (item.minSpanX > 0 && item.minSpanY > 0) { minSpanX = item.minSpanX; minSpanY = item.minSpanY; } int[] resultSpan = new int[2]; mTargetCell = dropTargetLayout.createArea((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 drop if (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; AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0], resultSpan[1]); } if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) { snapScreen = getPageIndexForScreenId(screenId); snapToPage(snapScreen); } if (foundCell) { final ItemInfo info = (ItemInfo) cell.getTag(); if (hasMovedLayouts) { // Reparent the view getParentCellLayoutForView(cell).removeView(cell); addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY); } // update the item's position after drop 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.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screenId, mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && cell instanceof LauncherAppWidgetHostView) { final CellLayout cellLayout = dropTargetLayout; // We post this call so that the widget has a chance to be placed // in its final location final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell; AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo(); if (pinfo != null && pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { final Runnable addResizeFrame = new Runnable() { public void run() { DragLayer dragLayer = mLauncher.getDragLayer(); dragLayer.addResizeFrame(info, hostView, cellLayout); } }; resizeRunnable = (new Runnable() { public void run() { if (!isPageMoving()) { addResizeFrame.run(); } else { mDelayedResizeRunnable = addResizeFrame; } } }); } } LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX, lp.cellY, item.spanX, item.spanY); } else { // If we can't find a drop location, we return the item to its original position CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); mTargetCell[0] = lp.cellX; mTargetCell[1] = lp.cellY; CellLayout layout = (CellLayout) cell.getParent().getParent(); layout.markCellsAsOccupiedForView(cell); } } final CellLayout parent = (CellLayout) cell.getParent().getParent(); final Runnable finalResizeRunnable = resizeRunnable; // Prepare it to be animated into its new position // This must be called after the view has been re-parented final Runnable onCompleteRunnable = new Runnable() { @Override public void run() { mAnimatingViewIntoPlace = false; updateChildrenLayersEnabled(false); if (finalResizeRunnable != null) { finalResizeRunnable.run(); } stripEmptyScreens(); } }; mAnimatingViewIntoPlace = true; if (d.dragView.hasDrawn()) { final ItemInfo info = (ItemInfo) cell.getTag(); if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE : ANIMATE_INTO_POSITION_AND_DISAPPEAR; animateWidgetDrop(info, parent, d.dragView, onCompleteRunnable, animationType, cell, false); } else { int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION; mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration, onCompleteRunnable, this); } } else { d.deferDragViewCleanupPostAnimation = false; cell.setVisibility(VISIBLE); } parent.onDropChild(cell); } }
方法蛮长的,我们只看重点:
if (!mInScrollArea && createUserFolderIfNecessary(cell, container, dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) { stripEmptyScreens(); return; }
createUserFolderIfNecessary顾名思义就是两个应用是否合成文件夹;进去里面看看
boolean createUserFolderIfNecessary(View newView, long container, CellLayout target, int[] targetCell, float distance, boolean external, DragView dragView, Runnable postAnimationRunnable) { if (distance > mMaxDistanceForFolderCreation) return false; View v = target.getChildAt(targetCell[0], targetCell[1]); boolean hasntMoved = false; if (mDragInfo != null) { CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell); hasntMoved = (mDragInfo.cellX == targetCell[0] && mDragInfo.cellY == targetCell[1]) && (cellParent == target); } if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false; mCreateUserFolderOnDrop = false; final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target); boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo); boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo); if (aboveShortcut && willBecomeShortcut) { ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag(); ShortcutInfo destInfo = (ShortcutInfo) v.getTag(); // if the drag started here, we need to remove it from the workspace if (!external) { getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); } Rect folderLocation = new Rect(); float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation); target.removeView(v); FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]); destInfo.cellX = -1; destInfo.cellY = -1; sourceInfo.cellX = -1; sourceInfo.cellY = -1; // If the dragView is null, we can't animate boolean animate = dragView != null; if (animate) { fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale, postAnimationRunnable); } else { fi.addItem(destInfo); fi.addItem(sourceInfo); } return true; } return false; }
方法有点长,也只看重点 boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
就是判断是否是在应用的上面,就是说,你放下的dragview下面是否是ShortcutInfo,而且你手放下的view也是ShortcutInfo,就合成文件夹 FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);合成文件夹返回true,
继续回到workspace的ondrop方法如果不是创建文件夹;继续往下
if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, distance, d, false)) { stripEmptyScreens(); return; }
addToExistingFolderIfNecessary 顾名思义:既是加入到已经存在的文件夹
boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell, float distance, DragObject d, boolean external) { if (distance > mMaxDistanceForFolderCreation) return false; View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); if (!mAddToExistingFolderOnDrop) return false; mAddToExistingFolderOnDrop = false; if (dropOverView instanceof FolderIcon) { FolderIcon fi = (FolderIcon) dropOverView; if (fi.acceptDrop(d.dragInfo)) { fi.onDrop(d); // if the drag started here, we need to remove it from the workspace if (!external) { getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); } return true; } } return false; }
这个方法就是判断下面的view是否是文件夹,就进入到文件夹的Ondrop方法进行对addItem(item);
是否接受应用,文件夹是否没有销毁,条件成立之后返回true;就加入到文件夹了
继续ondrop方法:
if (foundCell) { final ItemInfo info = (ItemInfo) cell.getTag(); if (hasMovedLayouts) { // Reparent the view getParentCellLayoutForView(cell).removeView(cell); addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY); }
如果桌面有位置就会 addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY);然后对数据的操作 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX,lp.cellY, item.spanX, item.spanY);
放下完成之后会调用source的onDropCompleted方法做一系列拖拽完成的操作;
if (parentCell != null) { parentCell.removeView(mDragInfo.cell); }
会把隐藏的view移除掉
拖拽完成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
相关文章推荐
- 个人信息安全报告发布:有 APP 每分钟调用位置权限 1468 次
- 下载量超过一亿的流行应用被发现含有恶意模块
- 苹果与Siri的七年之痒:“宫斗”戏码不断上演
- WinForm拖拽控件生成副本的解决方法
- 支持IE,firefxo,chrome浏览器下鼠标拖动和拖拽的鼠标指针特效
- js实现完美拖拽效果可拖动层与回放拖动规迹并显示拖动距离参数
- JavaScript实现拖拽网页内元素的方法
- Javascript拖拽系列文章1之offsetParent属性第1/3页
- Javascript拖拽&拖放系列文章3之细说事件对象第1/4页
- jQuery实现html元素拖拽
- jQuery控制Div拖拽效果完整实例分析
- jquery插件jquery.nicescroll实现图片无滚动条左右拖拽的方法
- Android APP与媒体存储服务的交互
- java实现收藏名言语句台词的app
- javascript 公用拖拽类代码
- 一个超简单的JS拖拽实现代码(兼容IE,Firefox)
- ExtJS的拖拽效果示例
- 修改Android App样式风格的方法
- 使用ViewPager实现高仿launcher左右拖动效果
- Android App数据格式Json解析方法和常见问题