仿Launcher Workspace左右滑动控件

修改Launcher的Workspace,去掉Drag相关的操作,精简为一个支持左右滑动的控件

每屏中可以自由放置layout



主要的问题是对

    @Override
    public boolean dispathTouchEvent(MotionEvent ev) {}

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {}

    @Override
    public boolean onTouchEvent(MotionEvent ev) {}

的理解,不然不好控制touch事件


代码贴上,其实没啥参考价值:

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3.       
  4.     <com.mylauncher.Workspace      
  5.     xmlns:android="http://schemas.android.com/apk/res/android"  
  6.     xmlns:launcher="http://schemas.android.com/apk/res/com.mylauncher"      
  7.         android:id="@+id/workspace"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent"  
  10.         android:scrollbars="horizontal"  
  11.         android:fadeScrollbars="true"  
  12.         launcher:defaultScreen="0">  
  13.           
  14.         <com.mylauncher.CellLayout   android:background="#ff0000ff"  
  15.             android:id="@+id/cell1"  
  16.             android:layout_width="match_parent"  
  17.             android:layout_height="match_parent"      
  18.             android:orientation="vertical"        
  19.             >  
  20.             <TextView      
  21.             android:layout_width="fill_parent"  
  22.             android:layout_height="wrap_content"  
  23.             android:textSize="30sp"                       
  24.             android:textStyle="bold"              
  25.             android:text="@string/screen1" />  
  26.             <Button        
  27.             android:layout_width="fill_parent"  
  28.             android:layout_height="wrap_content"  
  29.             android:textSize="30sp"                       
  30.             android:textStyle="bold"              
  31.             android:text="@string/screen1" />              
  32.               
  33.         </com.mylauncher.CellLayout>  
  34.           
  35.         <com.mylauncher.CellLayout   android:background="#ffff0000"  
  36.             android:id="@+id/cell2"  
  37.             android:layout_width="match_parent"  
  38.             android:layout_height="match_parent"    
  39.             android:orientation="vertical"            
  40.             >  
  41.             <TextView      
  42.             android:layout_width="fill_parent"  
  43.             android:layout_height="wrap_content"  
  44.             android:textSize="30sp"                       
  45.             android:textStyle="bold"              
  46.             android:text="@string/screen2" />       
  47.             <Button         
  48.             android:layout_width="fill_parent"  
  49.             android:layout_height="wrap_content"  
  50.             android:textSize="30sp"                       
  51.             android:textStyle="bold"              
  52.             android:text="@string/screen2" />                         
  53.         </com.mylauncher.CellLayout>      
  54.           
  55.         <com.mylauncher.CellLayout   android:background="#ff00ff00"  
  56.             android:id="@+id/cell3"  
  57.             android:layout_width="match_parent"  
  58.             android:layout_height="match_parent"     
  59.             android:orientation="vertical"        
  60.             >  
  61.             <TextView      
  62.             android:layout_width="fill_parent"  
  63.             android:layout_height="wrap_content"  
  64.             android:textSize="30sp"                       
  65.             android:textStyle="bold"              
  66.             android:text="@string/screen3" />        
  67.             <Button         
  68.             android:layout_width="fill_parent"  
  69.             android:layout_height="wrap_content"  
  70.             android:textSize="30sp"                       
  71.             android:textStyle="bold"              
  72.             android:text="@string/screen3" />                    
  73.         </com.mylauncher.CellLayout>                
  74.           
  75.     </com.mylauncher.Workspace>  

