Launcher长按拖拽流程

1、长按图标

Launcher类

实现了OnLongClickListener接口,重写onlongclick方法。workspace和hotseat在launcher的setupviews时,设置了长安监听:
mHotseat.setOnLongClickListener( this );
mWorkspace.setOnLongClickListener( this );
长按流程从launcher的Onlongclick开始,调用workspace的startDrag方法开始拖拽
mWorkspace.startDrag( longClickCellInfo );
Cellinfo里的信息:
View cell;//当前长按的view
int cellX = -1;//所在位置x
int cellY = -1;//所在位置y
int spanX;//x方向占格子数
int spanY;//y方向占格子数
long screenId;//页面数
long container;//容器类型(目前没发现有啥用)

workspace开始拖拽时

1、先把当前长按的view设置为invisible
2、然后createDragOutline方法返回了一个和长按view一样的bitmap图mDragOutline,可以称之为当前dragview的影子。表示松手后将放置的位置。
3、beginDragShared中,创建一个缩放之后的bitmap用来根手指动,并调用mDragController.startDrag开始拖拽。
void startDrag(
		com.cooee.phenix.data.CellInfo cellInfo )
{
	View child = cellInfo.getCell();
	// Make sure the drag was started by a long press as opposed to a long click.
	if( !child.isInTouchMode() )
	{
		return;
	}
	//cheyingkun start	//解决“拖动图标到垃圾框,松手快速点击桌面空白处,卸载提示出来后点击取消,之前拖动的图标消失”的问题。(bug:0010055)
	//		mDragInfo = cellInfo;//cheyingkun del
	//cheyingkun add start
	if( mDragInfo == null )
	{
		mDragInfo = new CellInfo();
	}
	cellInfo.cloneCellInfo( mDragInfo );
	//cheyingkun add end
	//cheyingkun end
	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 );
}

DragController:

starDrag方法中,

1、改变标志位
mDragging = true;
2、mDragObject赋值,记录拖拽的对象
mDragObject = new DropTarget.DragObject();
mDragObject.dragComplete = false;
mDragObject.xOffset = mMotionDownX - ( dragLayerX + dragRegionLeft );
mDragObject.yOffset = mMotionDownY - ( dragLayerY + dragRegionTop );
mDragObject.dragSource = source;//记录长按起的图标的来源(workspace、folder、AppsCustomizePagedView)
mDragObject.dragInfo = dragInfo;
3、创建一个DragView用于拖拽
final DragView dragView = mDragObject.dragView = new DragView( mLauncher , b , registrationX , registrationY , 0 , 0 , b.getWidth() , b.getHeight() , initialDragViewScale );
4、显示dragview
dragView.show( mMotionDownX , mMotionDownY );
5、设置dragview的位置,判断拖拽图标在什么东西上面并进行对应的回调
handleMoveEvent( mMotionDownX , mMotionDownY );
具体看看这个方法HandleMoveEvent
private void handleMoveEvent(
	int x ,
	int y )
{
	mDragObject.dragView.move( x , y );//移动dragview到指定位置
	// Drop on someone?
	final int[] coordinates = mCoordinatesTemp;
	DropTarget dropTarget = findDropTarget( x , y , coordinates );//根据坐标获取当前的dropTarget
	mDragObject.x = coordinates[0];
	mDragObject.y = coordinates[1];
	checkTouchMove( dropTarget );//根据dragview在哪个dropTarget上面,方法里是具体的回调操作
	// Check if we are hovering over the scroll areas
	mDistanceSinceScroll += Math.sqrt( Math.pow( mLastTouch[0] - x , 2 ) + Math.pow( mLastTouch[1] - y , 2 ) );
	mLastTouch[0] = x;
	mLastTouch[1] = y;
	checkScrollState( x , y );//检查是否拖拽到了页面边缘,如果是则切页
}

根据dragview在哪个dropTarget上,并进行相应的回调。

插入代码出问题,换张图

