您的位置:首页 > 移动开发

Launcher App拖拽流程

2015-09-09 18:34 288 查看
1,App所在位置是源source,拖拽的目的地是:Target;source和target都是接口

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移除掉

拖拽完成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  launcher 拖拽 app