`

android DragLayer源码

阅读更多
Android_launcher的源码详细分析
http://www.cnblogs.com/playing/archive/2011/04/22/2024980.html

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Paint;
import android.graphics.PorterDuffColorFilter;源码
import android.graphics.PorterDuff;
import android.os.Vibrator;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.KeyEvent;
import android.widget.FrameLayout;

/**
 * A ViewGroup that coordinated dragging across its dscendants
 */
public class DragLayer extends FrameLayout implements DragController {
    private static final int SCROLL_DELAY = 600;
    private static final int SCROLL_ZONE = 20;
    private static final int VIBRATE_DURATION = 35;
    private static final int ANIMATION_SCALE_UP_DURATION = 110;

    private static final boolean PROFILE_DRAWING_DURING_DRAG = false;

    // Number of pixels to add to the dragged item for scaling
    private static final float DRAG_SCALE = 24.0f;

    private boolean mDragging = false;
    private boolean mShouldDrop;
    private float mLastMotionX;
    private float mLastMotionY;
    
    /**
     * The bitmap that is currently being dragged
     */
    private Bitmap mDragBitmap = null;
    private View mOriginator;

    private int mBitmapOffsetX;
    private int mBitmapOffsetY;

    /**
     * X offset from where we touched on the cell to its upper-left corner
     */
    private float mTouchOffsetX;
    
    /**
     * Y offset from where we touched on the cell to its upper-left corner
     */
    private float mTouchOffsetY;
    
    /**
     * Utility rectangle
     */
    private Rect mDragRect = new Rect();
    
    /**
     * Where the drag originated
     */
    private DragSource mDragSource;
    
    /**
     * The data associated with the object being dragged
     */
    private Object mDragInfo;

    private final Rect mRect = new Rect();    
    private final int[] mDropCoordinates = new int[2];

    private final Vibrator mVibrator = new Vibrator();
    
    private DragListener mListener;

    private DragScroller mDragScroller;
    
    private static final int SCROLL_OUTSIDE_ZONE = 0;
    private static final int SCROLL_WAITING_IN_ZONE = 1;

    private static final int SCROLL_LEFT = 0;
    private static final int SCROLL_RIGHT = 1;
    
    private int mScrollState = SCROLL_OUTSIDE_ZONE;

    private ScrollRunnable mScrollRunnable = new ScrollRunnable();
    private View mIgnoredDropTarget;

    private RectF mDragRegion;
    private boolean mEnteredRegion;
    private DropTarget mLastDropTarget;

    private final Paint mTrashPaint = new Paint();
    private Paint mDragPaint;

    private static final int ANIMATION_STATE_STARTING = 1;
    private static final int ANIMATION_STATE_RUNNING = 2;
    private static final int ANIMATION_STATE_DONE = 3;

    private static final int ANIMATION_TYPE_SCALE = 1;

    private float mAnimationFrom;
    private float mAnimationTo;
    private int mAnimationDuration;
    private long mAnimationStartTime;
    private int mAnimationType;
    private int mAnimationState = ANIMATION_STATE_DONE;

    /**
     * Used to create a new DragLayer from XML.
     *
     * @param context The application's context.
     * @param attrs The attribtues set containing the Workspace's customization values.
     */
    public DragLayer(Context context, AttributeSet attrs) {
        super(context, attrs);

        final int srcColor = context.getResources().getColor(R.color.delete_color_filter);
        mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
    }

    public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
        if (PROFILE_DRAWING_DURING_DRAG) {
            android.os.Debug.startMethodTracing("Launcher");
        }
        
        if (mListener != null) {
            mListener.onDragStart(v, source, dragInfo, dragAction);
        }

        Rect r = mDragRect;
        r.set(v.getScrollX(), v.getScrollY(), 0, 0);

        offsetDescendantRectToMyCoords(v, r);
        mTouchOffsetX = mLastMotionX - r.left;
        mTouchOffsetY = mLastMotionY - r.top;

        v.clearFocus();
        v.setPressed(false);

        boolean willNotCache = v.willNotCacheDrawing();
        v.setWillNotCacheDrawing(false);
        v.buildDrawingCache();

        Bitmap viewBitmap = v.getDrawingCache();
        int width = viewBitmap.getWidth();
        int height = viewBitmap.getHeight();

        Matrix scale = new Matrix();
        float scaleFactor = v.getWidth();
        scaleFactor = (scaleFactor + DRAG_SCALE) /scaleFactor;
        scale.setScale(scaleFactor, scaleFactor);

        mAnimationTo = 1.0f;
        mAnimationFrom = 1.0f / scaleFactor;
        mAnimationDuration = ANIMATION_SCALE_UP_DURATION;
        mAnimationState = ANIMATION_STATE_STARTING;
        mAnimationType = ANIMATION_TYPE_SCALE;

        mDragBitmap = Bitmap.createBitmap(viewBitmap, 0, 0, width, height, scale, true);
        v.destroyDrawingCache();
        v.setWillNotCacheDrawing(willNotCache);

        final Bitmap dragBitmap = mDragBitmap;
        mBitmapOffsetX = (dragBitmap.getWidth() - width) / 2;
        mBitmapOffsetY = (dragBitmap.getHeight() - height) / 2;

        if (dragAction == DRAG_ACTION_MOVE) {
            v.setVisibility(GONE);
        }

        mDragPaint = null;
        mDragging = true;
        mShouldDrop = true;
        mOriginator = v;
        mDragSource = source;
        mDragInfo = dragInfo;

        mVibrator.vibrate(VIBRATE_DURATION);

        mEnteredRegion = false;

        invalidate();
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        return mDragging || super.dispatchKeyEvent(event);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);

        if (mDragging && mDragBitmap != null) {
            if (mAnimationState == ANIMATION_STATE_STARTING) {
                mAnimationStartTime = SystemClock.uptimeMillis();
                mAnimationState = ANIMATION_STATE_RUNNING;
            }

            if (mAnimationState == ANIMATION_STATE_RUNNING) {
                float normalized = (float) (SystemClock.uptimeMillis() - mAnimationStartTime) /
                        mAnimationDuration;
                if (normalized >= 1.0f) {
                    mAnimationState = ANIMATION_STATE_DONE;
                }
                normalized = Math.min(normalized, 1.0f);
                final float value = mAnimationFrom  + (mAnimationTo - mAnimationFrom) * normalized;

                switch (mAnimationType) {
                    case ANIMATION_TYPE_SCALE:
                        final Bitmap dragBitmap = mDragBitmap;
                        canvas.save();
                        canvas.translate(mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX,
                                mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY);
                        canvas.translate((dragBitmap.getWidth() * (1.0f - value)) / 2,
                                (dragBitmap.getHeight() * (1.0f - value)) / 2);
                        canvas.scale(value, value);
                        canvas.drawBitmap(dragBitmap, 0.0f, 0.0f, mDragPaint);
                        canvas.restore();
                        break;
                }
            } else {
                canvas.drawBitmap(mDragBitmap,
                        mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX,
                        mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY, mDragPaint);
            }
        }
    }

    private void endDrag() {
        if (mDragging) {
            mDragging = false;
            if (mDragBitmap != null) {
                mDragBitmap.recycle();
            }
            if (mOriginator != null) {
                mOriginator.setVisibility(VISIBLE);
            }
            if (mListener != null) {
                mListener.onDragEnd();
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();

        final float x = ev.getX();
        final float y = ev.getY();

        switch (action) {
            case MotionEvent.ACTION_MOVE:
                break;

            case MotionEvent.ACTION_DOWN:
                // Remember location of down touch
                mLastMotionX = x;
                mLastMotionY = y;
                mLastDropTarget = null;
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (mShouldDrop && drop(x, y)) {
                    mShouldDrop = false;
                }
                endDrag();
                break;
        }

        return mDragging;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!mDragging) {
            return false;
        }

        final int action = ev.getAction();
        final float x = ev.getX();
        final float y = ev.getY();

        switch (action) {
        case MotionEvent.ACTION_DOWN:

            // Remember where the motion event started
            mLastMotionX = x;
            mLastMotionY = y;

            if ((x < SCROLL_ZONE) || (x > getWidth() - SCROLL_ZONE)) {
                mScrollState = SCROLL_WAITING_IN_ZONE;
                postDelayed(mScrollRunnable, SCROLL_DELAY);
            } else {
                mScrollState = SCROLL_OUTSIDE_ZONE;
            }

            break;
        case MotionEvent.ACTION_MOVE:
            if (Launcher.sOpenGlEnabled) {
                mLastMotionX = x;
                mLastMotionY = y;

                invalidate();
            } else {
                final int scrollX = mScrollX;
                final int scrollY = mScrollY;

                final float touchX = mTouchOffsetX;
                final float touchY = mTouchOffsetY;

                final int offsetX = mBitmapOffsetX;
                final int offsetY = mBitmapOffsetY;

                int left = (int) (scrollX + mLastMotionX - touchX - offsetX);
                int top = (int) (scrollY + mLastMotionY - touchY - offsetY);

                final Bitmap dragBitmap = mDragBitmap;
                final int width = dragBitmap.getWidth();
                final int height = dragBitmap.getHeight();

                final Rect rect = mRect;
                rect.set(left - 1, top - 1, left + width + 1, top + height + 1);

                mLastMotionX = x;
                mLastMotionY = y;

                left = (int) (scrollX + x - touchX - offsetX);
                top = (int) (scrollY + y - touchY - offsetY);

                rect.union(left - 1, top - 1, left + width + 1, top + height + 1);
                invalidate(rect);
            }

            final int[] coordinates = mDropCoordinates;
            DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
            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;

            boolean inDragRegion = false;
            if (mDragRegion != null) {
                final RectF region = mDragRegion;
                final boolean inRegion = region.contains(ev.getRawX(), ev.getRawY());
                if (!mEnteredRegion && inRegion) {
                    mDragPaint = mTrashPaint;
                    mEnteredRegion = true;
                    inDragRegion = true;
                } else if (mEnteredRegion && !inRegion) {
                    mDragPaint = null;
                    mEnteredRegion = false;
                }
            }

            if (!inDragRegion && x < SCROLL_ZONE) {
                if (mScrollState == SCROLL_OUTSIDE_ZONE) {
                    mScrollState = SCROLL_WAITING_IN_ZONE;
                    mScrollRunnable.setDirection(SCROLL_LEFT);
                    postDelayed(mScrollRunnable, SCROLL_DELAY);
                }
            } else if (!inDragRegion && x > getWidth() - SCROLL_ZONE) {
                if (mScrollState == SCROLL_OUTSIDE_ZONE) {
                    mScrollState = SCROLL_WAITING_IN_ZONE;
                    mScrollRunnable.setDirection(SCROLL_RIGHT);
                    postDelayed(mScrollRunnable, SCROLL_DELAY);
                }
            } else {
                if (mScrollState == SCROLL_WAITING_IN_ZONE) {
                    mScrollState = SCROLL_OUTSIDE_ZONE;
                    mScrollRunnable.setDirection(SCROLL_RIGHT);
                    removeCallbacks(mScrollRunnable);
                }
            }

            break;
        case MotionEvent.ACTION_UP:
            removeCallbacks(mScrollRunnable);
            if (mShouldDrop) {
                drop(x, y);
                mShouldDrop = false;
            }
            endDrag();

            break;
        case MotionEvent.ACTION_CANCEL:
            endDrag();
        }

        return true;
    }

    private boolean drop(float x, float y) {
        invalidate();

        final int[] coordinates = mDropCoordinates;
        DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);

        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;
    }

    DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
        return findDropTarget(this, x, y, dropCoordinates);
    }

    private DropTarget findDropTarget(ViewGroup container, int x, int y, int[] dropCoordinates) {
        final Rect r = mDragRect;
        final int count = container.getChildCount();
        final int scrolledX = x + container.getScrollX();
        final int scrolledY = y + container.getScrollY();
        final View ignoredDropTarget = mIgnoredDropTarget;

        for (int i = count - 1; i >= 0; i--) {
            final View child = container.getChildAt(i);
            if (child.getVisibility() == VISIBLE && child != ignoredDropTarget) {
                child.getHitRect(r);
                if (r.contains(scrolledX, scrolledY)) {
                    DropTarget target = null;
                    if (child instanceof ViewGroup) {
                        x = scrolledX - child.getLeft();
                        y = scrolledY - child.getTop();
                        target = findDropTarget((ViewGroup) child, x, y, dropCoordinates);
                    }
                    if (target == null) {
                        if (child instanceof DropTarget) {
                            dropCoordinates[0] = x;
                            dropCoordinates[1] = y;
                            return (DropTarget) child;
                        }
                    } else {
                        return target;
                    }
                }
            }
        }

        return null;
    }

    public void setDragScoller(DragScroller scroller) {
        mDragScroller = scroller;
    }

    public void setDragListener(DragListener l) {
        mListener = l;
    }

    public void removeDragListener(DragListener l) {
        mListener = null;   
    }

    /**
     * Specifies the view that must be ignored when looking for a drop target.
     *
     * @param view The view that will not be taken into account while looking
     *        for a drop target.
     */
    void setIgnoredDropTarget(View view) {
        mIgnoredDropTarget = view;
    }

    /**
     * Specifies the delete region.
     *
     * @param region The rectangle in screen coordinates of the delete region.
     */
    void setDeleteRegion(RectF region) {
        mDragRegion = region;
    }

    private class ScrollRunnable implements Runnable {
        private int mDirection;

        ScrollRunnable() {
        }

        public void run() {
            if (mDragScroller != null) {
                if (mDirection == SCROLL_LEFT) {
                    mDragScroller.scrollLeft();
                } else {
                    mDragScroller.scrollRight();
                }
                mScrollState = SCROLL_OUTSIDE_ZONE;
            }
        }

        void setDirection(int direction) {
            mDirection = direction;
        }
    }    
}
分享到:
评论
1 楼 wzxf536 2011-08-28  
这个类是干嘛的?

相关推荐

    android Launcher源码详解

    Android Launcher 源码详解 Android Launcher 是 Android 系统中一个非常重要的组件,负责显示桌面程序和管理应用程序图标。了解 Launcher 的源码可以帮助我们更好地理解 Android 系统的设计思想和实现机制。本文...

    Android应用源码之Launcher2_源码.zip

    《深入剖析Android应用源码:聚焦Launcher2》 在Android操作系统中,Launcher是用户与系统交互的首要界面,它负责展示应用图标、快捷方式以及桌面小部件等。本篇文章将详细探讨Android应用源码中的Launcher2,这是...

    Android8.0 Launcher2源码

    `Launcher2`包含许多自定义视图,如`QuickStepView`(快速启动栏)、`DragLayer`(拖放层)等,它们扩展了Android的基础视图类,以满足特定需求。 ### 6. 广播接收器与服务 `BroadcastReceiver`用于监听系统广播,...

    Android_launcher的源码详细分析.pdf

    该源码分析了 Android_launcher 的主要组件和类,包括 Launcher.java、DragLayer.java、DragController.java、LauncherModel.java、Workspace.java、LauncherProvider.java、CellLayout.java、ItemInfo.java、User...

    Android项目源码安卓4.0Launcher原生桌面源码.zip

    《深入剖析Android 4.0 Launcher源码》 在Android世界中,Launcher是用户与操作系统交互的首要界面,它承担着展示应用图标、快捷方式、主屏幕小部件等任务。对于开发者来说,研究Launcher的源码是理解Android系统...

    android Launcher3 源码下载 从4 4 2剥离

    理解并分析Launcher3的源码对于开发者来说具有重要意义,可以帮助我们深入理解Android系统的运行机制,定制个性化桌面,或者开发自己的启动器应用。 首先,我们需要从官方AOSP(Android Open Source Project)仓库...

    Android桌面程序Launcher源码

    深入理解Android Launcher的源码可以帮助开发者更好地定制系统桌面,优化用户体验,或者开发自定义启动器应用。本文将详细探讨Android桌面程序Launcher的相关知识点。 首先,我们来看看Launcher的基本架构。Android...

    android lancher源码

    在Android 2.3(Gingerbread)版本中,Launcher源码提供了对主屏幕、应用抽屉、快捷方式和小部件等核心功能的实现。理解其源码有助于开发者深入掌握Android系统的运行机制,优化自定义Launcher或者进行桌面插件的...

    android桌面launcher源码 版本2.3

    5. **Drag and Drop**: Android桌面支持拖放操作,实现这一功能的关键是`DragLayer`和`DragController`。这些组件负责处理触摸事件,进行拖放操作,并更新UI。 6. **动画和过渡**: Android Launcher中的动画和过渡...

    android2.3 launcher 源码

    《Android 2.3 Launcher 源码解析》 Android 2.3,又被称为 Gingerbread,是Android操作系统的一个重要版本。在这个版本中,Launcher作为系统的核心组件之一,扮演着用户与系统交互的重要角色。Launcher,简单来说...

    android 4.1 launcher2 源码eclipse可以编译

    《深入解析Android 4.1 Launcher2源码与Eclipse编译》 在Android系统中,Launcher作为用户界面的核心部分,扮演着启动应用、管理桌面快捷方式和小部件的重要角色。在Android 4.1(代号Jelly Bean)版本中,Launcher...

    android Launcher2.20 源码

    这个源码版本对应的是Android 2.2(Froyo)系统,对于开发者来说,深入理解这个源码可以帮助他们自定义启动器、优化性能或者开发新的桌面功能。 一、Launcher2的架构 Launcher2 是一个基于Android Activity的组件...

    android Launcher源码

    《深入剖析Android 4.0 Launcher源码》 在Android操作系统中,Launcher是用户与系统交互的首要界面,也就是我们通常所说的桌面。它负责显示应用快捷方式、小部件以及主屏幕。本文将深入探讨Android 4.0 (Ice Cream ...

    android4.0 Launcher源码

    《深入解析Android 4.0 Launcher源码》 在Android操作系统中,Launcher是用户与系统交互的首要界面,它负责展示应用图标、桌面小部件以及管理屏幕。Android 4.0(Ice Cream Sandwich,简称ICS)是Android系统的一个...

    Andriod8.0 Launcher3源码

    Android 8.0引入了更流畅的过渡动画,这在`DragLayer`和`DropTarget`类中体现。通过`PropertyAnimator`实现平滑的拖放效果。 8. **个性化设置** 用户可以通过系统设置自定义Launcher3的壁纸、图标大小、网格布局...

    Android 7.1 Launcher源码

    Android 7.1 Launcher源码解析 Android 7.1的Launcher是系统桌面应用,它负责展示应用程序快捷方式、小部件以及主屏幕布局。深入理解其源码有助于开发者定制个性化启动器,提升用户体验,或者为自己的应用开发提供...

    android lanucher 2.3 源码

    在Android 2.3(Gingerbread)版本中,Launcher的源码提供了深入理解Android系统启动流程、界面定制以及应用程序管理机制的机会。让我们一起探索这个源码中的关键知识点。 1. **Android启动流程**: - `...

    android 4.0 Launcher2 源码

    以下是对 Android 4.0 Launcher2 源码的关键知识点的详细解析: 1. **组件结构**: - `Launcher` 类是 Launcher2 的核心,它是 Android 应用程序的基础组件,继承自 `Activity`。 - `Workspace` 和 `Hotseat` ...

    android launcher2.1源码,可运行,已经修改好

    《Android Launcher2.1源码解析与运行指南》 Android Launcher是系统启动器,它是用户与设备交互的首要界面,负责展示应用图标、桌面小部件等。本篇将深入探讨"android launcher2.1源码",并指导如何运行这个经过...

    android 2.3.3 Launcher源码

    《Android 2.3.3 Launcher源码解析》 Android 2.3.3,代号Gingerbread,是Google发布的Android系统的一个重要版本。在这个版本中,Launcher作为用户界面的核心部分,负责呈现桌面图标、小部件以及启动应用程序。...

Global site tag (gtag.js) - Google Analytics