<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: How to implement Swipe action in Android</title>
	<atom:link href="http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/</link>
	<description>Mobile App Dev</description>
	<lastBuildDate>Thu, 07 Oct 2010 07:18:02 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
	<item>
		<title>By: Eric Taix</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-399</link>
		<dc:creator>Eric Taix</dc:creator>
		<pubDate>Thu, 07 Oct 2010 07:18:02 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-399</guid>
		<description>Hi everybody,

Many users asked my to share the project so I created a project at Google code
http://code.google.com/p/andro-views/

Still have issues ! This project is opensource under Apache licence. It is provided as it for free. If you fixed an issue, please send me your corrections.</description>
		<content:encoded><![CDATA[<p>Hi everybody,</p>
<p>Many users asked my to share the project so I created a project at Google code<br />
<a href="http://code.google.com/p/andro-views/" rel="nofollow">http://code.google.com/p/andro-views/</a></p>
<p>Still have issues ! This project is opensource under Apache licence. It is provided as it for free. If you fixed an issue, please send me your corrections.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Alioooop</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-394</link>
		<dc:creator>Alioooop</dc:creator>
		<pubDate>Fri, 03 Sep 2010 16:26:12 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-394</guid>
		<description>can you post your project? cant get it to work.... 
&lt;a href=&quot;#comment-390&quot; rel=&quot;nofollow&quot;&gt;@Eric Taix&lt;/a&gt;</description>
		<content:encoded><![CDATA[<p>can you post your project? cant get it to work&#8230;.<br />
<a href="#comment-390" rel="nofollow">@Eric Taix</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Android Shogun</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-392</link>
		<dc:creator>Android Shogun</dc:creator>
		<pubDate>Fri, 20 Aug 2010 22:56:05 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-392</guid>
		<description>glad it works for u ;)</description>
		<content:encoded><![CDATA[<p>glad it works for u <img src='http://www.codeshogun.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Android Shogun</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-391</link>
		<dc:creator>Android Shogun</dc:creator>
		<pubDate>Fri, 20 Aug 2010 22:55:42 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-391</guid>
		<description>Thanks for sharing :)</description>
		<content:encoded><![CDATA[<p>Thanks for sharing <img src='http://www.codeshogun.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Eric Taix</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-390</link>
		<dc:creator>Eric Taix</dc:creator>
		<pubDate>Fri, 20 Aug 2010 14:06:30 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-390</guid>
		<description>Here is another way to implement swipe actions (home screen like).
I started from the android sources of &quot;Workspace.java&quot;, removed unecessary lines of code, fixed issues, et voilà !

A sample video is available here: http://www.youtube.com/watch?v=w6yi6I6z1rc

Try and give me your feedback.
Enjoy !

==== WorkspaceTestActivity snippet ======

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    WorkspaceView work = new WorkspaceView(this, null);
    // Car il y a toujours un petit décalage du doigt même lors d&#039;un scrolling vertical
    work.setTouchSlop(32);
    // Chargement de l&#039;image d fond (peut être enlevée)
    Bitmap backGd = BitmapFactory.decodeResource(getResources(), R.drawable.background_black_1280x1024);
    work.loadWallpaper(backGd);
    
    ListView lv1 = (ListView) inflater.inflate(R.layout.list, null, false);
    lv1.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, lv_arr));
    ListView lv2 = (ListView) inflater.inflate(R.layout.list, null, false);
    lv2.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, lv_arr2));
    View v1= inflater.inflate(R.layout.relative_layout, null, false);



===== WorkspaceView.java =====

/**
 * Copyright 2010 Eric Taix (eric.taix@gmail.com) Licensed under the Apache License, Version 2.0 (the &quot;License&quot;); 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 &quot;AS IS&quot; 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 org.jared.commons.ui;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Scroller;

/**
 * The workspace is a wide area with a infinite number of screens. Each screen contains a view. A workspace is meant to
 * be used with a fixed width only.
 * 
 * This code has been done by using com.android.launcher.Workspace.java
 */
public class WorkspaceView extends ViewGroup {
  private static final int INVALID_SCREEN = -1;

  // The velocity at which a fling gesture will cause us to snap to the next screen
  private static final int SNAP_VELOCITY = 1000;

  // the default screen index
  private int defaultScreen;
  // The current screen index
  private int currentScreen;
  // The next screen index
  private int nextScreen = INVALID_SCREEN;
  // Wallpaper properties
  private Bitmap wallpaper;
  private Paint paint;
  private int wallpaperWidth;
  private int wallpaperHeight;
  private float wallpaperOffset;
  private boolean wallpaperLoaded;
  private boolean firstWallpaperLayout = true;

  // The scroller which scroll each view
  private Scroller scroller;
  // A tracker which to calculate the velocity of a mouvement
  private VelocityTracker mVelocityTracker;

  // Tha last known values of X and Y
  private float lastMotionX;
  private float lastMotionY;

  private final static int TOUCH_STATE_REST = 0;
  private final static int TOUCH_STATE_SCROLLING = 1;

  // The current touch state
  private int touchState = TOUCH_STATE_REST;
  // The minimal distance of a touch slop
  private int touchSlop;

  // An internal flag to reset long press when user is scrolling
  private boolean allowLongPress;
  // A flag to know if touch event have to be ignored. Used also in internal
  private boolean locked;

  /**
   * Used to inflate the Workspace from XML.
   * 
   * @param context The application&#039;s context.
   * @param attrs The attribtues set containing the Workspace&#039;s customization values.
   */
  public WorkspaceView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  /**
   * Used to inflate the Workspace from XML.
   * 
   * @param context The application&#039;s context.
   * @param attrs The attribtues set containing the Workspace&#039;s customization values.
   * @param defStyle Unused.
   */
  public WorkspaceView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    defaultScreen = 0;
    initWorkspace();
  }

  /**
   * Initializes various states for this workspace.
   */
  private void initWorkspace() {
    scroller = new Scroller(getContext());
    currentScreen = defaultScreen;

    paint = new Paint();
    paint.setDither(false);
    touchSlop = ViewConfiguration.getTouchSlop();
  }

  /**
   * Set a new distance that a touch can wander before we think the user is scrolling in pixels slop
   * 
   * @param touchSlopP
   */
  public void setTouchSlop(int touchSlopP) {
    touchSlop = touchSlopP;
  }

  /**
   * Set the background&#039;s wallpaper.
   */
  public void loadWallpaper(Bitmap bitmap) {
    wallpaper = bitmap;
    wallpaperLoaded = true;
    requestLayout();
    invalidate();
  }

  boolean isDefaultScreenShowing() {
    return currentScreen == defaultScreen;
  }

  /**
   * Returns the index of the currently displayed screen.
   * 
   * @return The index of the currently displayed screen.
   */
  int getCurrentScreen() {
    return currentScreen;
  }

  /**
   * Sets the current screen.
   * 
   * @param currentScreen
   */
  void setCurrentScreen(int currentScreen) {
    currentScreen = Math.max(0, Math.min(currentScreen, getChildCount()));
    scrollTo(currentScreen * getWidth(), 0);
    invalidate();
  }

  /**
   * Shows the default screen (defined by the firstScreen attribute in XML.)
   */
  void showDefaultScreen() {
    setCurrentScreen(defaultScreen);
  }

  /**
   * Registers the specified listener on each screen contained in this workspace.
   * 
   * @param l The listener used to respond to long clicks.
   */
  @Override
  public void setOnLongClickListener(OnLongClickListener l) {
    final int count = getChildCount();
    for (int i = 0; i &lt; count; i++) {
      getChildAt(i).setOnLongClickListener(l);
    }
  }

  @Override
  public void computeScroll() {
    if (scroller.computeScrollOffset()) {
      scrollTo(scroller.getCurrX(), scroller.getCurrY());
    }
    else if (nextScreen != INVALID_SCREEN) {
      currentScreen = nextScreen;
      nextScreen = INVALID_SCREEN;
    }
  }

  /**
   * ViewGroup.dispatchDraw() supports many features we don&#039;t need: clip to padding, layout animation, animation
   * listener, disappearing children, etc. The following implementation attempts to fast-track the drawing dispatch by
   * drawing only what we know needs to be drawn.
   */
  @Override
  protected void dispatchDraw(Canvas canvas) {
    // First draw the wallpaper if needed
    if (wallpaper != null) {
      float x = getScrollX() * wallpaperOffset;
      if (x + wallpaperWidth = 0 &amp;&amp; nextScreen &lt; getChildCount() &amp;&amp; Math.abs(currentScreen - nextScreen) == 1) {
        drawChild(canvas, getChildAt(currentScreen), drawingTime);
        drawChild(canvas, getChildAt(nextScreen), drawingTime);
      }
      else {
        // If we are scrolling, draw all of our children
        final int count = getChildCount();
        for (int i = 0; i &lt; count; i++) {
          drawChild(canvas, getChildAt(i), drawingTime);
        }
      }
    }
  }

  /**
   * Measure the workspace AND also children
   */
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    final int width = MeasureSpec.getSize(widthMeasureSpec);
    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    if (widthMode != MeasureSpec.EXACTLY) {
      throw new IllegalStateException(&quot;Workspace can only be used in EXACTLY mode.&quot;);
    }

    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    if (heightMode != MeasureSpec.EXACTLY) {
      throw new IllegalStateException(&quot;Workspace can only be used in EXACTLY mode.&quot;);
    }

    // The children are given the same width and height as the workspace
    final int count = getChildCount();
    for (int i = 0; i  width ? (count * width - wallpaperWidth) / ((count - 1) * (float) width) : 1.0f;
    if (firstWallpaperLayout) {
      scrollTo(currentScreen * width, 0);
      firstWallpaperLayout = false;
    }
  }

  /**
   * Overrided method to layout child
   */
  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    int childLeft = 0;
    final int count = getChildCount();
    for (int i = 0; i  0) {
        scrollToScreen(getCurrentScreen() - 1);
        return true;
      }
    }
    else if (direction == View.FOCUS_RIGHT) {
      if (getCurrentScreen()  touchSlop;
        boolean yMoved = yDiff &gt; touchSlop;

        if (xMoved &#124;&#124; yMoved) {

          if (xMoved &amp;&amp; !yMoved) {
            // Scroll if the user moved far enough along the X axis
            touchState = TOUCH_STATE_SCROLLING;
          }
          // Either way, cancel any pending longpress
          if (allowLongPress) {
            allowLongPress = false;
            // Try canceling the long press. It could also have been scheduled
            // by a distant descendant, so use the mAllowLongPress flag to block
            // everything
            final View currentView = getChildAt(currentScreen);
            currentView.cancelLongPress();
          }
        }
        break;

      case MotionEvent.ACTION_DOWN:
        // Remember location of down touch
        lastMotionX = x;
        lastMotionY = y;
        allowLongPress = true;

        /*
         * If being flinged and user touches the screen, initiate drag; otherwise don&#039;t. mScroller.isFinished should be
         * false when being flinged.
         */
        touchState = scroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
        break;

      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        touchState = TOUCH_STATE_REST;
        break;
    }

    /*
     * The only time we want to intercept motion events is if we are in the drag mode.
     */
    return touchState != TOUCH_STATE_REST;
  }

  /**
   * Track the touch event
   */
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (locked) {
      return true;
    }
    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(ev);

    final int action = ev.getAction();
    final float x = ev.getX();

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        /*
         * If being flinged and user touches, stop the fling. isFinished will be false if being flinged.
         */
        if (!scroller.isFinished()) {
          scroller.abortAnimation();
        }

        // Remember where the motion event started
        lastMotionX = x;
        break;
      case MotionEvent.ACTION_MOVE:
        if (touchState == TOUCH_STATE_SCROLLING) {
          // Scroll to follow the motion event
          final int deltaX = (int) (lastMotionX - x);
          lastMotionX = x;

          if (deltaX  0) {
              scrollBy(Math.max(-getScrollX(), deltaX), 0);
            }
          }
          else if (deltaX &gt; 0) {
            final int availableToScroll = getChildAt(getChildCount() - 1).getRight() - getScrollX() - getWidth();
            if (availableToScroll &gt; 0) {
              scrollBy(Math.min(availableToScroll, deltaX), 0);
            }
          }
        }
        break;
      case MotionEvent.ACTION_UP:
        if (touchState == TOUCH_STATE_SCROLLING) {
          final VelocityTracker velocityTracker = mVelocityTracker;
          velocityTracker.computeCurrentVelocity(1000);
          int velocityX = (int) velocityTracker.getXVelocity();

          if (velocityX &gt; SNAP_VELOCITY &amp;&amp; currentScreen &gt; 0) {
            // Fling hard enough to move left
            scrollToScreen(currentScreen - 1);
          }
          else if (velocityX &lt; -SNAP_VELOCITY &amp;&amp; currentScreen  0 &amp;&amp; scroller.isFinished()) {
      scrollToScreen(currentScreen - 1);
    }
  }

  /**
   * Scroll to the next right screen
   */
  public void scrollRight() {
    if (nextScreen == INVALID_SCREEN &amp;&amp; currentScreen &lt; getChildCount() - 1 &amp;&amp; scroller.isFinished()) {
      scrollToScreen(currentScreen + 1);
    }
  }

  /**
   * Return the screen&#039;s index where a view has been added to.
   * 
   * @param v
   * @return
   */
  public int getScreenForView(View v) {
    int result = -1;
    if (v != null) {
      ViewParent vp = v.getParent();
      int count = getChildCount();
      for (int i = 0; i &lt; count; i++) {
        if (vp == getChildAt(i)) {
          return i;
        }
      }
    }
    return result;
  }

  /**
   * Return a view instance according to the tag parameter or null if the view could not be found
   * 
   * @param tag
   * @return
   */
  public View getViewForTag(Object tag) {
    int screenCount = getChildCount();
    for (int screen = 0; screen &lt; screenCount; screen++) {
      View child = getChildAt(screen);
      if (child.getTag() == tag) {
        return child;
      }
    }
    return null;
  }

  /**
   * Unlocks the SlidingDrawer so that touch events are processed.
   * 
   * @see #lock()
   */
  public void unlock() {
    locked = false;
  }

  /**
   * Locks the SlidingDrawer so that touch events are ignores.
   * 
   * @see #unlock()
   */
  public void lock() {
    locked = true;
  }

  /**
   * @return True is long presses are still allowed for the current touch
   */
  public boolean allowLongPress() {
    return allowLongPress;
  }

  /**
   * Move to the default screen
   */
  public void moveToDefaultScreen() {
    scrollToScreen(defaultScreen);
    getChildAt(defaultScreen).requestFocus();
  }

  // ========================= INNER CLASSES ==============================

  /**
   * A SavedState which save and load the current screen
   */
  public static class SavedState extends BaseSavedState {
    int currentScreen = -1;

    /**
     * Internal constructor
     * 
     * @param superState
     */
    SavedState(Parcelable superState) {
      super(superState);
    }

    /**
     * Private constructor
     * 
     * @param in
     */
    private SavedState(Parcel in) {
      super(in);
      currentScreen = in.readInt();
    }

    /**
     * Save the current screen
     */
    @Override
    public void writeToParcel(Parcel out, int flags) {
      super.writeToParcel(out, flags);
      out.writeInt(currentScreen);
    }

    /**
     * Return a Parcelable creator
     */
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
      public SavedState createFromParcel(Parcel in) {
        return new SavedState(in);
      }

      public SavedState[] newArray(int size) {
        return new SavedState[size];
      }
    };
  }

  // ======================== UTILITIES METHODS ==========================

  /**
   * Return a centered Bitmap
   * 
   * @param bitmap
   * @param width
   * @param height
   * @param context
   * @return
   */
  static Bitmap centerToFit(Bitmap bitmap, int width, int height, Context context) {
    final int bitmapWidth = bitmap.getWidth();
    final int bitmapHeight = bitmap.getHeight();

    if (bitmapWidth &lt; width &#124;&#124; bitmapHeight &lt; height) {
      // Normally should get the window_background color of the context
      int color = Integer.valueOf(&quot;FF191919&quot;, 16);
      Bitmap centered = Bitmap.createBitmap(bitmapWidth &lt; width ? width : bitmapWidth, bitmapHeight &lt; height ? height
              : bitmapHeight, Bitmap.Config.RGB_565);
      Canvas canvas = new Canvas(centered);
      canvas.drawColor(color);
      canvas.drawBitmap(bitmap, (width - bitmapWidth) / 2.0f, (height - bitmapHeight) / 2.0f, null);
      bitmap = centered;
    }
    return bitmap;
  }

}</description>
		<content:encoded><![CDATA[<p>Here is another way to implement swipe actions (home screen like).<br />
I started from the android sources of &#8220;Workspace.java&#8221;, removed unecessary lines of code, fixed issues, et voilà !</p>
<p>A sample video is available here: <a href="http://www.youtube.com/watch?v=w6yi6I6z1rc" rel="nofollow">http://www.youtube.com/watch?v=w6yi6I6z1rc</a></p>
<p>Try and give me your feedback.<br />
Enjoy !</p>
<p>==== WorkspaceTestActivity snippet ======</p>
<p>  public void onCreate(Bundle savedInstanceState) {<br />
    super.onCreate(savedInstanceState);<br />
    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);</p>
<p>    WorkspaceView work = new WorkspaceView(this, null);<br />
    // Car il y a toujours un petit décalage du doigt même lors d&#8217;un scrolling vertical<br />
    work.setTouchSlop(32);<br />
    // Chargement de l&#8217;image d fond (peut être enlevée)<br />
    Bitmap backGd = BitmapFactory.decodeResource(getResources(), R.drawable.background_black_1280x1024);<br />
    work.loadWallpaper(backGd);</p>
<p>    ListView lv1 = (ListView) inflater.inflate(R.layout.list, null, false);<br />
    lv1.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, lv_arr));<br />
    ListView lv2 = (ListView) inflater.inflate(R.layout.list, null, false);<br />
    lv2.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, lv_arr2));<br />
    View v1= inflater.inflate(R.layout.relative_layout, null, false);</p>
