`
亚当爱上java
  • 浏览: 707357 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android Launcher拖拽事件详解【android4.0--Launcher系列二】

阅读更多

AndroidICS4.0版本的launcher拖 拽的流程,基本和2.3的相似。就是比2.3写的封装的接口多了一些,比如删除类的写法就多了个类。等等。4.0的改变有一些,但是不是特别大。这个月一 直在改动Launcher的缩略图的效果,4.0的缩略图的功能没有实现,还得从2.3的Launcher中摘出来。通过做这个缩略图对Launcher 的模块有一点点了解,拿来分享一下Launcher拖拽的工作流程。微笑有图有真相!吐舌头

 

                (1) 先来看看类之间的继承关系

                     

      

                                                          图(1)

                                                                                                                                               

               (2)再来看看Launcher拖拽流程的时序图

              

 

                                                                       图(2)

 

下面咱们分步来解析Launcher拖拽的详细过程:

step 1 :先来看看Launcher.java这个类的onCreate()方法中的setupViews()方法中的一部分代码:

 

        // Setup the workspace
        mWorkspace.setHapticFeedbackEnabled(false);
        mWorkspace.setOnLongClickListener(this);
        mWorkspace.setup(dragController);
        dragController.addDragListener(mWorkspace);

 

 

Workspace设置长按事件的监听交给了Launcher.java这个类了。所以在主屏上长按事件会走到Launcher.java----->onLongClick()这个方法中去;

 

step 2 :接着我们来看看Launcher.java中onLongClick()的代码:

public boolean onLongClick(View v) {
         ··············
 // The hotseat touch handling does not go through Workspace, and we always allow long press
        // on hotseat items.
        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);
                startWallpaper();
            } else {
                if (!(itemUnderLongClick instanceof Folder)) {
                    // User long pressed on an item
                    mWorkspace.startDrag(longClickCellInfo);
                }
            }
        }
        return true;
    }
 

通过itemUnderLongClick == null 来判断,在屏幕上触发长按事件是否选中了shortcut或者widget。如果为空,就启动桌面的壁纸,else,就把拖拽事件往Workspace.java这个类传递。

 

Step 3 :通过mWorkspace.startDrag(longClickCellInfo),把长按事件传递给workspace来处理,具体来看代码:

   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
        child.setVisibility(GONE);

        child.clearFocus();
        child.setPressed(false);

        final Canvas canvas = new Canvas();

        // We need to add extra padding to the bitmap to make room for the glow effect
        final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;

        // The outline is used to visualize where the item will land if dropped
        mDragOutline = createDragOutline(child, canvas, bitmapPadding);
        beginDragShared(child, this);
    }
 

上面的代码主要做的工作是:把正在拖拽的这个view隐藏掉,在主屏幕上绘制一个蓝色的,大小和图标相似的一个边框,以表示能在主屏的这个位置放置。

 

Step 4 :接着调用beginDragShared(child, this)这个方法,代码如下:

 public void beginDragShared(View child, DragSource source) {
    ··· ···
// 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);
        b.recycle();
    }
 

这个方法做的工作是:开始进行拖拽,绘制正在拖拽的图片,把拖拽的事件交给DragController来处理。

 

Step 5 :接 着来看看mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect)这个方法,代码如下:

 public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
            DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion) {
··· ···
 mDragObject.dragComplete = false;
        mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
        mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
        mDragObject.dragSource = source;
        mDragObject.dragInfo = dragInfo;
mVibrator.vibrate(VIBRATE_DURATION);

        final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
                registrationY, 0, 0, b.getWidth(), b.getHeight());

        if (dragOffset != null) {
            dragView.setDragVisualizeOffset(new Point(dragOffset));
        }
        if (dragRegion != null) {
            dragView.setDragRegion(new Rect(dragRegion));
        }

        dragView.show(mMotionDownX, mMotionDownY);
        handleMoveEvent(mMotionDownX, mMotionDownY);
    }
 

这 个方法的作用是:计算要拖拽的view的大小,显示在workspace上,dragView.show(mMotionDownX, mMotionDownY);这个show()会根据手指的移动而移动的。然后在通过handleMoveEvent()方法来分发拖拽的目标到底在哪个 目标上。DropTarget一共有3个:workspace,ButtonDropTarget(删除类),Folder;他们分别实现了 DropTarget这个接口。

下面来看看这个接口有一下几个方法:

boolean isDropEnabled();
void onDrop(DragObject dragObject);

    void onDragEnter(DragObject dragObject);

    void onDragOver(DragObject dragObject);

    void onDragExit(DragObject dragObject);
DropTarget getDropTargetDelegate(DragObject dragObject);
boolean acceptDrop(DragObject dragObject);

    // These methods are implemented in Views
    void getHitRect(Rect outRect);
    void getLocationInDragLayer(int[] loc);
    int getLeft();
    int getTop();
 

这些方法不是每个类继承了DropTarget的接口,都要把每个方法都实现,这要看具体的需要来定。

 

另外这个接口中有个内部类-----DragObject:如下

class DragObject {
        public int x = -1;
        public int y = -1;

        /** X offset from the upper-left corner of the cell to where we touched.  */
        public int xOffset = -1;

        /** Y offset from the upper-left corner of the cell to where we touched.  */
        public int yOffset = -1;

        /** This indicates whether a drag is in final stages, either drop or cancel. It
         * differentiates onDragExit, since this is called when the drag is ending, above
         * the current drag target, or when the drag moves off the current drag object.
         */
        public boolean dragComplete = false;

        /** The view that moves around while you drag.  */
        public DragView dragView = null;

        /** The data associated with the object being dragged */
        public Object dragInfo = null;

        /** Where the drag originated */
        public DragSource dragSource = null;

        /** Post drag animation runnable */
        public Runnable postAnimationRunnable = null;

        /** Indicates that the drag operation was cancelled */
        public boolean cancelled = false;

        public DragObject() {
        }
    }
 

这个类的作用是存储一些坐标,拖拽点距离整个view左上角x轴上的距离,y轴上的距离,还有一些拖拽的信息都保存在这个类中,还有动画线程类等等。在拖拽过程中这些信息都是会用到的。

 

Step 6 :接 着来看看handleMoveEvent()这个类,这个类频繁被调用,因为在DragLayer.java这个类中onTouchEvent()方法, 最后调用的是 mDragController.onTouchEvent(ev)这个方法,长按后,移动的事件就传递到了DragController中的 onTouchEvent()方法中,先来看看mDragController.onTouchEvent(ev)这个方法,代码如下:

/**
     * Call this from a drag source view.
     */
    public boolean onTouchEvent(MotionEvent ev) {
        if (!mDragging) {
            return false;
        }

        final int action = ev.getAction();
        final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
        final int dragLayerX = dragLayerPos[0];
        final int dragLayerY = dragLayerPos[1];

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            // Remember where the motion event started
            mMotionDownX = dragLayerX;
            mMotionDownY = dragLayerY;

            if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
                mScrollState = SCROLL_WAITING_IN_ZONE;
                mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
            } else {
                mScrollState = SCROLL_OUTSIDE_ZONE;
            }
            break;
        case MotionEvent.ACTION_MOVE:
            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) {
                drop(dragLayerX, dragLayerY);
            }
            endDrag();
            break;
        case MotionEvent.ACTION_CANCEL:
            cancelDrag();
            break;
        }

        return true;
    }
 

在这个方法中清楚的可以看见handleMoveEvent()这个方法会在move,up的时候频繁地调用。

现在再来看看这个handleMoveEvent()方法,看看它的庐山真面目:

private void handleMoveEvent(int x, int y) {
        mDragObject.dragView.move(x, y);

        // Drop on someone?
        final int[] coordinates = mCoordinatesTemp;
        DropTarget dropTarget = findDropTarget(x, y, coordinates);
        mDragObject.x = coordinates[0];
        mDragObject.y = coordinates[1];
        if (dropTarget != null) {
            DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
            if (delegate != null) {
                dropTarget = delegate;
            }

            if (mLastDropTarget != dropTarget) {
                if (mLastDropTarget != null) {
                    mLastDropTarget.onDragExit(mDragObject);
                }
                dropTarget.onDragEnter(mDragObject);
            }
            dropTarget.onDragOver(mDragObject);
        } else {
            if (mLastDropTarget != null) {
                mLastDropTarget.onDragExit(mDragObject);
            }
        }
        mLastDropTarget = dropTarget;

··· ···
}
   

这 个方法的作用:通过findDropTarget(x, y, coordinates),来判断在哪个拖拽目标里面,然后通过下面的if判断来执行不同的onDragOver,onDragExit等的方法。这样就 在相应的类中去做处理,以后的事情就明朗了。这就是Launcher的拖拽事件的分发与处理,用到了MVC的思想,代码阅读起来还是比较顺利的。有图有真 相。

欢迎大家留言讨论相关问题。

本文转载自:http://blog.csdn.net/wdaming1986/article/details/7671318

  • 大小: 25.2 KB
  • 大小: 51.5 KB
分享到:
评论

相关推荐

    android4.0原生launcher代码

    【Android 4.0 原生 Launcher 代码详解】 Android 4.0(冰淇淋三明治,Ice Cream Sandwich)的 Launcher 是用户界面的核心部分,它作为系统的启动器,负责展示应用图标、小部件和主屏幕。理解其源码对于开发者深入...

    Android Launcher2

    **Android Launcher2详解** 在Android系统中,Launcher是用户与设备交互的第一道窗口,它扮演着桌面的角色,负责展示应用图标、小部件以及管理主屏幕。`Launcher2`是Android早期版本中的默认启动器,虽然在后来的...

    Android launcher应用讲解

    ### Android Launcher应用详解 #### 一、Launcher概念与作用 Launcher是Android系统中非常重要的一部分,通常被称为“启动器”或“桌面”。它负责展示应用程序的快捷方式、小部件(widgets)以及文件夹等内容,为...

    android2.3 launcher分析二

    8. **DragController.constructive**:处理拖拽事件,允许用户在桌面上移动图标或组件。 9. **AllApps2D.constructive**:实现多页应用程序列表的视图。 10. **Workspace.constructive**:构建工作区,即用户看到的...

    launcher2源码

    **launcher2源码详解** `launcher2`是Android操作系统中默认主屏幕应用的早期实现,主要负责管理桌面快捷方式、小部件以及应用抽屉。在Android 4.3及以上版本中,`launcher2`作为系统组件,对于理解Android系统的...

    基于Android的高仿小米launcher(ZAKER)跨屏拖动item.zip

    8. **事件处理**: 跨屏拖动功能涉及到触摸事件的处理,包括ACTION_DOWN、ACTION_MOVE和ACTION_UP等,需要理解Android事件传递机制。 9. **动画效果**: 在拖动过程中,可能包含过渡动画,如淡入淡出、平移等,这些...

    高仿小米launcher(ZAKER)跨屏拖动item_Android.rar

    "高仿小米launcher(ZAKER)跨屏拖动item_Android.rar" 这个标题揭示了我们即将探讨的主题是关于Android系统中的一个启动器应用,它模仿了小米(Xiaomi)手机的桌面布局和ZAKER新闻阅读器的特性,特别是涉及到跨屏拖动...

    带注释的Launcher3

    【Launcher3详解】 Launcher3是Android系统中默认的桌面启动器,它负责管理应用程序的图标、小部件以及主屏幕布局。这个"带注释的Launcher3"很可能是一个开发者为了教学或者研究目的,对源代码进行了详细注解的版本...

    Launcher4源码包

    【Launcher4.0.3源码包详解】 Launcher是Android操作系统中的核心组件之一,它扮演着用户界面的入口角色,负责展示应用图标、桌面小部件等,并管理用户的启动操作。Launcher4.0.3源码包是针对Android系统的一个特定...

    使用ViewPager实现高仿launcher拖动效果.rar

    "使用ViewPager实现高仿launcher拖动效果" 这个标题指出我们要讨论的是如何使用Android的ViewPager组件来创建一个类似手机启动器(launcher)的滑动界面。在Android开发中,ViewPager通常用于在多个页面之间进行平滑...

    Launcher的源码详细分析

    《Android Launcher源码详解》 Android Launcher作为手机的主屏幕,是用户与系统交互的核心入口。深入了解其源码,有助于我们更好地定制和优化系统行为,提高用户体验。本文将基于Android 2.1的launcher2源码,分析...

    Android控件大全以及各布局控件的使用方式

    ### Android控件大全及各布局控件的使用详解 #### 一、Android控件概述 Android控件是指在Android应用程序中用于实现用户界面的各种组件。这些控件包括但不限于按钮、文本框、列表视图等。熟悉并掌握这些控件对于...

    android开发资料大全

    Android 小項目之---Iphone拖动图片特效 (附源码) 一个完整的新浪微博客户端android版OAuth认证示例 超爽的android抽屉效果 65个Android实例教程汇总 基本控件及基本动画效果dem 2011android面试题目及其答案大全...

    launcher初学者

    #### 二、主要文件和类详解 ##### 1. **Launcher.java** - **功能**:作为Launcher的核心Activity,负责整个Launcher界面的初始化和管理。 - **职责**:控制Launcher的生命周期,管理用户交互,并与其他组件进行...

    MONKEY测试

    - `--pct-motion 20`:运动事件(如拖动)占比20%。 - `--pct-trackball 0`:轨迹球事件占比0%。 - `--pct-syskeys 10`:系统键事件占比10%。 - `--pct-nav 10`:导航事件(如返回键)占比10%。 - `--pct-...

    Android客户端GPS定位源码

    - `&lt;intent-filter&gt;`用于指定该活动的启动意图,这里的`android.intent.action.MAIN`和`android.intent.category.LAUNCHER`表明这是一个启动活动。 - `&lt;uses-library&gt;`标签指定了使用了Google Maps库。 3. **权限...

    疯狂Android讲义源码

     3.1 Android的事件处理 145  3.2 基于监听的事件处理 145  3.2.1 事件监听的处理模型 145  3.2.2 事件和事件监听器 148  3.2.3 内部类作为事件监听器类 151  3.2.4 外部类作为事件监听器类 152  3.2.5 ...

    安卓Android源码——FloatWindowDemo.zip

    2. `ic_launcher-web.png`:这是应用的启动图标,用于设备上显示和识别应用。 3. `.project`:是Eclipse项目配置文件,包含了项目的构建信息、编译设置、构建路径等,对于在Eclipse中打开和理解项目结构至关重要。 ...

    MyAndroidExample

    【Android控件实现详解】 在Android开发中,控件是构建用户界面的基础元素,它们使得应用程序具有交互性和可视化。在"MyAndroidExample"这个压缩包中,我们很可能会找到一系列示例,涵盖了Android开发中常见的控件...

Global site tag (gtag.js) - Google Analytics