版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a396604593/article/details/52846513
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。
其中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来源的变化。
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,我也不是很清楚每一个细节,有本事你们来打我呀,略略略~~