<p>===== WorkspaceView.java =====</p>
<p>/**<br />
 * Copyright 2010 Eric Taix (eric.taix@gmail.com) Licensed under the Apache License, Version 2.0 (the &#8220;License&#8221;); you<br />
 * may not use this file except in compliance with the License. You may obtain a copy of the License at<br />
 * <a href="http://www.apache.org/licenses/LICENSE-2.0" rel="nofollow">http://www.apache.org/licenses/LICENSE-2.0</a> Unless required by applicable law or agreed to in writing, software<br />
 * distributed under the License is distributed on an &#8220;AS IS&#8221; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,<br />
 * either express or implied. See the License for the specific language governing permissions and limitations under the<br />
 * License.<br />
 */<br />
package org.jared.commons.ui;</p>
<p>import android.content.Context;<br />
import android.graphics.Bitmap;<br />
import android.graphics.Canvas;<br />
import android.graphics.Paint;<br />
import android.os.Parcel;<br />
import android.os.Parcelable;<br />
import android.util.AttributeSet;<br />
import android.util.Log;<br />
import android.view.MotionEvent;<br />
import android.view.VelocityTracker;<br />
import android.view.View;<br />
import android.view.ViewConfiguration;<br />
import android.view.ViewGroup;<br />
import android.view.ViewParent;<br />
import android.widget.Scroller;</p>
<p>/**<br />
 * The workspace is a wide area with a infinite number of screens. Each screen contains a view. A workspace is meant to<br />
 * be used with a fixed width only.<br />
 *<br />
 * This code has been done by using com.android.launcher.Workspace.java<br />
 */<br />
