android1.6 launcher源码学习笔记

长按应用程序实现拖动它到桌面(workspace)或从桌面删除:

重要类简介

public class DeleteZone extends ImageView implements DropTarget, DragController.DragListener;

public class FolderIcon extends BubbleTextView implements DropTarget;

public class UserFolder extends Folder implements DropTarget;

public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller;

public class AllAppsGridView extends GridView implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, DragSource


launcher的根布局文件launcher.xml

launcher.xml布局如下:

<com.android.launcher.DragLayer  android:id="@+id/drag_layer"......>

    <!-- The workspace contains 3 screens of cells -->
    <com.android.launcher.Workspace
        android:id="@+id/workspace"......>
        <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
        <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
        <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
    </com.android.launcher.Workspace>


    <SlidingDrawer
        android:id="@+id/drawer"
        android:handle="@+id/all_apps"
        android:content="@+id/content">


        <com.android.launcher.HandleView
            android:id="@id/all_apps"......./>

        <com.android.launcher.AllAppsGridView
            android:id="@id/content"................../>

    </SlidingDrawer>

    <com.android.launcher.DeleteZone
        android:id="@+id/delete_zone".................. />

</com.android.launcher.DragLayer>

它的根元素是public class DragLayer extends FrameLayout implementsDragController


public interface DragController {
    

/*DragListener是给删除回收站(DeleteZone)实现的接口,拖动app item的时候删除回收站(DeleteZone)会实现onDragStart(),同时它可见;结束的时候onDragEnd(),DeleteZone再次隐藏起来

*/
    interface DragListener {        
        void onDragStart(View v, DragSource source, Object info, int dragAction);
        void onDragEnd();
    }
  
    public static int DRAG_ACTION_MOVE = 0;
    public static int DRAG_ACTION_COPY = 1;

    void startDrag(View v, DragSource source, Object info, int dragAction);   
    void setDragListener(DragListener l);    
    void removeDragListener(DragListener l);
}

public class DeleteZone extends ImageView implements DropTarget, DragController.DragListener

DeleteZone通过实现DragController.DragListener的onDragStart(),onDragEnd()的两个接口

public void onDragStart(View v, DragSource source, Object info, int dragAction) {
            setVisibility(VISIBLE); //可见
    }

    public void onDragEnd() {
            setVisibility(GONE);//再次隐藏
    }

DragLayer通过接口setDragListener,将DeleteZone应用到内部成员mListener

说几个DragLayer内部几个接口变量:

DrogTarget拖动app_icon的时候,最终放置(接受)它的object

DeleteZone(垃圾回收筒),Workspace(桌面),FolderIcon/UserFolder(文件夹)都是可以放置app_icon的地方,所以它们都implement DropTarget

public interface DropTarget {
    void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
    
    void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

    void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

    void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

    boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);

    Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle);
}

DragSource拖动来源的object,它可以是AllAppsGridView,Folder,Workspace

public interface DragSource {
    void setDragger(DragController dragger);
    void onDropCompleted(View target, boolean success);
}

在AllAppsGridView界面长按么个app_icon

....AllAppsGridView .....{

public boolean onItemLongClick() {
..........

        mDragger.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);        //DragLayer开始拖动
        mLauncher.closeAllApplications();                //关闭AllAppsGridView界面,切换到workspace
..........
    }

}

若是在workspace界面长按么个app_icon

....Launcher .....{

public boolean onLongClick(View v) {

....

....

}

}


看看DragLayer.startDrag()做了什么,