[html]  view plain copy
  1. package com.mylauncher;  
  2.   
  3. import android.app.WallpaperManager;  
  4. import android.content.Context;  
  5. import android.content.res.TypedArray;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Rect;  
  8. import android.graphics.drawable.Drawable;  
  9. import android.os.IBinder;  
  10. import android.os.Parcel;  
  11. import android.os.Parcelable;  
  12. import android.util.AttributeSet;  
  13. import android.util.Log;  
  14. import android.view.MotionEvent;  
  15. import android.view.VelocityTracker;  
  16. import android.view.View;  
  17. import android.view.ViewConfiguration;  
  18. import android.view.ViewGroup;  
  19. import android.view.ViewParent;  
  20. import android.view.animation.Interpolator;  
  21. import android.widget.Scroller;  
  22.   
  23. /**  
  24.  * The workspace is a wide area with a wallpaper and a finite number of screens. Each  
  25.  * screen contains a number of icons, folders or widgets the user can interact with.  
  26.  * A workspace is meant to be used with a fixed width only.  
  27.  */  
  28. public class Workspace extends ViewGroup {  
  29.     @SuppressWarnings({"UnusedDeclaration"})  
  30.     private static final String TAG = "MyLauncher.Workspace";  
  31.     private static final int INVALID_SCREEN = -1;  
  32.       
  33.     /**  
  34.      * The velocity at which a fling gesture will cause us to snap to the next screen  
  35.      */  
  36.     private static final int SNAP_VELOCITY = 600;  
  37.   
  38.     private final WallpaperManager mWallpaperManager;  
  39.       
  40.     private int mDefaultScreen;  
  41.   
  42.     private boolean mFirstLayout = true;  
  43.   
  44.     private int mCurrentScreen;  
  45.     private int mNextScreen = INVALID_SCREEN;  
  46.     private Scroller mScroller;  
  47.     private VelocityTracker mVelocityTracker;  
  48.   
  49.   
  50.       
  51.     /**  
  52.      * Target drop area calculated during last acceptDrop call.  
  53.      */  
  54.     private int[] mTargetCell = null;  
  55.   
  56.     private float mLastMotionX;  
  57.     private float mLastMotionY;  
  58.       
  59.     private final static int TOUCH_STATE_REST = 0;  
  60.     private final static int TOUCH_STATE_SCROLLING = 1;  
  61.   
  62.     private int mTouchState = TOUCH_STATE_REST;  
  63.   
  64.     private OnLongClickListener mLongClickListener;  
  65.   
  66.   
  67.       
  68.   
  69.       
  70.     private int[] mTempCell = new int[2];  
  71.     private int[] mTempEstimate = new int[2];  
  72.   
  73.     private boolean mAllowLongPress = true;  
  74.   
  75.     private int mTouchSlop;  
  76.     private int mMaximumVelocity;  
  77.       
  78.     private static final int INVALID_POINTER = -1;  
  79.   
  80.     private int mActivePointerId = INVALID_POINTER;  
  81.       
  82.     private Drawable mPreviousIndicator;  
  83.     private Drawable mNextIndicator;  
  84.       
  85.     private static final float NANOTIME_DIV = 1000000000.0f;  
  86.     private static final float SMOOTHING_SPEED = 0.75f;  
  87.     private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));  
  88.     private float mSmoothingTime;  
  89.     private float mTouchX;  
  90.   
  91.     private WorkspaceOvershootInterpolator mScrollInterpolator;  
  92.   
  93.     private static final float BASELINE_FLING_VELOCITY = 2500.f;  
  94.     private static final float FLING_VELOCITY_INFLUENCE = 0.4f;  
  95.       
  96.     private static class WorkspaceOvershootInterpolator implements Interpolator {  
  97.         private static final float DEFAULT_TENSION = 1.3f;  
  98.         private float mTension;  
  99.   
  100.         public WorkspaceOvershootInterpolator() {  
  101.             mTension = DEFAULT_TENSION;  
  102.         }  
  103.           
  104.         public void setDistance(int distance) {  
  105.             mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;  
  106.         }  
  107.   
  108.         public void disableSettle() {  
  109.             mTension = 0.f;  
  110.         }  
  111.   
  112.         public float getInterpolation(float t) {  
  113.             // _o(t) = t * t * ((tension + 1) * t + tension)  
  114.             // o(t) = _o(t - 1) + 1  
  115.             t -1.0f;  
  116.             return t * t * ((mTension + 1) * t + mTension) + 1.0f;  
  117.         }  
  118.     }  
  119.       
  120.     /**  
  121.      * Used to inflate the Workspace from XML.  
  122.      *  
  123.      * @param context The application's context.  
  124.      * @param attrs The attribtues set containing the Workspace's customization values.  
  125.      */  
  126.     public Workspace(Context context, AttributeSet attrs) {  
  127.         this(context, attrs, 0);  
  128.     }  
  129.   
  130.     /**  
  131.      * Used to inflate the Workspace from XML.  
  132.      *  
  133.      * @param context The application's context.  
  134.      * @param attrs The attribtues set containing the Workspace's customization values.  
  135.      * @param defStyle Unused.  
  136.      */  
  137.     public Workspace(Context context, AttributeSet attrs, int defStyle) {  
  138.         super(context, attrs, defStyle);  
  139.   
  140.         mWallpaperManager = WallpaperManager.getInstance(context);  
  141.           
  142.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0);  
  143.         mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1);  
  144.         a.recycle();  
  145.   
  146.         setHapticFeedbackEnabled(false);  
  147.         initWorkspace();  
  148.     }  
  149.   
  150.     /**  
  151.      * Initializes various states for this workspace.  
  152.      */  
  153.     private void initWorkspace() {  
  154.         Context context = getContext();  
  155.         mScrollInterpolator = new WorkspaceOvershootInterpolator();  
  156.         mScroller = new Scroller(context, mScrollInterpolator);  
  157.         mCurrentScreen = mDefaultScreen;  
  158.   
  159.   
  160.         final ViewConfiguration configuration = ViewConfiguration.get(getContext());  
  161.         mTouchSlop = configuration.getScaledTouchSlop();  
  162.         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();  
  163.     }  
  164.   
  165.   
  166.   
  167.   
  168.   
  169.   
  170.   
  171.   
  172.   
  173.   
  174.   
  175.   
  176.   
  177.   
  178.   
  179.     boolean isDefaultScreenShowing() {  
  180.         return mCurrentScreen == mDefaultScreen;  
  181.     }  
  182.   
  183.     /**  
  184.      * Returns the index of the currently displayed screen.  
  185.      *  
  186.      * @return The index of the currently displayed screen.  
  187.      */  
  188.     int getCurrentScreen() {  
  189.         return mCurrentScreen;  
  190.     }  
  191.   
  192.     /**  
  193.      * Sets the current screen.  
  194.      *  
  195.      * @param currentScreen  
  196.      */  
  197.     void setCurrentScreen(int currentScreen) {  
  198.         if (!mScroller.isFinished()) mScroller.abortAnimation();  
  199.           
  200.         mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));  
  201.         //mPreviousIndicator.setLevel(mCurrentScreen);  
  202.         //mNextIndicator.setLevel(mCurrentScreen);  
  203.         scrollTo(mCurrentScreen * getWidth(), 0);  
  204.   
  205.         invalidate();  
  206.     }  
  207.   
  208.   
  209.   
  210.   
  211.     /**  
  212.      * Registers the specified listener on each screen contained in this workspace.  
  213.      *  
  214.      * @param l The listener used to respond to long clicks.  
  215.      */  
  216.     @Override  
  217.     public void setOnLongClickListener(OnLongClickListener l) {  
  218.         mLongClickListener = l;  
  219.         final int count = getChildCount();  
  220.         for (int i = 0; i < count; i++) {  
  221.             getChildAt(i).setOnLongClickListener(l);  
  222.         }  
  223.     }  
  224.   
  225.   
  226.   
  227.     private void updateWallpaperOffset(int scrollRange) {  
  228.         IBinder token = getWindowToken();  
  229.         if (token != null) {  
  230.             mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 );  
  231.             mWallpaperManager.setWallpaperOffsets(getWindowToken(),  
  232.                     Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0);  
  233.         }  
  234.     }  
  235.       
  236.     @Override  
  237.     public void scrollTo(int x, int y) {  
  238.         super.scrollTo(x, y);  
  239.         mTouchX = x;  
  240.         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  241.     }  
  242.       
  243.     @Override  
  244.     public void computeScroll() {  
  245.         if (mScroller.computeScrollOffset()) {  
  246.             mTouchX = mScrollX = mScroller.getCurrX();  
  247.             mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  248.             mScrollY = mScroller.getCurrY();  
  249.               
  250.             postInvalidate();  
  251.         } else if (mNextScreen != INVALID_SCREEN) {  
  252.             mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));  
  253.             //mPreviousIndicator.setLevel(mCurrentScreen);  
  254.             //mNextIndicator.setLevel(mCurrentScreen);  
  255.   
  256.             mNextScreen = INVALID_SCREEN;  
  257.             //clearChildrenCache();  
  258.         } else if (mTouchState == TOUCH_STATE_SCROLLING) {  
  259.             final float now = System.nanoTime() / NANOTIME_DIV;  
  260.             final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);  
  261.             final float dx = mTouchX - mScrollX;  
  262.             mScrollX += dx * e;  
  263.             mSmoothingTime = now;  
  264.   
  265.             // Keep generating points as long as we're more than 1px away from the target  
  266.             if (dx > 1.f || dx < -1.f) {  
  267.                   
  268.                 postInvalidate();  
  269.             }  
  270.         }  
  271.     }  
  272.   
  273.     @Override  
  274.     protected void dispatchDraw(Canvas canvas) {  
  275.         boolean restore = false;  
  276.         int restoreCount = 0;  
  277.   
  278.         // ViewGroup.dispatchDraw() supports many features we don't need:  
  279.         // clip to padding, layout animation, animation listener, disappearing  
  280.         // children, etc. The following implementation attempts to fast-track  
  281.         // the drawing dispatch by drawing only what we know needs to be drawn.  
  282.   
  283.         boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;  
  284.         // If we are not scrolling or flinging, draw only the current screen  
  285.         if (fastDraw) {  
  286.             drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());  
  287.         } else {  
  288.             final long drawingTime = getDrawingTime();  
  289.             final float scrollPos = (float) mScrollX / getWidth();  
  290.             final int leftScreen = (int) scrollPos;  
  291.             final int rightScreen = leftScreen + 1;  
  292.             if (leftScreen >= 0) {  
  293.                 drawChild(canvas, getChildAt(leftScreen), drawingTime);  
  294.             }  
  295.             if (scrollPos != leftScreen && rightScreen < getChildCount()) {  
  296.                 drawChild(canvas, getChildAt(rightScreen), drawingTime);  
  297.             }  
  298.         }  
  299.   
  300.         if (restore) {  
  301.             canvas.restoreToCount(restoreCount);  
  302.         }  
  303.     }  
  304.   
  305.     protected void onAttachedToWindow() {  
  306.         super.onAttachedToWindow();  
  307.         computeScroll();  
  308.   
  309.     }  
  310.   
  311.     @Override  
  312.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  313.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  314.   
  315.         final int width = MeasureSpec.getSize(widthMeasureSpec);  
  316.         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  317.         if (widthMode != MeasureSpec.EXACTLY) {  
  318.             throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");  
  319.         }  
  320.   
  321.         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  322.         if (heightMode != MeasureSpec.EXACTLY) {  
  323.             throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");  
  324.         }  
  325.   
  326.         // The children are given the same width and height as the workspace  
  327.         final int count = getChildCount();  
  328.         for (int i = 0; i < count; i++) {  
  329.             getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  
  330.         }  
  331.   
  332.   
  333.         if (mFirstLayout) {  
  334.             setHorizontalScrollBarEnabled(false);  
  335.             scrollTo(mCurrentScreen * width, 0);  
  336.             setHorizontalScrollBarEnabled(true);  
  337.             updateWallpaperOffset(width * (getChildCount() - 1));  
  338.             mFirstLayout = false;  
  339.         }  
  340.     }  
  341.   
  342.     @Override  
  343.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  344.         int childLeft = 0;  
  345.   
  346.         final int count = getChildCount();  
  347.         for (int i = 0; i < count; i++) {  
  348.             final View child = getChildAt(i);  
  349.             if (child.getVisibility() != View.GONE) {  
  350.                 final int childWidth = child.getMeasuredWidth();  
  351.                 child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());  
  352.                 childLeft += childWidth;  
  353.             }  
  354.         }  
  355.     }  
  356.   
  357.     @Override  
  358.     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {  
  359.         int screen = indexOfChild(child);  
  360.         if (screen != mCurrentScreen || !mScroller.isFinished()) {  
  361.             snapToScreen(screen);  
  362.             return true;  
  363.         }  
  364.         return false;  
  365.     }  
  366.   
  367.   
  368.   
  369.   
  370.     @Override  
  371.     public boolean dispatchUnhandledMove(View focused, int direction) {  
  372.         if (direction == View.FOCUS_LEFT) {  
  373.             if (getCurrentScreen() > 0) {  
  374.                 snapToScreen(getCurrentScreen() - 1);  
  375.                 return true;  
  376.             }  
  377.         } else if (direction == View.FOCUS_RIGHT) {  
  378.             if (getCurrentScreen() < getChildCount() - 1) {  
  379.                 snapToScreen(getCurrentScreen() + 1);  
  380.                 return true;  
  381.             }  
  382.         }  
  383.         return super.dispatchUnhandledMove(focused, direction);  
  384.     }  
  385.   
  386.   
  387.   
  388.   
  389.     @Override  
  390.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  391.   
  392.   
  393.         /*  
  394.          * This method JUST determines whether we want to intercept the motion.  
  395.          * If we return true, onTouchEvent will be called and we do the actual  
  396.          * scrolling there.  
  397.          */  
  398.   
  399.         /*  
  400.          * Shortcut the most recurring case: the user is in the dragging  
  401.          * state and he is moving his finger.  We want to intercept this  
  402.          * motion.  
  403.          */  
  404.            
  405.         final int action = ev.getAction();  
  406.                  
  407.           
  408.         Log.d(TAG, "onInterceptTouchEvent, action: " + action + " mTouchState: " + mTouchState);  
  409.           
  410.         if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {  
  411.             Log.d(TAG, "onInterceptTouchEvent, MotionEvent.ACTION_MOVE mTouchState: " + mTouchState);  
  412.             return true;  
  413.         }  
  414.   
  415.         acquireVelocityTrackerAndAddMovement(ev);  
  416.           
  417.         switch (action & MotionEvent.ACTION_MASK) {  
  418.             case MotionEvent.ACTION_MOVE: {  
  419.                 Log.d(TAG, "onInterceptTouchEvent.ACTION_MOVE.................");  
  420.                 /*  
  421.                  * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check  
  422.                  * whether the user has moved far enough from his original down touch.  
  423.                  */  
  424.   
  425.                 /*  
  426.                  * Locally do absolute value. mLastMotionX is set to the y value  
  427.                  * of the down event.  
  428.                  */  
  429.                 final int pointerIndex = ev.findPointerIndex(mActivePointerId);  
  430.                 final float x = ev.getX(pointerIndex);  
  431.                 final float y = ev.getY(pointerIndex);  
  432.                 final int xDiff = (int) Math.abs(x - mLastMotionX);  
  433.                 final int yDiff = (int) Math.abs(y - mLastMotionY);  
  434.   
  435.                 final int touchSlop = mTouchSlop;  
  436.                 boolean xMoved = xDiff > touchSlop;  
  437.                 boolean yMoved = yDiff > touchSlop;  
  438.                   
  439.                 if (xMoved || yMoved) {  
  440.                       
  441.                     if (xMoved) {  
  442.                         Log.d(TAG, "onInterceptTouchEvent.ACTION_MOVE.TOUCH_STATE_SCROLLING................");  
  443.                         // Scroll if the user moved far enough along the X axis  
  444.                         mTouchState = TOUCH_STATE_SCROLLING;  
  445.                         mLastMotionX = x;  
  446.                         mTouchX = getScrollX();  
  447.                         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  448.                         //enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);  
  449.                     }  
  450.                     // Either way, cancel any pending longpress  
  451.                     if (mAllowLongPress) {  
  452.                         mAllowLongPress = false;  
  453.                         // Try canceling the long press. It could also have been scheduled  
  454.                         // by a distant descendant, so use the mAllowLongPress flag to block  
  455.                         // everything  
  456.                         final View currentScreen = getChildAt(mCurrentScreen);  
  457.                         currentScreen.cancelLongPress();  
  458.                     }  
  459.                 }  
  460.                 break;  
  461.             }  
  462.   
  463.             case MotionEvent.ACTION_DOWN: {  
  464.                 Log.d(TAG, "onInterceptTouchEvent.ACTION_DOWN.................");  
  465.                 final float x = ev.getX();  
  466.                 final float y = ev.getY();  
  467.                 // Remember location of down touch  
  468.                 mLastMotionX = x;  
  469.                 mLastMotionY = y;  
  470.                 mActivePointerId = ev.getPointerId(0);  
  471.                 mAllowLongPress = true;  
  472.   
  473.                 /*  
  474.                  * If being flinged and user touches the screen, initiate drag;  
  475.                  * otherwise don't.  mScroller.isFinished should be false when  
  476.                  * being flinged.  
  477.                  */  
  478.                 Log.d(TAG, "mScroller.isFinished()................." + mScroller.isFinished());  
  479.                 mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;  
  480.                 break;  
  481.             }  
  482.   
  483.             case MotionEvent.ACTION_CANCEL:  
  484.             case MotionEvent.ACTION_UP:  
  485.                 Log.d(TAG, "onInterceptTouchEvent.ACTION_UP.................");  
  486.   
  487.                   
  488.                 // Release the drag  
  489.                 //clearChildrenCache();  
  490.                 mTouchState = TOUCH_STATE_REST;  
  491.                 mActivePointerId = INVALID_POINTER;  
  492.                 mAllowLongPress = false;  
  493.                 releaseVelocityTracker();  
  494.                 break;  
  495.                   
  496.             case MotionEvent.ACTION_POINTER_UP:  
  497.                 Log.d(TAG, "onInterceptTouchEvent.ACTION_POINTER_UP.................");  
  498.                 onSecondaryPointerUp(ev);  
  499.                 break;  
  500.         }  
  501.   
  502.         /*  
  503.          * The only time we want to intercept motion events is if we are in the  
  504.          * drag mode.  
  505.          */  
  506.         Log.d(TAG, "onInterceptTouchEvent.mTouchState != TOUCH_STATE_REST................." + (mTouchState != TOUCH_STATE_REST));    
  507.         return mTouchState != TOUCH_STATE_REST;  
  508.     }  
  509.       
  510.     private void onSecondaryPointerUp(MotionEvent ev) {  
  511.         final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>  
  512.                 MotionEvent.ACTION_POINTER_INDEX_SHIFT;  
  513.         final int pointerId = ev.getPointerId(pointerIndex);  
  514.         if (pointerId == mActivePointerId) {  
  515.             // This was our active pointer going up. Choose a new  
  516.             // active pointer and adjust accordingly.  
  517.             // TODO: Make this decision more intelligent.  
  518.             final int newPointerIndex = pointerIndex == 0 ? 1 : 0;  
  519.             mLastMotionX = ev.getX(newPointerIndex);  
  520.             mLastMotionY = ev.getY(newPointerIndex);  
  521.             mActivePointerId = ev.getPointerId(newPointerIndex);  
  522.             if (mVelocityTracker != null) {  
  523.                 mVelocityTracker.clear();  
  524.             }  
  525.         }  
  526.     }  
  527.   
  528.     /**  
  529.      * If one of our descendant views decides that it could be focused now, only  
  530.      * pass that along if it's on the current screen.  
  531.      *  
  532.      * This happens when live folders requery, and if they're off screen, they  
  533.      * end up calling requestFocus, which pulls it on screen.  
  534.      */  
  535.     @Override  
  536.     public void focusableViewAvailable(View focused) {  
  537.         View current = getChildAt(mCurrentScreen);  
  538.         View v = focused;  
  539.         while (true) {  
  540.             if (v == current) {  
  541.                 super.focusableViewAvailable(focused);  
  542.                 return;  
  543.             }  
  544.             if (v == this) {  
  545.                 return;  
  546.             }  
  547.             ViewParent parent = v.getParent();  
  548.             if (parent instanceof View) {  
  549.                 v = (View)v.getParent();  
  550.             } else {  
  551.                 return;  
  552.             }  
  553.         }  
  554.     }  
  555.   
  556.   
  557.   
  558.   
  559.     @Override  
  560.     public boolean onTouchEvent(MotionEvent ev) {  
  561.           
  562.   
  563.   
  564.         acquireVelocityTrackerAndAddMovement(ev);  
  565.   
  566.         final int action = ev.getAction();  
  567.   
  568.         switch (action & MotionEvent.ACTION_MASK) {  
  569.         case MotionEvent.ACTION_DOWN:  
  570.             Log.d(TAG, "onTouchEvent.ACTION_DOWN.................");  
  571.             /*  
  572.              * If being flinged and user touches, stop the fling. isFinished  
  573.              * will be false if being flinged.  
  574.              */  
  575.             if (!mScroller.isFinished()) {  
  576.                 mScroller.abortAnimation();  
  577.             }  
  578.   
  579.             // Remember where the motion event started  
  580.             mLastMotionX = ev.getX();  
  581.             mActivePointerId = ev.getPointerId(0);  
  582.             if (mTouchState == TOUCH_STATE_SCROLLING) {  
  583.                 //enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);  
  584.             }  
  585.             break;  
  586.         case MotionEvent.ACTION_MOVE:  
  587.             Log.d(TAG, "onTouchEvent.ACTION_MOVE.................");  
  588.             if (mTouchState == TOUCH_STATE_SCROLLING) {  
  589.                 Log.d(TAG, "onTouchEvent.ACTION_MOVE.TOUCH_STATE_SCROLLING................");  
  590.                 // Scroll to follow the motion event  
  591.                 final int pointerIndex = ev.findPointerIndex(mActivePointerId);  
  592.                 final float x = ev.getX(pointerIndex);  
  593.                 final float deltaX = mLastMotionX - x;  
  594.                 mLastMotionX = x;  
  595.   
  596.                 if (deltaX < 0) {  
  597.                     if (mTouchX > 0) {  
  598.                         mTouchX += Math.max(-mTouchX, deltaX);  
  599.                         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  600.                         invalidate();  
  601.                     }  
  602.                 } else if (deltaX > 0) {  
  603.                     final float availableToScroll = getChildAt(getChildCount() - 1).getRight() -  
  604.                             mTouchX - getWidth();  
  605.                     if (availableToScroll > 0) {  
  606.                         mTouchX += Math.min(availableToScroll, deltaX);  
  607.                         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  608.                         invalidate();  
  609.                     }  
  610.                 } else {  
  611.                     awakenScrollBars();  
  612.                 }  
  613.             }  
  614.             break;  
  615.         case MotionEvent.ACTION_UP:  
  616.             Log.d(TAG, "onTouchEvent.ACTION_UP.................");  
  617.             if (mTouchState == TOUCH_STATE_SCROLLING) {  
  618.                 final VelocityTracker velocityTracker = mVelocityTracker;  
  619.                 velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
  620.                 final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);  
  621.                   
  622.                 final int screenWidth = getWidth();  
  623.                 final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;  
  624.                 final float scrolledPos = (float) getScrollX() / screenWidth;  
  625.                   
  626.                 if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {  
  627.                     // Fling hard enough to move left.  
  628.                     // Don't fling across more than one screen at a time.  
  629.                     final int bound = scrolledPos < whichScreen ?  
  630.                             mCurrentScreen - 1 : mCurrentScreen;  
  631.                     snapToScreen(Math.min(whichScreen, bound), velocityX, true);  
  632.                 } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {  
  633.                     // Fling hard enough to move right  
  634.                     // Don't fling across more than one screen at a time.  
  635.                     final int bound = scrolledPos > whichScreen ?  
  636.                             mCurrentScreen + 1 : mCurrentScreen;  
  637.                     snapToScreen(Math.max(whichScreen, bound), velocityX, true);  
  638.                 } else {  
  639.                     snapToScreen(whichScreen, 0, true);  
  640.                 }  
  641.             }  
  642.             mTouchState = TOUCH_STATE_REST;  
  643.             mActivePointerId = INVALID_POINTER;  
  644.             releaseVelocityTracker();  
  645.             break;  
  646.         case MotionEvent.ACTION_CANCEL:  
  647.             if (mTouchState == TOUCH_STATE_SCROLLING) {  
  648.                 final int screenWidth = getWidth();  
  649.                 final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;  
  650.                 snapToScreen(whichScreen, 0, true);  
  651.             }  
  652.             mTouchState = TOUCH_STATE_REST;  
  653.             mActivePointerId = INVALID_POINTER;  
  654.             releaseVelocityTracker();  
  655.             break;  
  656.         case MotionEvent.ACTION_POINTER_UP:  
  657.             Log.d(TAG, "onTouchEvent.ACTION_POINTER_UP.................");  
  658.             onSecondaryPointerUp(ev);  
  659.             break;  
  660.         }  
  661.   
  662.         return true;  
  663.     }  
  664.       
  665.     private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {  
  666.         if (mVelocityTracker == null) {  
  667.             mVelocityTracker = VelocityTracker.obtain();  
  668.         }  
  669.         mVelocityTracker.addMovement(ev);  
  670.     }  
  671.   
  672.     private void releaseVelocityTracker() {  
  673.         if (mVelocityTracker != null) {  
  674.             mVelocityTracker.recycle();  
  675.             mVelocityTracker = null;  
  676.         }  
  677.     }  
  678.   
  679.     void snapToScreen(int whichScreen) {  
  680.         snapToScreen(whichScreen, 0, false);  
  681.     }  
  682.   
  683.     private void snapToScreen(int whichScreen, int velocity, boolean settle) {  
  684.         //if (!mScroller.isFinished()) return;  
  685.   
  686.         whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));  
  687.           
  688.   
  689.         //enableChildrenCache(mCurrentScreen, whichScreen);  
  690.   
  691.         mNextScreen = whichScreen;  
  692.   
  693.         //mPreviousIndicator.setLevel(mNextScreen);  
  694.         //mNextIndicator.setLevel(mNextScreen);  
  695.   
  696.         View focusedChild = getFocusedChild();  
  697.         if (focusedChild != null && whichScreen != mCurrentScreen &&  
  698.                 focusedChild == getChildAt(mCurrentScreen)) {  
  699.             focusedChild.clearFocus();  
  700.         }  
  701.           
  702.         final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));  
  703.         final int newX = whichScreen * getWidth();  
  704.         final int delta = newX - mScrollX;  
  705.         int duration = (screenDelta + 1) * 100;  
  706.   
  707.         if (!mScroller.isFinished()) {  
  708.             mScroller.abortAnimation();  
  709.         }  
  710.           
  711.         if (settle) {  
  712.             mScrollInterpolator.setDistance(screenDelta);  
  713.         } else {  
  714.             mScrollInterpolator.disableSettle();  
  715.         }  
  716.           
  717.         velocity = Math.abs(velocity);  
  718.         if (velocity > 0) {  
  719.             duration += (duration / (velocity / BASELINE_FLING_VELOCITY))  
  720.                     * FLING_VELOCITY_INFLUENCE;  
  721.         } else {  
  722.             duration += 100;  
  723.         }  
  724.   
  725.         awakenScrollBars(duration);  
  726.         mScroller.startScroll(mScrollX, 0, delta, 0, duration);  
  727.         invalidate();  
  728.     }  
  729.   
  730.   
  731.   
  732.     @Override  
  733.     protected Parcelable onSaveInstanceState() {  
  734.         final SavedState state = new SavedState(super.onSaveInstanceState());  
  735.         state.currentScreen = mCurrentScreen;  
  736.         return state;  
  737.     }  
  738.   
  739.     @Override  
  740.     protected void onRestoreInstanceState(Parcelable state) {  
  741.         SavedState savedState = (SavedState) state;  
  742.         super.onRestoreInstanceState(savedState.getSuperState());  
  743.         if (savedState.currentScreen != -1) {  
  744.             mCurrentScreen = savedState.currentScreen;  
  745.   
  746.         }  
  747.     }  
  748.   
  749.   
  750.     public void scrollLeft() {  
  751.         Log.d(TAG, "scrollLeft.................");  
  752.          
  753.         if (mScroller.isFinished()) {  
  754.             if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);  
  755.         } else {  
  756.             if (mNextScreen > 0) snapToScreen(mNextScreen - 1);              
  757.         }  
  758.     }  
  759.   
  760.     public void scrollRight() {  
  761.         Log.d(TAG, "scrollRight.................");  
  762.   
  763.         if (mScroller.isFinished()) {  
  764.             if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);  
  765.         } else {  
  766.             if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);              
  767.         }  
  768.     }  
  769.   
  770.     public int getScreenForView(View v) {  
  771.         int result = -1;  
  772.         if (v != null) {  
  773.             ViewParent vp = v.getParent();  
  774.             int count = getChildCount();  
  775.             for (int i = 0; i < count; i++) {  
  776.                 if (vp == getChildAt(i)) {  
  777.                     return i;  
  778.                 }  
  779.             }  
  780.         }  
  781.         return result;  
  782.     }  
  783.   
  784.   
  785.     /**  
  786.      * @return True is long presses are still allowed for the current touch  
  787.      */  
  788.     public boolean allowLongPress() {  
  789.         return mAllowLongPress;  
  790.     }  
  791.       
  792.     /**  
  793.      * Set true to allow long-press events to be triggered, usually checked by  
  794.      * {@link Launcher} to accept or block dpad-initiated long-presses.  
  795.      */  
  796.     public void setAllowLongPress(boolean allowLongPress) {  
  797.         mAllowLongPress = allowLongPress;  
  798.     }  
  799.   
  800.      
  801.   
  802.     void moveToDefaultScreen(boolean animate) {  
  803.         if (animate) {  
  804.             snapToScreen(mDefaultScreen);  
  805.         } else {  
  806.             setCurrentScreen(mDefaultScreen);  
  807.         }  
  808.         getChildAt(mDefaultScreen).requestFocus();  
  809.     }  
  810.   
  811. //    void setIndicators(Drawable previous, Drawable next) {  
  812. //        mPreviousIndicator = previous;  
  813. //        mNextIndicator = next;  
  814. //        previous.setLevel(mCurrentScreen);  
  815. //        next.setLevel(mCurrentScreen);  
  816. //    }  
  817.   
  818.     public static class SavedState extends BaseSavedState {  
  819.         int currentScreen = -1;  
  820.   
  821.         SavedState(Parcelable superState) {  
  822.             super(superState);  
  823.         }  
  824.   
  825.         private SavedState(Parcel in) {  
  826.             super(in);  
  827.             currentScreen = in.readInt();  
  828.         }  
  829.   
  830.         @Override  
  831.         public void writeToParcel(Parcel out, int flags) {  
  832.             super.writeToParcel(out, flags);  
  833.             out.writeInt(currentScreen);  
  834.         }  
  835.   
  836.         public static final Parcelable.Creator<SavedState> CREATOR =  
  837.                 new Parcelable.Creator<SavedState>() {  
  838.             public SavedState createFromParcel(Parcel in) {  
  839.                 return new SavedState(in);  
  840.             }  
  841.   
  842.             public SavedState[] newArray(int size) {  
  843.                 return new SavedState[size];  
  844.             }  
  845.         };  
  846.     }  
  847. }  
[html]  view plain copy
  1. package com.mylauncher;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.view.View;  
  6. import android.widget.LinearLayout;  
  7. import android.view.MotionEvent;  
  8. import android.util.Log;  
  9.   
  10. public class CellLayout extends LinearLayout {  
  11.     private static final String TAG = "MyLauncher.CellLayout";  
  12.     public CellLayout(Context context, AttributeSet attrs) {  
  13.         super(context, attrs);  
  14.         // TODO Auto-generated constructor stub  
  15.     }  
  16.   
  17.     @Override  
  18.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  19.         Log.d(TAG, "onInterceptTouchEvent, action=" + ev.getAction());  
  20.         return true;  
  21.     }  
  22.       
  23.     @Override  
  24.     public boolean onTouchEvent(MotionEvent ev) {  
  25.         Log.d(TAG, "onTouchEvent, action=" + ev.getAction());  
  26.         return true;  
  27.     }      
  28.       
  29. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值