public class WorkspaceView extends ViewGroup {<br />
  private static final int INVALID_SCREEN = -1;</p>
<p>  // The velocity at which a fling gesture will cause us to snap to the next screen<br />
  private static final int SNAP_VELOCITY = 1000;</p>
<p>  // the default screen index<br />
  private int defaultScreen;<br />
  // The current screen index<br />
  private int currentScreen;<br />
  // The next screen index<br />
  private int nextScreen = INVALID_SCREEN;<br />
  // Wallpaper properties<br />
  private Bitmap wallpaper;<br />
  private Paint paint;<br />
  private int wallpaperWidth;<br />
  private int wallpaperHeight;<br />
  private float wallpaperOffset;<br />
  private boolean wallpaperLoaded;<br />
  private boolean firstWallpaperLayout = true;</p>
<p>  // The scroller which scroll each view<br />
  private Scroller scroller;<br />
  // A tracker which to calculate the velocity of a mouvement<br />
  private VelocityTracker mVelocityTracker;</p>
<p>  // Tha last known values of X and Y<br />
  private float lastMotionX;<br />
  private float lastMotionY;</p>
<p>  private final static int TOUCH_STATE_REST = 0;<br />
  private final static int TOUCH_STATE_SCROLLING = 1;</p>
<p>  // The current touch state<br />
  private int touchState = TOUCH_STATE_REST;<br />
  // The minimal distance of a touch slop<br />
  private int touchSlop;</p>
<p>  // An internal flag to reset long press when user is scrolling<br />
  private boolean allowLongPress;<br />
  // A flag to know if touch event have to be ignored. Used also in internal<br />
  private boolean locked;</p>
<p>  /**<br />
   * Used to inflate the Workspace from XML.<br />
   *<br />
   * @param context The application&#8217;s context.<br />
   * @param attrs The attribtues set containing the Workspace&#8217;s customization values.<br />
   */<br />
  public WorkspaceView(Context context, AttributeSet attrs) {<br />
    this(context, attrs, 0);<br />
  }</p>
<p>  /**<br />
   * Used to inflate the Workspace from XML.<br />
   *<br />
   * @param context The application&#8217;s context.<br />
   * @param attrs The attribtues set containing the Workspace&#8217;s customization values.<br />
   * @param defStyle Unused.<br />
   */<br />
  public WorkspaceView(Context context, AttributeSet attrs, int defStyle) {<br />
    super(context, attrs, defStyle);<br />
    defaultScreen = 0;<br />
    initWorkspace();<br />
  }</p>
<p>  /**<br />
   * Initializes various states for this workspace.<br />
   */<br />
  private void initWorkspace() {<br />
    scroller = new Scroller(getContext());<br />
    currentScreen = defaultScreen;</p>
<p>    paint = new Paint();<br />
    paint.setDither(false);<br />
    touchSlop = ViewConfiguration.getTouchSlop();<br />
  }</p>
<p>  /**<br />
   * Set a new distance that a touch can wander before we think the user is scrolling in pixels slop<br />
   *<br />
   * @param touchSlopP<br />
   */<br />
  public void setTouchSlop(int touchSlopP) {<br />
    touchSlop = touchSlopP;<br />
  }</p>
<p>  /**<br />
   * Set the background&#8217;s wallpaper.<br />
   */<br />
  public void loadWallpaper(Bitmap bitmap) {<br />
    wallpaper = bitmap;<br />
    wallpaperLoaded = true;<br />
    requestLayout();<br />
    invalidate();<br />
  }</p>
<p>  boolean isDefaultScreenShowing() {<br />
    return currentScreen == defaultScreen;<br />
  }</p>
<p>  /**<br />
   * Returns the index of the currently displayed screen.<br />
   *<br />
   * @return The index of the currently displayed screen.<br />
   */<br />
  int getCurrentScreen() {<br />
    return currentScreen;<br />
  }</p>
<p>  /**<br />
   * Sets the current screen.<br />
   *<br />
   * @param currentScreen<br />
   */<br />
  void setCurrentScreen(int currentScreen) {<br />
    currentScreen = Math.max(0, Math.min(currentScreen, getChildCount()));<br />
    scrollTo(currentScreen * getWidth(), 0);<br />
    invalidate();<br />
  }</p>
<p>  /**<br />
   * Shows the default screen (defined by the firstScreen attribute in XML.)<br />
   */<br />
  void showDefaultScreen() {<br />
    setCurrentScreen(defaultScreen);<br />
  }</p>
<p>  /**<br />
   * Registers the specified listener on each screen contained in this workspace.<br />
   *<br />
   * @param l The listener used to respond to long clicks.<br />
   */<br />
  @Override<br />
  public void setOnLongClickListener(OnLongClickListener l) {<br />
    final int count = getChildCount();<br />
    for (int i = 0; i &lt; count; i++) {<br />
      getChildAt(i).setOnLongClickListener(l);<br />
    }<br />
  }</p>
<p>  @Override<br />
  public void computeScroll() {<br />
    if (scroller.computeScrollOffset()) {<br />
      scrollTo(scroller.getCurrX(), scroller.getCurrY());<br />
    }<br />
    else if (nextScreen != INVALID_SCREEN) {<br />
      currentScreen = nextScreen;<br />
      nextScreen = INVALID_SCREEN;<br />
    }<br />
  }</p>
<p>  /**<br />
   * ViewGroup.dispatchDraw() supports many features we don&#039;t need: clip to padding, layout animation, animation<br />
   * listener, disappearing children, etc. The following implementation attempts to fast-track the drawing dispatch by<br />
   * drawing only what we know needs to be drawn.<br />
   */<br />
  @Override<br />
  protected void dispatchDraw(Canvas canvas) {<br />
    // First draw the wallpaper if needed<br />
    if (wallpaper != null) {<br />
      float x = getScrollX() * wallpaperOffset;<br />
      if (x + wallpaperWidth = 0 &amp;&amp; nextScreen &lt; getChildCount() &amp;&amp; Math.abs(currentScreen &#8211; nextScreen) == 1) {<br />
        drawChild(canvas, getChildAt(currentScreen), drawingTime);<br />
        drawChild(canvas, getChildAt(nextScreen), drawingTime);<br />
      }<br />
      else {<br />
        // If we are scrolling, draw all of our children<br />
        final int count = getChildCount();<br />
        for (int i = 0; i &lt; count; i++) {<br />
          drawChild(canvas, getChildAt(i), drawingTime);<br />
        }<br />
      }<br />
    }<br />
  }</p>
<p>  /**<br />
   * Measure the workspace AND also children<br />
   */<br />
  @Override<br />
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {<br />
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);</p>
<p>    final int width = MeasureSpec.getSize(widthMeasureSpec);<br />
    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);<br />
    if (widthMode != MeasureSpec.EXACTLY) {<br />
      throw new IllegalStateException(&quot;Workspace can only be used in EXACTLY mode.&quot;);<br />
    }</p>
<p>    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);<br />
    if (heightMode != MeasureSpec.EXACTLY) {<br />
      throw new IllegalStateException(&quot;Workspace can only be used in EXACTLY mode.&quot;);<br />
    }</p>
