android仿UC墨迹天气左右拖动效果

http://www.oschina.net/code/snippet_16_2541

(另)http://www.eoeandroid.com/thread-48286-1-1.html(带附件)

[代码] FlingGalleryActivity

001 import android.app.Activity;
002 import android.os.Bundle;
003  
004 import android.content.Context;
005 import android.graphics.Color;
006 import android.util.Log;
007 import android.view.Gravity;
008 import android.view.MotionEvent;
009 import android.view.View;
010 import android.view.ViewGroup;
011 import android.view.View.OnClickListener;
012 import android.widget.ArrayAdapter;
013 import android.widget.Button;
014 import android.widget.CheckBox;
015 import android.widget.EditText;
016 import android.widget.LinearLayout;
017 import android.widget.TableLayout;
018 import android.widget.TextView;
019  
020 public class FlingGalleryActivity extends Activity
021 {
022     private final int color_red = Color.argb(100, 200, 0, 0);
023     private final int color_green = Color.argb(100, 0, 200, 0);
024     private final int color_blue = Color.argb(100, 0, 0, 200);
025     private final int color_yellow = Color.argb(100, 200, 200, 0);
026     private final int color_purple = Color.argb(100, 200, 0, 200);
027  
028     private final String[] mLabelArray = {"View1", "View2", "View3", "View4", "View5"};
029     private final int[] mColorArray = {color_red, color_green, color_blue, color_yellow, color_purple};
030  
031     private FlingGallery mGallery;
032     private CheckBox mCheckBox;
033  
034     // Note: The following handler is critical to correct function of
035     // the FlingGallery class. This enables the FlingGallery class to
036     // detect when the motion event has ended by finger being lifted
037  
038     @Override
039     public boolean onTouchEvent(MotionEvent event)
040     {
041         return mGallery.onGalleryTouchEvent(event);
042     }
043  
044     public void onCreate(Bundle savedInstanceState)
045     {
046         super.onCreate(savedInstanceState);
047  
048         mGallery = new FlingGallery(this);
049         mGallery.setPaddingWidth(5);
050         mGallery.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, mLabelArray)
051         {
052             @Override
053             public View getView(int position, View convertView, ViewGroup parent)
054             {
055                 Log.d("111", "count="+position);
056 //              if (convertView != null && convertView instanceof GalleryViewItem)
057 //                {
058 //                  GalleryViewItem galleryView = (GalleryViewItem) convertView;
059 //
060 //                  galleryView.mEdit1.setText("");
061 //                  galleryView.mText1.setText(mLabelArray[position]);
062 //                  galleryView.mText1.setBackgroundColor(mColorArray[position]);
063 //                  galleryView.mText2.setText(mLabelArray[position]);
064 //                  galleryView.mText2.setBackgroundColor(mColorArray[position]);
065 //                 
066 //                  Log.d("111", "count="+position);
067 //                 
068 //                  return galleryView;
069 //                 
070 //                }
071                  
072                 return new GalleryViewItem(getApplicationContext(), position);
073             }
074         });
075  
076         LinearLayout layout = new LinearLayout(getApplicationContext());
077         layout.setOrientation(LinearLayout.VERTICAL);
078  
079         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
080                 LinearLayout.LayoutParams.MATCH_PARENT,
081                 LinearLayout.LayoutParams.MATCH_PARENT);
082  
083         layoutParams.setMargins(10, 10, 10, 10);
084         layoutParams.weight = 1.0f;
085    
086         layout.addView(mGallery, layoutParams);
087          
088         mCheckBox = new CheckBox(getApplicationContext());
089         mCheckBox.setText("Gallery is Circular");
090         mCheckBox.setText("Gallery is Circular");
091         mCheckBox.setPadding(50, 10, 0, 10);
092         mCheckBox.setTextSize(30);
093         mCheckBox.setChecked(true);
094         mCheckBox.setOnClickListener(new OnClickListener()
095         {
096             @Override
097             public void onClick(View view)
098             {
099                 mGallery.setIsGalleryCircular(mCheckBox.isChecked());
100             }
101         });
102  
103         layout.addView(mCheckBox, new LinearLayout.LayoutParams(
104                 LinearLayout.LayoutParams.MATCH_PARENT,
105                 LinearLayout.LayoutParams.WRAP_CONTENT));
106          
107         setContentView(layout);
108     }  
109  
110     private class GalleryViewItem extends TableLayout
111     {
112         private EditText mEdit1;
113         private TextView mText1;
114         private TextView mText2;
115         private Button mButton1;
116         private Button mButton2;
117  
118         public GalleryViewItem(Context context, int position)
119         {
120             super(context);
121  
122             this.setOrientation(LinearLayout.VERTICAL);
123  
124             this.setLayoutParams(new LinearLayout.LayoutParams(
125                     LinearLayout.LayoutParams.MATCH_PARENT,
126                     LinearLayout.LayoutParams.MATCH_PARENT));
127              
128             mEdit1 = new EditText(context);
129  
130             this.addView(mEdit1, new LinearLayout.LayoutParams(
131                     LinearLayout.LayoutParams.MATCH_PARENT,
132                     LinearLayout.LayoutParams.WRAP_CONTENT));
133  
134             mText1 = new TextView(context);
135             mText1.setText(mLabelArray[position]);
136             mText1.setTextSize(30);
137             mText1.setGravity(Gravity.LEFT);
138             mText1.setBackgroundColor(mColorArray[position]);
139  
140             this.addView(mText1, new LinearLayout.LayoutParams(
141                     LinearLayout.LayoutParams.MATCH_PARENT,
142                     LinearLayout.LayoutParams.WRAP_CONTENT));
143  
144             mButton1 = new Button(context);
145             mButton1.setText("<<");
146             mButton1.setGravity(Gravity.LEFT);
147             mButton1.setOnClickListener(new OnClickListener()
148             {
149                 @Override
150                 public void onClick(View view)
151                 {
152                     mGallery.movePrevious();
153                 }
154             });
155              
156             this.addView(mButton1, new LinearLayout.LayoutParams(
157                     LinearLayout.LayoutParams.MATCH_PARENT,
158                     LinearLayout.LayoutParams.WRAP_CONTENT));
159  
160             mButton2 = new Button(context);
161             mButton2.setText(">>");
162             mButton2.setGravity(Gravity.RIGHT);
163             mButton2.setOnClickListener(new OnClickListener()
164             {
165                 @Override
166                 public void onClick(View view)
167                 {
168                     mGallery.moveNext();
169                 }
170             });
171              
172             this.addView(mButton2, new LinearLayout.LayoutParams(
173                     LinearLayout.LayoutParams.MATCH_PARENT,
174                     LinearLayout.LayoutParams.WRAP_CONTENT));
175  
176             mText2 = new TextView(context);
177             mText2.setText(mLabelArray[position]);
178             mText2.setTextSize(30);
179             mText2.setGravity(Gravity.RIGHT);
180             mText2.setBackgroundColor(mColorArray[position]);
181  
182             this.addView(mText2, new LinearLayout.LayoutParams(
183                     LinearLayout.LayoutParams.MATCH_PARENT,
184                     LinearLayout.LayoutParams.MATCH_PARENT, 1));
185         }
186     }
187 }

