This looks really useful, I'm going to have a play with it, many
thanks for sharing.

Are you able to edit it so that it works with older android versions?
I haven't come across the LayoutParams.MATCH_PARENT before.

On Jun 14, 1:32 pm, droidful <austral...@gmail.com> wrote:
> package com.droidful.flinggallery;
>
> import android.content.Context;
> import android.util.Log;
> import android.view.GestureDetector;
> import android.view.KeyEvent;
> import android.view.MotionEvent;
> import android.view.View;
> import android.view.animation.Animation;
> import android.view.animation.AnimationUtils;
> import android.view.animation.Interpolator;
> import android.view.animation.Transformation;
> import android.widget.Adapter;
> import android.widget.FrameLayout;
> import android.widget.LinearLayout;
>
> public class FlingGallery extends FrameLayout
> {
>         // Constants
>
>         private final int swipe_min_distance = 120;
>     private final int swipe_max_off_path = 250;
>     private final int swipe_threshold_veloicty = 400;
>
>     // Properties
>
>         private int mViewPaddingWidth = 0;
>     private int mAnimationDuration = 200;
>     private float mSnapBorderRatio = 0.4f;
>     private boolean mIsGalleryCircular = true;
>
>     // Members
>
>     private int mGalleryWidth = 0;
>     private boolean mIsTouched = false;
>     private boolean mIsDragging = false;
>     private float mCurrentOffset = 0.0f;
>     private long mScrollTimestamp = 0;
>     private int mFlingDirection = 0;
>     private int mCurrentPosition = 0;
>     private int mCurrentViewNumber = 0;
>
>     private Context mContext;
>     private Adapter mAdapter;
>     private FlingGalleryView[] mViews;
>     private FlingGalleryAnimation mAnimation;
>     private GestureDetector mGestureDetector;
>     private Interpolator mDecelerateInterpolater;
>
>     public FlingGallery(Context context)
>         {
>                 super(context);
>
>                 mContext = context;
>                 mAdapter = null;
>
>         mViews = new FlingGalleryView[3];
>         mViews[0] = new FlingGalleryView(0, this);
>         mViews[1] = new FlingGalleryView(1, this);
>         mViews[2] = new FlingGalleryView(2, this);
>
>                 mAnimation = new FlingGalleryAnimation();
>                 mGestureDetector = new GestureDetector(new 
> FlingGestureDetector());
>                 mDecelerateInterpolater = 
> AnimationUtils.loadInterpolator(mContext,
> android.R.anim.decelerate_interpolator);
>             AnimationUtils.loadInterpolator(mContext,
> android.R.anim.linear_interpolator);
>         }
>
>         public void setPaddingWidth(int viewPaddingWidth)
>         {
>                 mViewPaddingWidth = viewPaddingWidth;
>         }
>
>         public void setAnimationDuration(int animationDuration)
>         {
>                 mAnimationDuration = animationDuration;
>         }
>
>         public void setSnapBorderRatio(float snapBorderRatio)
>         {
>                 mSnapBorderRatio = snapBorderRatio;
>         }
>
>         public void setIsGalleryCircular(boolean isGalleryCircular)
>         {
>                 if (mIsGalleryCircular != isGalleryCircular)
>                 {
>                         mIsGalleryCircular = isGalleryCircular;
>
>                         if (mCurrentPosition == getFirstPosition())
>                         {
>                                 // We need to reload the view immediately to 
> the left to change it
> to circular view or blank
>
> mViews[getPrevViewNumber(mCurrentViewNumber)].recycleView(getPrevPosition(mCurrentPosition));
>                         }
>
>                         if (mCurrentPosition == getLastPosition())
>                         {
>                                 // We need to reload the view immediately to 
> the right to change
> it to circular view or blank
>
> mViews[getNextViewNumber(mCurrentViewNumber)].recycleView(getNextPosition(mCurrentPosition));
>                         }
>                 }
>         }
>
>         public int getGalleryCount()
>         {
>                 return (mAdapter == null) ? 0 : mAdapter.getCount();
>         }
>
>         public int getFirstPosition()
>         {
>                 return 0;
>         }
>
>         public int getLastPosition()
>         {
>                 return (getGalleryCount() == 0) ? 0 : getGalleryCount() - 1;
>         }
>
>         private int getPrevPosition(int relativePosition)
>         {
>                 int prevPosition = relativePosition - 1;
>
>                 if (prevPosition < getFirstPosition())
>                 {
>                         prevPosition = getFirstPosition() - 1;
>
>                         if (mIsGalleryCircular == true)
>                         {
>                                 prevPosition = getLastPosition();
>                         }
>                 }
>
>                 return prevPosition;
>         }
>
>         private int getNextPosition(int relativePosition)
>         {
>                 int nextPosition = relativePosition + 1;
>
>                 if (nextPosition > getLastPosition())
>                 {
>                         nextPosition = getLastPosition() + 1;
>
>                         if (mIsGalleryCircular == true)
>                         {
>                                 nextPosition = getFirstPosition();
>                         }
>                 }
>
>                 return nextPosition;
>         }
>
>         private int getPrevViewNumber(int relativeViewNumber)
>         {
>                 return (relativeViewNumber == 0) ? 2 : relativeViewNumber - 1;
>         }
>
>         private int getNextViewNumber(int relativeViewNumber)
>         {
>                 return (relativeViewNumber == 2) ? 0 : relativeViewNumber + 1;
>         }
>
>         @Override
>         protected void onLayout(boolean changed, int left, int top, int
> right, int bottom)
>         {
>                 super.onLayout(changed, left, top, right, bottom);
>
>                 // Calculate our view width
>                 mGalleryWidth = right - left;
>
>                 if (changed == true)
>                 {
>                 // Position views at correct starting offsets
>                 mViews[0].setOffset(0, 0, mCurrentViewNumber);
>                 mViews[1].setOffset(0, 0, mCurrentViewNumber);
>                 mViews[2].setOffset(0, 0, mCurrentViewNumber);
>             }
>         }
>
>         public void setAdapter(Adapter adapter)
>     {
>         mAdapter = adapter;
>         mCurrentPosition = 0;
>         mCurrentViewNumber = 0;
>
>         // Load the initial views from adapter
>         mViews[0].recycleView(mCurrentPosition);
>         mViews[1].recycleView(getNextPosition(mCurrentPosition));
>         mViews[2].recycleView(getPrevPosition(mCurrentPosition));
>
>         // Position views at correct starting offsets
>         mViews[0].setOffset(0, 0, mCurrentViewNumber);
>         mViews[1].setOffset(0, 0, mCurrentViewNumber);
>         mViews[2].setOffset(0, 0, mCurrentViewNumber);
>     }
>
>         private int getViewOffset(int viewNumber, int relativeViewNumber)
>         {
>                 // Determine width including configured padding width
>                 int offsetWidth = mGalleryWidth + mViewPaddingWidth;
>
>                 // Position the previous view one measured width to left
>                 if (viewNumber == getPrevViewNumber(relativeViewNumber))
>                 {
>                         return offsetWidth;
>                 }
>
>                 // Position the next view one measured width to the right
>                 if (viewNumber == getNextViewNumber(relativeViewNumber))
>                 {
>                         return offsetWidth * -1;
>                 }
>
>                 return 0;
>         }
>
>         void movePrevious()
>         {
>                 // Slide to previous view
>                 mFlingDirection = 1;
>                 processGesture();
>         }
>
>         void moveNext()
>         {
>                 // Slide to next view
>                 mFlingDirection = -1;
>                 processGesture();
>         }
>
>         �...@override
>          public boolean onKeyDown(int keyCode, KeyEvent event)
>          {
>             switch (keyCode)
>             {
>             case KeyEvent.KEYCODE_DPAD_LEFT:
>                 movePrevious();
>                 return true;
>
>             case KeyEvent.KEYCODE_DPAD_RIGHT:
>                 moveNext();
>                 return true;
>
>             case KeyEvent.KEYCODE_DPAD_CENTER:
>             case KeyEvent.KEYCODE_ENTER:
>             }
>
>             return super.onKeyDown(keyCode, event);
>         }
>
>         public boolean onGalleryTouchEvent(MotionEvent event)
>         {
>                 boolean consumed = mGestureDetector.onTouchEvent(event);
>
>                 if (event.getAction() == MotionEvent.ACTION_UP)
>                 {
>                         if (mIsTouched || mIsDragging)
>                         {
>                                 processScrollSnap();
>                                 processGesture();
>                         }
>                 }
>
>         return consumed;
>     }
>
>         void processGesture()
>         {
>                 int newViewNumber = mCurrentViewNumber;
>                 int reloadViewNumber = 0;
>                 int reloadPosition = 0;
>
>                 mIsTouched = false;
>                 mIsDragging = false;
>
>                 if (mFlingDirection > 0)
>                 {
>                         if (mCurrentPosition > getFirstPosition() || 
> mIsGalleryCircular ==
> true)
>                         {
>                                 // Determine previous view and outgoing view 
> to recycle
>                                 newViewNumber = 
> getPrevViewNumber(mCurrentViewNumber);
>                                 mCurrentPosition = 
> getPrevPosition(mCurrentPosition);
>                                 reloadViewNumber = 
> getNextViewNumber(mCurrentViewNumber);
>                                 reloadPosition = 
> getPrevPosition(mCurrentPosition);
>                         }
>                 }
>
>                 if (mFlingDirection < 0)
>                 {
>                         if (mCurrentPosition < getLastPosition() || 
> mIsGalleryCircular ==
> true)
>                         {
>                                 // Determine the next view and outgoing view 
> to recycle
>                                 newViewNumber = 
> getNextViewNumber(mCurrentViewNumber);
>                                 mCurrentPosition = 
> getNextPosition(mCurrentPosition);
>                                 reloadViewNumber = 
> getPrevViewNumber(mCurrentViewNumber);
>                                 reloadPosition = 
> getNextPosition(mCurrentPosition);
>                         }
>                 }
>
>                 if (newViewNumber != mCurrentViewNumber)
>                 {
>                         mCurrentViewNumber = newViewNumber;
>
>                         // Reload outgoing view from adapter in new position
>                         mViews[reloadViewNumber].recycleView(reloadPosition);
>                 }
>
>                 // Ensure input focus on the current view
>                 mViews[mCurrentViewNumber].requestFocus();
>
>                 // Run the slide animations for view transitions
>                 mAnimation.prepareAnimation(mCurrentViewNumber);
>                 this.startAnimation(mAnimation);
>
>                 // Reset fling state
>                 mFlingDirection = 0;
>         }
>
>         void processScrollSnap()
>         {
>                 // Snap to next view if scrolled passed snap position
>                 float rollEdgeWidth = mGalleryWidth * mSnapBorderRatio;
>                 int rollOffset = mGalleryWidth - (int) rollEdgeWidth;
>                 int currentOffset = 
> mViews[mCurrentViewNumber].getCurrentOffset();
>
>                 if (currentOffset <= rollOffset * -1)
>                 {
>                         // Snap to previous view
>                         mFlingDirection = 1;
>                 }
>
>                 if (currentOffset >= rollOffset)
>                 {
>                         // Snap to next view
>                         mFlingDirection = -1;
>                 }
>         }
>
>         private class FlingGalleryView
>         {
>                 private int mViewNumber;
>                 private FrameLayout mParentLayout;
>
>                 private FrameLayout mInvalidLayout = null;
>                 private LinearLayout mInternalLayout = null;
>                 private View mExternalView = null;
>
>                 public FlingGalleryView(int viewNumber, FrameLayout 
> parentLayout)
>                 {
>                         mViewNumber = viewNumber;
>                         mParentLayout = parentLayout;
>
>                         // Invalid layout is used when outside gallery
>                         mInvalidLayout = new FrameLayout(mContext);
>                         mInvalidLayout.setLayoutParams(new 
> LinearLayout.LayoutParams(
>                         LayoutParams.MATCH_PARENT,
> LayoutParams.MATCH_PARENT));
>
>                         // Internal layout is permanent for duration
>                         mInternalLayout = new LinearLayout(mContext);
>                         mInternalLayout.setLayoutParams(new 
> LinearLayout.LayoutParams(
>                         LayoutParams.MATCH_PARENT,
> LayoutParams.MATCH_PARENT));
>
>                         mParentLayout.addView(mInternalLayout);
>                 }
>
>                 public void recycleView(int newPosition)
>                 {
>                         if (mExternalView != null)
>                         {
>                                 mInternalLayout.removeView(mExternalView);
>                         }
>
>                         if (mAdapter != null)
>                         {
>                                 mExternalView =...
>
> read more »

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to