<p>    // The children are given the same width and height as the workspace<br />
    final int count = getChildCount();<br />
    for (int i = 0; i  width ? (count * width &#8211; wallpaperWidth) / ((count &#8211; 1) * (float) width) : 1.0f;<br />
    if (firstWallpaperLayout) {<br />
      scrollTo(currentScreen * width, 0);<br />
      firstWallpaperLayout = false;<br />
    }<br />
  }</p>
<p>  /**<br />
   * Overrided method to layout child<br />
   */<br />
  @Override<br />
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {<br />
    int childLeft = 0;<br />
    final int count = getChildCount();<br />
    for (int i = 0; i  0) {<br />
        scrollToScreen(getCurrentScreen() &#8211; 1);<br />
        return true;<br />
      }<br />
    }<br />
    else if (direction == View.FOCUS_RIGHT) {<br />
      if (getCurrentScreen()  touchSlop;<br />
        boolean yMoved = yDiff &gt; touchSlop;</p>
<p>        if (xMoved || yMoved) {</p>
<p>          if (xMoved &amp;&amp; !yMoved) {<br />
            // Scroll if the user moved far enough along the X axis<br />
            touchState = TOUCH_STATE_SCROLLING;<br />
          }<br />
          // Either way, cancel any pending longpress<br />
          if (allowLongPress) {<br />
            allowLongPress = false;<br />
            // Try canceling the long press. It could also have been scheduled<br />
            // by a distant descendant, so use the mAllowLongPress flag to block<br />
            // everything<br />
            final View currentView = getChildAt(currentScreen);<br />
            currentView.cancelLongPress();<br />
          }<br />
        }<br />
        break;</p>
<p>      case MotionEvent.ACTION_DOWN:<br />
        // Remember location of down touch<br />
        lastMotionX = x;<br />
        lastMotionY = y;<br />
        allowLongPress = true;</p>
<p>        /*<br />
         * If being flinged and user touches the screen, initiate drag; otherwise don&#8217;t. mScroller.isFinished should be<br />
         * false when being flinged.<br />
         */<br />
        touchState = scroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;<br />
        break;</p>
<p>      case MotionEvent.ACTION_CANCEL:<br />
      case MotionEvent.ACTION_UP:<br />
        touchState = TOUCH_STATE_REST;<br />
        break;<br />
    }</p>
<p>    /*<br />
     * The only time we want to intercept motion events is if we are in the drag mode.<br />
     */<br />
    return touchState != TOUCH_STATE_REST;<br />
  }</p>
<p>  /**<br />
   * Track the touch event<br />
   */<br />
  @Override<br />
  public boolean onTouchEvent(MotionEvent ev) {<br />
    if (locked) {<br />
      return true;<br />
    }<br />
    if (mVelocityTracker == null) {<br />
      mVelocityTracker = VelocityTracker.obtain();<br />
    }<br />
    mVelocityTracker.addMovement(ev);</p>
<p>    final int action = ev.getAction();<br />
    final float x = ev.getX();</p>
<p>    switch (action) {<br />
      case MotionEvent.ACTION_DOWN:<br />
        /*<br />
         * If being flinged and user touches, stop the fling. isFinished will be false if being flinged.<br />
         */<br />
        if (!scroller.isFinished()) {<br />
          scroller.abortAnimation();<br />
        }</p>
<p>        // Remember where the motion event started<br />
        lastMotionX = x;<br />
        break;<br />
      case MotionEvent.ACTION_MOVE:<br />
        if (touchState == TOUCH_STATE_SCROLLING) {<br />
          // Scroll to follow the motion event<br />
          final int deltaX = (int) (lastMotionX &#8211; x);<br />
          lastMotionX = x;</p>
<p>          if (deltaX  0) {<br />
              scrollBy(Math.max(-getScrollX(), deltaX), 0);<br />
            }<br />
          }<br />
          else if (deltaX &gt; 0) {<br />
            final int availableToScroll = getChildAt(getChildCount() &#8211; 1).getRight() &#8211; getScrollX() &#8211; getWidth();<br />
            if (availableToScroll &gt; 0) {<br />
              scrollBy(Math.min(availableToScroll, deltaX), 0);<br />
            }<br />
          }<br />
        }<br />
        break;<br />
      case MotionEvent.ACTION_UP:<br />
        if (touchState == TOUCH_STATE_SCROLLING) {<br />
          final VelocityTracker velocityTracker = mVelocityTracker;<br />
          velocityTracker.computeCurrentVelocity(1000);<br />
          int velocityX = (int) velocityTracker.getXVelocity();</p>
<p>          if (velocityX &gt; SNAP_VELOCITY &amp;&amp; currentScreen &gt; 0) {<br />
            // Fling hard enough to move left<br />
            scrollToScreen(currentScreen &#8211; 1);<br />
          }<br />
          else if (velocityX &lt; -SNAP_VELOCITY &amp;&amp; currentScreen  0 &amp;&amp; scroller.isFinished()) {<br />
      scrollToScreen(currentScreen &#8211; 1);<br />
    }<br />
  }</p>
<p>  /**<br />
   * Scroll to the next right screen<br />
   */<br />
  public void scrollRight() {<br />
    if (nextScreen == INVALID_SCREEN &amp;&amp; currentScreen &lt; getChildCount() &#8211; 1 &amp;&amp; scroller.isFinished()) {<br />
      scrollToScreen(currentScreen + 1);<br />
    }<br />
  }</p>
<p>  /**<br />
   * Return the screen&#039;s index where a view has been added to.<br />
   *<br />
   * @param v<br />
   * @return<br />
   */<br />
  public int getScreenForView(View v) {<br />
    int result = -1;<br />
    if (v != null) {<br />
      ViewParent vp = v.getParent();<br />
      int count = getChildCount();<br />
      for (int i = 0; i &lt; count; i++) {<br />
        if (vp == getChildAt(i)) {<br />
          return i;<br />
        }<br />
      }<br />
    }<br />
    return result;<br />
  }</p>
<p>  /**<br />
   * Return a view instance according to the tag parameter or null if the view could not be found<br />
   *<br />
   * @param tag<br />
   * @return<br />
   */<br />
  public View getViewForTag(Object tag) {<br />
    int screenCount = getChildCount();<br />
    for (int screen = 0; screen &lt; screenCount; screen++) {<br />
      View child = getChildAt(screen);<br />
      if (child.getTag() == tag) {<br />
        return child;<br />
      }<br />
    }<br />
    return null;<br />
  }</p>
<p>  /**<br />
   * Unlocks the SlidingDrawer so that touch events are processed.<br />
   *<br />
   * @see #lock()<br />
   */<br />
  public void unlock() {<br />
    locked = false;<br />
  }</p>
<p>  /**<br />
   * Locks the SlidingDrawer so that touch events are ignores.<br />
   *<br />
   * @see #unlock()<br />
   */<br />
  public void lock() {<br />
    locked = true;<br />
  }</p>
<p>  /**<br />
   * @return True is long presses are still allowed for the current touch<br />
   */<br />
  public boolean allowLongPress() {<br />
    return allowLongPress;<br />
  }</p>
<p>  /**<br />
   * Move to the default screen<br />
   */<br />
  public void moveToDefaultScreen() {<br />
    scrollToScreen(defaultScreen);<br />
    getChildAt(defaultScreen).requestFocus();<br />
  }</p>
<p>  // ========================= INNER CLASSES ==============================</p>
<p>  /**<br />
   * A SavedState which save and load the current screen<br />
   */<br />
  public static class SavedState extends BaseSavedState {<br />
    int currentScreen = -1;</p>
<p>    /**<br />
     * Internal constructor<br />
     *<br />
     * @param superState<br />
     */<br />
    SavedState(Parcelable superState) {<br />
      super(superState);<br />
    }</p>
<p>    /**<br />
     * Private constructor<br />
     *<br />
     * @param in<br />
     */<br />
    private SavedState(Parcel in) {<br />
      super(in);<br />
      currentScreen = in.readInt();<br />
    }</p>
<p>    /**<br />
     * Save the current screen<br />
     */<br />
    @Override<br />
    public void writeToParcel(Parcel out, int flags) {<br />
      super.writeToParcel(out, flags);<br />
      out.writeInt(currentScreen);<br />
    }</p>
<p>    /**<br />
     * Return a Parcelable creator<br />
     */<br />
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {<br />
      public SavedState createFromParcel(Parcel in) {<br />
        return new SavedState(in);<br />
      }</p>
<p>      public SavedState[] newArray(int size) {<br />
        return new SavedState[size];<br />
      }<br />
    };<br />
  }</p>
<p>  // ======================== UTILITIES METHODS ==========================</p>
<p>  /**<br />
   * Return a centered Bitmap<br />
   *<br />
   * @param bitmap<br />
   * @param width<br />
   * @param height<br />
   * @param context<br />
   * @return<br />
   */<br />
  static Bitmap centerToFit(Bitmap bitmap, int width, int height, Context context) {<br />
    final int bitmapWidth = bitmap.getWidth();<br />
    final int bitmapHeight = bitmap.getHeight();</p>
<p>    if (bitmapWidth &lt; width || bitmapHeight &lt; height) {<br />
      // Normally should get the window_background color of the context<br />
      int color = Integer.valueOf(&quot;FF191919&quot;, 16);<br />
      Bitmap centered = Bitmap.createBitmap(bitmapWidth &lt; width ? width : bitmapWidth, bitmapHeight &lt; height ? height<br />
              : bitmapHeight, Bitmap.Config.RGB_565);<br />
      Canvas canvas = new Canvas(centered);<br />
      canvas.drawColor(color);<br />
      canvas.drawBitmap(bitmap, (width &#8211; bitmapWidth) / 2.0f, (height &#8211; bitmapHeight) / 2.0f, null);<br />
      bitmap = centered;<br />
    }<br />
    return bitmap;<br />
  }</p>
<p>}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: ArtWork</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-389</link>
		<dc:creator>ArtWork</dc:creator>
		<pubDate>Thu, 12 Aug 2010 07:39:46 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-389</guid>
		<description>here is a working solution that behaves like a homescreen, the source is attached at the end of the artikel</description>
		<content:encoded><![CDATA[<p>here is a working solution that behaves like a homescreen, the source is attached at the end of the artikel</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Lora</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-386</link>
		<dc:creator>Lora</dc:creator>
		<pubDate>Wed, 28 Jul 2010 10:44:34 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-386</guid>
		<description>@Eric

Great tip! It works graciously! Thanks a lot man!
Have a nice day!</description>
		<content:encoded><![CDATA[<p>@Eric</p>
<p>Great tip! It works graciously! Thanks a lot man!<br />
Have a nice day!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Lora</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-385</link>
		<dc:creator>Lora</dc:creator>
		<pubDate>Wed, 28 Jul 2010 09:22:28 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-385</guid>
		<description>Great tutorial!

I&#039;m doing this with webView (EbookReader). Hopefully it will work granted that webView is way too special for ViewFlipper.

Keep up the good work guys. God bless!</description>
		<content:encoded><![CDATA[<p>Great tutorial!</p>
<p>I&#8217;m doing this with webView (EbookReader). Hopefully it will work granted that webView is way too special for ViewFlipper.</p>
<p>Keep up the good work guys. God bless!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: P</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-375</link>
		<dc:creator>P</dc:creator>
		<pubDate>Fri, 25 Jun 2010 21:40:50 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-375</guid>
		<description>&lt;a href=&quot;#comment-374&quot; rel=&quot;nofollow&quot;&gt;@P&lt;/a&gt; 
o0ooo gestureDetector is of the type GestureDetector. Not MyGestureDetector. My bad :-)</description>
		<content:encoded><![CDATA[<p><a href="#comment-374" rel="nofollow">@P</a><br />
o0ooo gestureDetector is of the type GestureDetector. Not MyGestureDetector. My bad <img src='http://www.codeshogun.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: P</title>
		<link>http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/comment-page-1/#comment-374</link>
		<dc:creator>P</dc:creator>
		<pubDate>Fri, 25 Jun 2010 21:33:20 +0000</pubDate>
		<guid isPermaLink="false">http://www.codeshogun.com/blog/?p=97#comment-374</guid>
		<description>I&#039;m sorry am I missing something here..

when I try and do the lines

@Override
	public boolean onTouch(View v, MotionEvent event) {
		if (gestureDetector.onTouchEvent(event))
			return true;
			else
			return false;
	}

I get &#039;The method onTouchEvent(MotionEvent) is undefined for the type GestureDetector&#039; as a compile error?</description>
		<content:encoded><![CDATA[<p>I&#8217;m sorry am I missing something here..</p>
<p>when I try and do the lines</p>
<p>@Override<br />
	public boolean onTouch(View v, MotionEvent event) {<br />
		if (gestureDetector.onTouchEvent(event))<br />
			return true;<br />
			else<br />
			return false;<br />
	}</p>
<p>I get &#8216;The method onTouchEvent(MotionEvent) is undefined for the type GestureDetector&#8217; as a compile error?</p>
]]></content:encoded>
	</item>
</channel>
</rss>