[代码] FlingGallery

001 import android.content.Context;
002 import android.view.GestureDetector;
003 import android.view.KeyEvent;
004 import android.view.MotionEvent;
005 import android.view.View;
006 import android.view.animation.Animation;
007 import android.view.animation.AnimationUtils;
008 import android.view.animation.Interpolator;
009 import android.view.animation.Transformation;
010 import android.widget.Adapter;
011 import android.widget.FrameLayout;
012 import android.widget.LinearLayout;
013  
014 // TODO:
015  
016 // 1. In order to improve performance Cache screen bitmap and use for animation
017 // 2. Establish superfluous memory allocations and delay or replace with reused objects
018 //    Probably need to make sure we are not allocating objects (strings, etc.) in loops
019  
020 public class FlingGallery extends FrameLayout
021 {
022     // Constants
023      
024     private final int swipe_min_distance = 120;
025     private final int swipe_max_off_path = 250;
026     private final int swipe_threshold_veloicty = 400;
027  
028     // Properties
029      
030     private int mViewPaddingWidth = 0;
031     private int mAnimationDuration = 250;
032     private float mSnapBorderRatio = 0.5f;
033     private boolean mIsGalleryCircular = true;
034  
035     // Members
036  
037     private int mGalleryWidth = 0;
038     private boolean mIsTouched = false;
039     private boolean mIsDragging = false;
040     private float mCurrentOffset = 0.0f;
041     private long mScrollTimestamp = 0;
042     private int mFlingDirection = 0;
043     private int mCurrentPosition = 0;
044     private int mCurrentViewNumber = 0;
045  
046     private Context mContext;
047     private Adapter mAdapter;
048     private FlingGalleryView[] mViews;
049     private FlingGalleryAnimation mAnimation;
050     private GestureDetector mGestureDetector;
051     private Interpolator mDecelerateInterpolater;
052  
053     public FlingGallery(Context context)
054     {
055         super(context);
056  
057         mContext = context;
058         mAdapter = null;
059          
060         mViews = new FlingGalleryView[3];
061         mViews[0] = new FlingGalleryView(0, this);
062         mViews[1] = new FlingGalleryView(1, this);
063         mViews[2] = new FlingGalleryView(2, this);
064  
065         mAnimation = new FlingGalleryAnimation();
066         mGestureDetector = new GestureDetector(new FlingGestureDetector());
067         mDecelerateInterpolater = AnimationUtils.loadInterpolator(mContext, android.R.anim.decelerate_interpolator);
068     }
069  
070     public void setPaddingWidth(int viewPaddingWidth)
071     {
072         mViewPaddingWidth = viewPaddingWidth;
073     }
074  
075     public void setAnimationDuration(int animationDuration)
076     {
077         mAnimationDuration = animationDuration;
078     }
079      
080     public void setSnapBorderRatio(float snapBorderRatio)
081     {
082         mSnapBorderRatio = snapBorderRatio;
083     }
084  
085     public void setIsGalleryCircular(boolean isGalleryCircular)
086     {
087         if (mIsGalleryCircular != isGalleryCircular)
088         {
089             mIsGalleryCircular = isGalleryCircular;
090      
091             if (mCurrentPosition == getFirstPosition())
092             {
093                 // We need to reload the view immediately to the left to change it to circular view or blank
094                 mViews[getPrevViewNumber(mCurrentViewNumber)].recycleView(getPrevPosition(mCurrentPosition));          
095             }
096      
097             if (mCurrentPosition == getLastPosition())
098             {
099                 // We need to reload the view immediately to the right to change it to circular view or blank
100                 mViews[getNextViewNumber(mCurrentViewNumber)].recycleView(getNextPosition(mCurrentPosition));          
101             }
102         }
103     }
104  
105     public int getGalleryCount()
106     {
107         return (mAdapter == null) ? 0 : mAdapter.getCount();
108     }
109  
110     public int getFirstPosition()
111     {
112         return 0;
113     }
114  
115     public int getLastPosition()
116     {
117         return (getGalleryCount() == 0) ? 0 : getGalleryCount() - 1;
118     }
119  
120     private int getPrevPosition(int relativePosition)
121     {
122         int prevPosition = relativePosition - 1;
123  
124         if (prevPosition < getFirstPosition())
125         {
126             prevPosition = getFirstPosition() - 1;
127  
128             if (mIsGalleryCircular == true)
129             {
130                 prevPosition = getLastPosition();
131             }
132         }
133  
134         return prevPosition;
135     }
136  
137     private int getNextPosition(int relativePosition)
138     {
139         int nextPosition = relativePosition + 1;
140  
141         if (nextPosition > getLastPosition())
142         {
143             nextPosition = getLastPosition() + 1;
144  
145             if (mIsGalleryCircular == true)
146             {
147                 nextPosition = getFirstPosition();
148             }
149         }
150  
151         return nextPosition;
152     }
153  
154     private int getPrevViewNumber(int relativeViewNumber)
155     {
156         return (relativeViewNumber == 0) ? 2 : relativeViewNumber - 1;
157     }
158  
159     private int getNextViewNumber(int relativeViewNumber)
160     {
161         return (relativeViewNumber == 2) ? 0 : relativeViewNumber + 1;
162     }
163      
164     @Override
165     protected void onLayout(boolean changed, int left, int top, int right, int bottom)
166     {
167         super.onLayout(changed, left, top, right, bottom);
168  
169         // Calculate our view width
170         mGalleryWidth = right - left;
171  
172         if (changed == true)
173         {
174             // Position views at correct starting offsets
175             mViews[0].setOffset(0, 0, mCurrentViewNumber);
176             mViews[1].setOffset(0, 0, mCurrentViewNumber);
177             mViews[2].setOffset(0, 0, mCurrentViewNumber);
178         }
179     }
180  
181     public void setAdapter(Adapter adapter)
182     {
183         mAdapter = adapter;
184         mCurrentPosition = 0;
185         mCurrentViewNumber = 0;
186  
187         // Load the initial views from adapter
188         mViews[0].recycleView(mCurrentPosition);
189         mViews[1].recycleView(getNextPosition(mCurrentPosition));
190         mViews[2].recycleView(getPrevPosition(mCurrentPosition));
191  
192         // Position views at correct starting offsets
193         mViews[0].setOffset(0, 0, mCurrentViewNumber);
194         mViews[1].setOffset(0, 0, mCurrentViewNumber);
195         mViews[2].setOffset(0, 0, mCurrentViewNumber);
196     }
197  
198     private int getViewOffset(int viewNumber, int relativeViewNumber)
199     {
200         // Determine width including configured padding width
201         int offsetWidth = mGalleryWidth + mViewPaddingWidth;
202  
203         // Position the previous view one measured width to left
204         if (viewNumber == getPrevViewNumber(relativeViewNumber))
205         {
206             return offsetWidth;
207         }
208  
209         // Position the next view one measured width to the right
210         if (viewNumber == getNextViewNumber(relativeViewNumber))
211         {
212             return offsetWidth * -1;
213         }
214  
215         return 0;
216     }
217  
218     void movePrevious()
219     {
220         // Slide to previous view
221         mFlingDirection = 1;
222         processGesture();
223     }
224  
225     void moveNext()
226     {
227         // Slide to next view
228         mFlingDirection = -1;
229         processGesture();
230     }
231  
232      @Override
233      public boolean onKeyDown(int keyCode, KeyEvent event)
234      {
235         switch (keyCode)
236         {
237         case KeyEvent.KEYCODE_DPAD_LEFT:
238             movePrevious();
239             return true;
240      
241         case KeyEvent.KEYCODE_DPAD_RIGHT:
242             moveNext();
243             return true;
244      
245         case KeyEvent.KEYCODE_DPAD_CENTER:
246         case KeyEvent.KEYCODE_ENTER:
247         }
248  
249         return super.onKeyDown(keyCode, event);
250     }
251  
252     public boolean onGalleryTouchEvent(MotionEvent event)
253     {
254         boolean consumed = mGestureDetector.onTouchEvent(event);
255          
256         if (event.getAction() == MotionEvent.ACTION_UP)
257         {
258             if (mIsTouched || mIsDragging)
259             {
260                 processScrollSnap();
261                 processGesture();
262             }
263         }
264          
265         return consumed;
266     }
267  
268     void processGesture()
269     {
270         int newViewNumber = mCurrentViewNumber;
271         int reloadViewNumber = 0;
272         int reloadPosition = 0;
273  
274         mIsTouched = false;
275         mIsDragging = false;
276  
277         if (mFlingDirection > 0)
278         {
279             if (mCurrentPosition > getFirstPosition() || mIsGalleryCircular == true)
280             {
281                 // Determine previous view and outgoing view to recycle
282                 newViewNumber = getPrevViewNumber(mCurrentViewNumber);
283                 mCurrentPosition = getPrevPosition(mCurrentPosition);
284                 reloadViewNumber = getNextViewNumber(mCurrentViewNumber);
285                 reloadPosition = getPrevPosition(mCurrentPosition);
286             }
287         }
288  
289         if (mFlingDirection < 0)
290         {
291             if (mCurrentPosition < getLastPosition() || mIsGalleryCircular == true)
292             {
293                 // Determine the next view and outgoing view to recycle
294                 newViewNumber = getNextViewNumber(mCurrentViewNumber);
295                 mCurrentPosition = getNextPosition(mCurrentPosition);
296                 reloadViewNumber = getPrevViewNumber(mCurrentViewNumber);
297                 reloadPosition = getNextPosition(mCurrentPosition);
298             }
299         }
300  
301         if (newViewNumber != mCurrentViewNumber)
302         {
303             mCurrentViewNumber = newViewNumber;
304  
305             // Reload outgoing view from adapter in new position
306             mViews[reloadViewNumber].recycleView(reloadPosition);
307         }
308  
309         // Ensure input focus on the current view
310         mViews[mCurrentViewNumber].requestFocus();
311  
312         // Run the slide animations for view transitions
313         mAnimation.prepareAnimation(mCurrentViewNumber);
314         this.startAnimation(mAnimation);
315  
316         // Reset fling state
317         mFlingDirection = 0;
318     }
319  
320     void processScrollSnap()
321     {
322         // Snap to next view if scrolled passed snap position
323         float rollEdgeWidth = mGalleryWidth * mSnapBorderRatio;
324         int rollOffset = mGalleryWidth - (int) rollEdgeWidth;
325         int currentOffset = mViews[mCurrentViewNumber].getCurrentOffset();
326  
327         if (currentOffset <= rollOffset * -1)
328         {
329             // Snap to previous view
330             mFlingDirection = 1;
331         }
332  
333         if (currentOffset >= rollOffset)
334         {
335             // Snap to next view
336             mFlingDirection = -1;
337         }
338     }
339  
340     private class FlingGalleryView
341     {
342         private int mViewNumber;
343         private FrameLayout mParentLayout;
344          
345         private FrameLayout mInvalidLayout = null;
346         private LinearLayout mInternalLayout = null;
347         private View mExternalView = null;
348  
349         public FlingGalleryView(int viewNumber, FrameLayout parentLayout)
350         {
351             mViewNumber = viewNumber;
352             mParentLayout = parentLayout;
353  
354             // Invalid layout is used when outside gallery
355             mInvalidLayout = new FrameLayout(mContext);
356             mInvalidLayout.setLayoutParams(new LinearLayout.LayoutParams(
357                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
358  
359             // Internal layout is permanent for duration
360             mInternalLayout = new LinearLayout(mContext);
361             mInternalLayout.setLayoutParams(new LinearLayout.LayoutParams(
362                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
363  
364             mParentLayout.addView(mInternalLayout);
365         }
366  
367         public void recycleView(int newPosition)
368         {
369             if (mExternalView != null)
370             {
371                 mInternalLayout.removeView(mExternalView);
372             }
373  
374             if (mAdapter != null)
375             {
376                 if (newPosition >= getFirstPosition() && newPosition <= getLastPosition())
377                 {
378                     mExternalView = mAdapter.getView(newPosition, mExternalView, mInternalLayout);
379                 }
380                 else
381                 {
382                     mExternalView = mInvalidLayout;
383                 }
384             }
385  
386             if (mExternalView != null)
387             {
388                 mInternalLayout.addView(mExternalView, new LinearLayout.LayoutParams(
389                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
390             }
391         }
392  
393         public void setOffset(int xOffset, int yOffset, int relativeViewNumber)
394         {
395             // Scroll the target view relative to its own position relative to currently displayed view
396             mInternalLayout.scrollTo(getViewOffset(mViewNumber, relativeViewNumber) + xOffset, yOffset);
397         }
398          
399         public int getCurrentOffset()
400         {
401             // Return the current scroll position
402             return mInternalLayout.getScrollX();
403         }
404  
405         public void requestFocus()
406         {
407             mInternalLayout.requestFocus();
408         }
409     }
410  
411     private class FlingGalleryAnimation extends Animation
412     {
413         private boolean mIsAnimationInProgres;
414         private int mRelativeViewNumber;
415         private int mInitialOffset;
416         private int mTargetOffset;
417         private int mTargetDistance;   
418   
419         public FlingGalleryAnimation()
420         {
421             mIsAnimationInProgres = false;
422             mRelativeViewNumber = 0;
423             mInitialOffset = 0;
424             mTargetOffset = 0;
425             mTargetDistance = 0;
426         }
427   
428         public void prepareAnimation(int relativeViewNumber)
429         {
430             // If we are animating relative to a new view
431             if (mRelativeViewNumber != relativeViewNumber)
432             {
433                 if (mIsAnimationInProgres == true)
434                 {
435                     // We only have three views so if requested again to animate in same direction we must snap
436                     int newDirection = (relativeViewNumber == getPrevViewNumber(mRelativeViewNumber)) ? 1 : -1;
437                     int animDirection = (mTargetDistance < 0) ? 1 : -1;
438  
439                     // If animation in same direction
440                     if (animDirection == newDirection)
441                     {
442                         // Ran out of time to animate so snap to the target offset
443                         mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);
444                         mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);
445                         mViews[2].setOffset(mTargetOffset, 0, mRelativeViewNumber);
446                     }
447                 }
448      
449                 // Set relative view number for animation
450                 mRelativeViewNumber = relativeViewNumber;
451             }
452  
453             // Note: In this implementation the targetOffset will always be zero
454             // as we are centering the view; but we include the calculations of
455             // targetOffset and targetDistance for use in future implementations
456  
457             mInitialOffset = mViews[mRelativeViewNumber].getCurrentOffset();
458             mTargetOffset = getViewOffset(mRelativeViewNumber, mRelativeViewNumber);
459             mTargetDistance = mTargetOffset - mInitialOffset;
460  
461             // Configure base animation properties
462             this.setDuration(mAnimationDuration);
463             this.setInterpolator(mDecelerateInterpolater);
464  
465             // Start/continued animation
466             mIsAnimationInProgres = true;
467         }
468  
469         @Override
470         protected void applyTransformation(float interpolatedTime, Transformation transformation)
471         {
472             // Ensure interpolatedTime does not over-shoot then calculate new offset
473             interpolatedTime = (interpolatedTime > 1.0f) ? 1.0f : interpolatedTime;
474             int offset = mInitialOffset + (int) (mTargetDistance * interpolatedTime);
475  
476             for (int viewNumber = 0; viewNumber < 3; viewNumber++)
477             {
478                 // Only need to animate the visible views as the other view will always be off-screen
479                 if ((mTargetDistance > 0 && viewNumber != getNextViewNumber(mRelativeViewNumber)) ||
480                     (mTargetDistance < 0 && viewNumber != getPrevViewNumber(mRelativeViewNumber)))
481                 {
482                     mViews[viewNumber].setOffset(offset, 0, mRelativeViewNumber);
483                 }
484             }
485         }
486  
487         @Override
488         public boolean getTransformation(long currentTime, Transformation outTransformation)
489         {
490             if (super.getTransformation(currentTime, outTransformation) == false)
491             {
492                 // Perform final adjustment to offsets to cleanup animation
493                 mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);
494                 mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);
495                 mViews[2].setOffset(mTargetOffset, 0, mRelativeViewNumber);
496  
497                 // Reached the animation target
498                 mIsAnimationInProgres = false;
499  
500                 return false;
501             }
502   
503             // Cancel if the screen touched
504             if (mIsTouched || mIsDragging)
505             {
506                 // Note that at this point we still consider ourselves to be animating
507                 // because we have not yet reached the target offset; its just that the
508                 // user has temporarily interrupted the animation with a touch gesture
509  
510                 return false;
511             }
512  
513             return true;
514         }
515     }
516  
517     private class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener
518     {
519         @Override
520         public boolean onDown(MotionEvent e)
521         {
522             // Stop animation
523             mIsTouched = true;
524  
525             // Reset fling state
526             mFlingDirection = 0;
527             return true;
528         }
529  
530         @Override
531         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
532         {
533             if (e2.getAction() == MotionEvent.ACTION_MOVE)
534             {
535                 if (mIsDragging == false)
536                 {
537                     // Stop animation
538                     mIsTouched = true;
539       
540                     // Reconfigure scroll
541                     mIsDragging = true;
542                     mFlingDirection = 0;
543                     mScrollTimestamp = System.currentTimeMillis();
544                     mCurrentOffset = mViews[mCurrentViewNumber].getCurrentOffset();
545                 }
546  
547                 float maxVelocity = mGalleryWidth / (mAnimationDuration / 1000.0f);
548                 long timestampDelta = System.currentTimeMillis() - mScrollTimestamp;
549                 float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);
550                 float currentScrollDelta = e1.getX() - e2.getX();
551  
552                 if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1;
553                 if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta;
554                 int scrollOffset = Math.round(mCurrentOffset + currentScrollDelta);
555  
556                 // We can't scroll more than the width of our own frame layout
557                 if (scrollOffset >= mGalleryWidth) scrollOffset = mGalleryWidth;
558                 if (scrollOffset <= mGalleryWidth * -1) scrollOffset = mGalleryWidth * -1;
559                  
560                 mViews[0].setOffset(scrollOffset, 0, mCurrentViewNumber);
561                 mViews[1].setOffset(scrollOffset, 0, mCurrentViewNumber);
562                 mViews[2].setOffset(scrollOffset, 0, mCurrentViewNumber);
563             }
564  
565             return false;
566         }
567  
568         @Override
569         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
570         {
571             if (Math.abs(e1.getY() - e2.getY()) <= swipe_max_off_path)
572             {
573                 if (e2.getX() - e1.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)
574                 {
575                     movePrevious();
576                 }
577  
578                 if(e1.getX() - e2.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)
579                 {
580                     moveNext();
581                 }
582             }
583  
584             return false;
585         }
586  
587         @Override
588         public void onLongPress(MotionEvent e)
589         {
590             // Finalise scrolling
591             mFlingDirection = 0;
592             processGesture();
593         }
594  
595         @Override
596         public void onShowPress(MotionEvent e)
597         {
598         }
599  
600         @Override
601         public boolean onSingleTapUp(MotionEvent e)
602         {
603             // Reset fling state
604             mFlingDirection = 0;
605             return false;
606         }
607     }
608 }
原文地址:https://www.cnblogs.com/Greenwood/p/2079926.html