关于DropTarget:Interface defining an object that can receive a drag.

主要方法:
void onDrop( DragObject dragObject );//当dragview被放下时,调用onDrop
void onDragEnter( DragObject dragObject );//进入一个dropTarget时,会调用dropTarget.onDragEnter方法
void onDragOver( DragObject dragObject );//退出一个droptarget时,调用mLastDropTarget.onDragExit方法
void onDragExit( DragObject dragObject );//dropTarget不变时,则回调dropTarget.onDragOver( mDragObject );方法
/**
 * Handle an object being dropped as a result of flinging to delete and will be called in place
 * of onDrop().  (This is only called on objects that are set as the DragController's
 * fling-to-delete target.
 */
void onFlingToDelete( DragObject dragObject , int x , int y , PointF vec );//dragview被抛去垃圾桶
/**
 * Check if a drop action can occur at, or near, the requested location.
 * This will be called just before onDrop.
 */
boolean acceptDrop( DragObject dragObject );//判断是否可以ondrop
实现DropTarget的类有三个:Workspace、Folder、ButtonDropTarget。
其中InfoDropTarget extends ButtonDropTarget、DeleteDropTarget extends ButtonDropTarget。

onTouchEvent中:

case MotionEvent.ACTION_MOVE:
if( ev.getPointerCount() == 1 )//cheyingkun add	//解决“第一个手指长按桌面图标,另一个手指在按住桌面空白处不松开,松开第一个手指后再点击桌面任意空白处,图标闪烁”的问题。【i_0011723】
{
	handleMoveEvent( dragLayerX , dragLayerY );
}
break;
case MotionEvent.ACTION_UP:
// Ensure that we've processed a move event at the current pointer location.
handleMoveEvent( dragLayerX , dragLayerY );
mHandler.removeCallbacks( mScrollRunnable );
if( mDragging )
{
	PointF vec = isFlingingToDelete( mDragObject.dragSource );
	if( !DeleteDropTarget.willAcceptDrop( mDragObject.dragInfo ) )
	{
		vec = null;
	}
	if( vec != null )
	{
		dropOnFlingToDeleteTarget( dragLayerX , dragLayerY , vec );//删除
	}
	else
	{
		drop( dragLayerX , dragLayerY );//放下图标
	}
}
endDrag();
break;
1、当手指移动时,则不断回调第四步handleMoveEvent,更新位置、判断是否进入新的dragtarget、等等。
2、松手后,则根据是否抛向垃圾筐,进行dropOnFlingToDeleteTarget或者drop,他们都会调用到mDragObject.dragSource.onDropCompleted(方法,来进行松手完成之后,长按起来的view来源的变化。
比如workspace中的图标显示、删除。因为一开始就有说,长按时,把桌面图标设置了invisible,跟着手指动的图和影子都是根据这个view画出来的。这一步是操作和原view之间逻辑的同步。
最后结束拖拽endDrag:
private void endDrag()
{
	if( mDragging )
	{
		mDragging = false;//重置标志位
		mIsAccessibleDrag = false;
		clearScrollRunnable();//清空滚动线程
		boolean isDeferred = false;
		if( mDragObject.dragView != null )
		{
			isDeferred = mDragObject.deferDragViewCleanupPostAnimation;
			if( !isDeferred )
			{
				mDragObject.dragView.remove();
			}
			mDragObject.dragView = null;//清空dragview
		}
		// Only end the drag if we are not deferred
		if( !isDeferred )
		{
			for( DragListener listener : new ArrayList<>( mListeners ) )//循环回调onDragEnd
			{
				listener.onDragEnd();
			}
		}
	}
	releaseVelocityTracker();
}

尾注:

本篇文章粗略的讲了一下拖拽流程,回调里的东西并没有详细介绍。各位看官如有不懂,请对照源码继续修行。

ps:不要问我为啥不写回调之后的blog,我也不是很清楚每一个细节,有本事你们来打我呀,略略略~~

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值