DragLayer ...{

      startDrag(...){

            .........

            mListener.onDragStart(v, source, dragInfo, dragAction); //调用垃圾筒listener(DeleteZone)接口onDragStart(),DeleteZone会将自己setVisibility(VISIBLE);

           mDragBitmap = Bitmap.createBitmap(viewBitmap, 0, 0, width, height, scale, true);   //创建一个拖动过程中,跟随拖动坐标浮动的app_icon 

           mDragSource = source;      //设置拖动的源object,是AllAppsGridView,还是Workspace,Folder,其它

           mDragInfo = dragInfo;        //记录长按的那个app_icon相关信息

           ............

      }
//接下来是长按图标不松的情况下,移动的过程当中,这个是onTouchEvent,onInterceptTouchEvent中实现
      public boolean onTouchEvent(MotionEvent ev) {
                  .............
            case MotionEvent.ACTION_MOVE:
            DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); // 查找可以receive 拖动中的app_icon(它或是workspace,DeleteZone,Folder)
            if (dropTarget != null) {
                if (mLastDropTarget == dropTarget) {
                    dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
                } else {
                    if (mLastDropTarget != null) {
                        mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
                            (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
                    }
                    dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
                }
            } else {
                if (mLastDropTarget != null) {
                    mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
                }
            }
           ..................
           mLastDropTarget = dropTarget;//每次移动的过程当中,记录最近一次DropTarget
           //同时在这个过程当中,当移动到边界的时候,workspace会实现一个滚到下一个celllayout(界面)的动作,DrayLayer定义一个自类ScrollRunable
      case MotionEvent.ACTION_UP:
            removeCallbacks(mScrollRunnable);
            if (mShouldDrop) {
                drop(x, y);                                // 添加到桌面(workspace)/文件夹(Folder)/垃圾筒(DeleteZone)
                mShouldDrop = false;
            }
            endDrag(); // mListener.onDragEnd() 垃圾筒再次隐藏起来

            break;
        case MotionEvent.ACTION_CANCEL:
            endDrag();

      }
      private boolean drop(float x, float y) {
        final int[] coordinates = mDropCoordinates;
        DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); // 查找最终接受app_icon的DropTarget(workspace,folder,deleteZone),以workspace为最终的                 //droptarget,看看workspace做了什么,转到Workspace的类 
        if (dropTarget != null) {
            dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
            if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1],
                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo)) {
                dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1],
                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
                mDragSource.onDropCompleted((View) dropTarget, true);
                return true;
            } else {
                mDragSource.onDropCompleted((View) dropTarget, false);
                return true;
            }
        }
        return false;
    }
   

     private class ScrollRunnable implements Runnable {
        private int mDirection;

        ScrollRunnable() {
        }
        public void run() {
            if (mDragScroller != null) {
                mDrawEstimated = false;
                if (mDirection == SCROLL_LEFT) {
                    mDragScroller.scrollLeft();                       //mDragScroller引用到workspace实例,它实现workspace的左右滚动
                } else {
                    mDragScroller.scrollRight();
                }
                mScrollState = SCROLL_OUTSIDE_ZONE;
            }
        }

        void setDirection(int direction) {
            mDirection = direction;
        }
    }

}

 

class Workspace {

   public boolean acceptDrop(DragSource source, int x, int y,              //看看是否有空间来放app_icon
            int xOffset, int yOffset, Object dragInfo) {
        final CellLayout layout = getCurrentDropLayout();
        final CellLayout.CellInfo cellInfo = mDragInfo;
        final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
        final int spanY = cellInfo == null ? 1 : cellInfo.spanY;

        if (mVacantCache == null) {
            final View ignoreView = cellInfo == null ? null : cellInfo.cell;
            mVacantCache = layout.findAllVacantCells(null, ignoreView);
        }

        return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false);
    }
 

public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
        final CellLayout cellLayout = getCurrentDropLayout();
        if (source != this) {    //拖动的app_icon是否是从workspace中拖动来的,如从AllappsGridView拖动来的app_icon就走这个分支
            onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);   //添加到数据库
        } else {
            // Move internally          workspace内部拖动,移动app_icon的位置
            if (mDragInfo != null) {
                final View cell = mDragInfo.cell;
                if (mCurrentScreen != mDragInfo.screen) {
                    final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                    originalCellLayout.removeView(cell);
                    cellLayout.addView(cell);
                }
                mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
                        mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
                cellLayout.onDropChild(cell, mTargetCell);
                LauncherModel.moveItemInDatabase(mLauncher, info,
                        LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
            }
        }
    }

}


当在workspace上添加一个app_icon的时,最终app_icon用的布局文件layout下的application.xml

<com.android.launcher.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
  style="@style/WorkspaceIcon.Portrait" />

class BubbleTextView extends TextView

BubbleTextView是在TextView的背景画一个透明汽泡


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值