zoukankan      html  css  js  c++  java
  • 实现自定义view(2):仿Android QQ多屏幕显示ListView的效果


    转载请注明出处。博客地址:http://blog.csdn.net/mylzc

    本文在《仿 UC,墨迹天气左右拖动 多屏幕显示效果》的基础上对代码进行修改,模仿Android QQ主界面的分屏ListView滑动效果。

    当进行横向滑动时,会切换屏幕,当纵向滑动时,ListView会滚动。

    效果图如下:



    代码如下:

    工程文件下载

    FlingGallery.java

    [java] view plaincopy
    1. package com.droidful.flinggallery;  
    2.   
    3. import android.content.Context;  
    4. import android.util.Log;  
    5. import android.view.GestureDetector;  
    6. import android.view.KeyEvent;  
    7. import android.view.MotionEvent;  
    8. import android.view.View;  
    9. import android.view.animation.Animation;  
    10. import android.view.animation.AnimationUtils;  
    11. import android.view.animation.Interpolator;  
    12. import android.view.animation.Transformation;  
    13. import android.widget.Adapter;  
    14. import android.widget.FrameLayout;  
    15. import android.widget.LinearLayout;  
    16.   
    17. // TODO:  
    18.   
    19. // 1. In order to improve performance Cache screen bitmap and use for animation  
    20. // 2. Establish superfluous memory allocations and delay or replace with reused objects  
    21. //    Probably need to make sure we are not allocating objects (strings, etc.) in loops  
    22.   
    23. public class FlingGallery extends FrameLayout  
    24. {  
    25.     // Constants  
    26.       
    27.     private final int swipe_min_distance = 120;  
    28.     private final int swipe_max_off_path = 250;  
    29.     private final int swipe_threshold_veloicty = 400;  
    30.   
    31.     // Properties  
    32.       
    33.     private int mViewPaddingWidth = 0;  
    34.     private int mAnimationDuration = 250;  
    35.     private float mSnapBorderRatio = 0.5f;  
    36.     private boolean mIsGalleryCircular = true;  
    37.     private int mDetectScrollX = 50;  
    38.   
    39.     // Members  
    40.   
    41.     private int mGalleryWidth = 0;  
    42.     private boolean mIsTouched = false;  
    43.     private boolean mIsDragging = false;  
    44.     private float mCurrentOffset = 0.0f;  
    45.     private long mScrollTimestamp = 0;  
    46.     private int mFlingDirection = 0;  
    47.     private int mCurrentPosition = 0;  
    48.     private int mCurrentViewNumber = 0;  
    49.   
    50.     private Context mContext;  
    51.     private Adapter mAdapter;  
    52.     private FlingGalleryView[] mViews;  
    53.     private FlingGalleryAnimation mAnimation;  
    54.     private GestureDetector mGestureDetector;  
    55.     private FlingGestureDetectorListener mGestureDetectorListener;  
    56.     private GestureDetector mInterruptDetector;  
    57.     private Interpolator mDecelerateInterpolater;  
    58.   
    59.     public FlingGallery(Context context)  
    60.     {  
    61.         super(context);  
    62.   
    63.         mContext = context;  
    64.         mAdapter = null;  
    65.           
    66.         mViews = new FlingGalleryView[3];  
    67.         mViews[0] = new FlingGalleryView(0this);  
    68.         mViews[1] = new FlingGalleryView(1this);  
    69.         mViews[2] = new FlingGalleryView(2this);  
    70.   
    71.         mAnimation = new FlingGalleryAnimation();  
    72.         mGestureDetectorListener = new FlingGestureDetectorListener();  
    73.         mGestureDetector = new GestureDetector(mGestureDetectorListener);  
    74.         mInterruptDetector = new GestureDetector(new InterruptGestureDetectorListener());  
    75.         mDecelerateInterpolater = AnimationUtils.loadInterpolator(mContext, android.R.anim.decelerate_interpolator);  
    76.     }  
    77.   
    78.     public void setPaddingWidth(int viewPaddingWidth)  
    79.     {  
    80.         mViewPaddingWidth = viewPaddingWidth;  
    81.     }  
    82.   
    83.     public void setAnimationDuration(int animationDuration)  
    84.     {  
    85.         mAnimationDuration = animationDuration;  
    86.     }  
    87.       
    88.     public void setSnapBorderRatio(float snapBorderRatio)  
    89.     {  
    90.         mSnapBorderRatio = snapBorderRatio;  
    91.     }  
    92.   
    93.     public void setIsGalleryCircular(boolean isGalleryCircular)   
    94.     {  
    95.         if (mIsGalleryCircular != isGalleryCircular)  
    96.         {  
    97.             mIsGalleryCircular = isGalleryCircular;  
    98.       
    99.             if (mCurrentPosition == getFirstPosition())  
    100.             {  
    101.                 // We need to reload the view immediately to the left to change it to circular view or blank  
    102.                 mViews[getPrevViewNumber(mCurrentViewNumber)].recycleView(getPrevPosition(mCurrentPosition));             
    103.             }  
    104.       
    105.             if (mCurrentPosition == getLastPosition())  
    106.             {  
    107.                 // We need to reload the view immediately to the right to change it to circular view or blank  
    108.                 mViews[getNextViewNumber(mCurrentViewNumber)].recycleView(getNextPosition(mCurrentPosition));             
    109.             }  
    110.         }  
    111.     }  
    112.   
    113.     public int getGalleryCount()  
    114.     {  
    115.         return (mAdapter == null) ? 0 : mAdapter.getCount();  
    116.     }  
    117.   
    118.     public int getFirstPosition()  
    119.     {  
    120.         return 0;  
    121.     }  
    122.       
    123.     @Override  
    124.     public boolean onInterceptTouchEvent (MotionEvent ev) {  
    125.   
    126.         return mInterruptDetector.onTouchEvent(ev);  
    127.     }  
    128.       
    129.     @Override  
    130.     public boolean onTouchEvent (MotionEvent ev) {  
    131.         Log.d("Test""test" );  
    132.         boolean value = onGalleryTouchEvent(ev);  
    133.         Log.d("Test""" + value);  
    134.         return true;  
    135.     }  
    136.   
    137.     public int getLastPosition()  
    138.     {  
    139.         return (getGalleryCount() == 0) ? 0 : getGalleryCount() - 1;  
    140.     }  
    141.   
    142.     private int getPrevPosition(int relativePosition)  
    143.     {  
    144.         int prevPosition = relativePosition - 1;  
    145.   
    146.         if (prevPosition < getFirstPosition())  
    147.         {  
    148.             prevPosition = getFirstPosition() - 1;  
    149.   
    150.             if (mIsGalleryCircular == true)  
    151.             {  
    152.                 prevPosition = getLastPosition();  
    153.             }  
    154.         }  
    155.   
    156.         return prevPosition;  
    157.     }  
    158.   
    159.     private int getNextPosition(int relativePosition)  
    160.     {  
    161.         int nextPosition = relativePosition + 1;  
    162.   
    163.         if (nextPosition > getLastPosition())  
    164.         {  
    165.             nextPosition = getLastPosition() + 1;  
    166.   
    167.             if (mIsGalleryCircular == true)  
    168.             {  
    169.                 nextPosition = getFirstPosition();  
    170.             }  
    171.         }  
    172.   
    173.         return nextPosition;  
    174.     }  
    175.   
    176.     private int getPrevViewNumber(int relativeViewNumber)  
    177.     {  
    178.         return (relativeViewNumber == 0) ? 2 : relativeViewNumber - 1;  
    179.     }  
    180.   
    181.     private int getNextViewNumber(int relativeViewNumber)  
    182.     {  
    183.         return (relativeViewNumber == 2) ? 0 : relativeViewNumber + 1;  
    184.     }  
    185.       
    186.     @Override  
    187.     protected void onLayout(boolean changed, int left, int top, int right, int bottom)  
    188.     {  
    189.         super.onLayout(changed, left, top, right, bottom);  
    190.   
    191.         // Calculate our view width  
    192.         mGalleryWidth = right - left;  
    193.   
    194.         if (changed == true)  
    195.         {  
    196.             // Position views at correct starting offsets  
    197.             mViews[0].setOffset(00, mCurrentViewNumber);  
    198.             mViews[1].setOffset(00, mCurrentViewNumber);  
    199.             mViews[2].setOffset(00, mCurrentViewNumber);  
    200.         }  
    201.     }  
    202.   
    203.     public void setAdapter(Adapter adapter)  
    204.     {  
    205.         mAdapter = adapter;  
    206.         mCurrentPosition = 0;  
    207.         mCurrentViewNumber = 0;  
    208.   
    209.         // Load the initial views from adapter  
    210.         mViews[0].recycleView(mCurrentPosition);  
    211.         mViews[1].recycleView(getNextPosition(mCurrentPosition));  
    212.         mViews[2].recycleView(getPrevPosition(mCurrentPosition));  
    213.   
    214.         // Position views at correct starting offsets  
    215.         mViews[0].setOffset(00, mCurrentViewNumber);  
    216.         mViews[1].setOffset(00, mCurrentViewNumber);  
    217.         mViews[2].setOffset(00, mCurrentViewNumber);  
    218.     }  
    219.   
    220.     private int getViewOffset(int viewNumber, int relativeViewNumber)  
    221.     {  
    222.         // Determine width including configured padding width  
    223.         int offsetWidth = mGalleryWidth + mViewPaddingWidth;  
    224.   
    225.         // Position the previous view one measured width to left  
    226.         if (viewNumber == getPrevViewNumber(relativeViewNumber))  
    227.         {  
    228.             return offsetWidth;  
    229.         }  
    230.   
    231.         // Position the next view one measured width to the right  
    232.         if (viewNumber == getNextViewNumber(relativeViewNumber))  
    233.         {  
    234.             return offsetWidth * -1;  
    235.         }  
    236.   
    237.         return 0;  
    238.     }  
    239.   
    240.     void movePrevious()  
    241.     {  
    242.         // Slide to previous view  
    243.         mFlingDirection = 1;  
    244.         processGesture();  
    245.     }  
    246.   
    247.     void moveNext()  
    248.     {  
    249.         // Slide to next view  
    250.         mFlingDirection = -1;  
    251.         processGesture();  
    252.     }  
    253.   
    254.      @Override  
    255.      public boolean onKeyDown(int keyCode, KeyEvent event)  
    256.      {  
    257.         switch (keyCode)  
    258.         {  
    259.         case KeyEvent.KEYCODE_DPAD_LEFT:  
    260.             movePrevious();  
    261.             return true;  
    262.       
    263.         case KeyEvent.KEYCODE_DPAD_RIGHT:  
    264.             moveNext();  
    265.             return true;  
    266.       
    267.         case KeyEvent.KEYCODE_DPAD_CENTER:  
    268.         case KeyEvent.KEYCODE_ENTER:  
    269.         }  
    270.   
    271.         return super.onKeyDown(keyCode, event);  
    272.     }  
    273.   
    274.        
    275.     public boolean onGalleryTouchEvent(MotionEvent event)  
    276.     {  
    277.         boolean consumed = mGestureDetector.onTouchEvent(event);  
    278.           
    279.         if (event.getAction() == MotionEvent.ACTION_UP)  
    280.         {  
    281.             if (mIsTouched || mIsDragging)  
    282.             {  
    283.                 processScrollSnap();  
    284.                 processGesture();  
    285.             }  
    286.         }  
    287.           
    288.         return consumed;  
    289.     }  
    290.   
    291.     void processGesture()  
    292.     {  
    293.         int newViewNumber = mCurrentViewNumber;  
    294.         int reloadViewNumber = 0;  
    295.         int reloadPosition = 0;  
    296.   
    297.         mIsTouched = false;  
    298.         mIsDragging = false;  
    299.   
    300.         if (mFlingDirection > 0)  
    301.         {  
    302.             if (mCurrentPosition > getFirstPosition() || mIsGalleryCircular == true)  
    303.             {  
    304.                 // Determine previous view and outgoing view to recycle  
    305.                 newViewNumber = getPrevViewNumber(mCurrentViewNumber);  
    306.                 mCurrentPosition = getPrevPosition(mCurrentPosition);  
    307.                 reloadViewNumber = getNextViewNumber(mCurrentViewNumber);   
    308.                 reloadPosition = getPrevPosition(mCurrentPosition);  
    309.             }  
    310.         }  
    311.   
    312.         if (mFlingDirection < 0)  
    313.         {  
    314.             if (mCurrentPosition < getLastPosition() || mIsGalleryCircular == true)  
    315.             {  
    316.                 // Determine the next view and outgoing view to recycle  
    317.                 newViewNumber = getNextViewNumber(mCurrentViewNumber);  
    318.                 mCurrentPosition = getNextPosition(mCurrentPosition);  
    319.                 reloadViewNumber = getPrevViewNumber(mCurrentViewNumber);  
    320.                 reloadPosition = getNextPosition(mCurrentPosition);  
    321.             }  
    322.         }  
    323.   
    324.         if (newViewNumber != mCurrentViewNumber)  
    325.         {  
    326.             mCurrentViewNumber = newViewNumber;   
    327.   
    328.             // Reload outgoing view from adapter in new position  
    329.             mViews[reloadViewNumber].recycleView(reloadPosition);  
    330.         }  
    331.   
    332.         // Ensure input focus on the current view  
    333.         mViews[mCurrentViewNumber].requestFocus();  
    334.   
    335.         // Run the slide animations for view transitions  
    336.         mAnimation.prepareAnimation(mCurrentViewNumber);  
    337.         this.startAnimation(mAnimation);  
    338.   
    339.         // Reset fling state  
    340.         mFlingDirection = 0;  
    341.     }  
    342.   
    343.     void processScrollSnap()  
    344.     {  
    345.         // Snap to next view if scrolled passed snap position  
    346.         float rollEdgeWidth = mGalleryWidth * mSnapBorderRatio;  
    347.         int rollOffset = mGalleryWidth - (int) rollEdgeWidth;  
    348.         int currentOffset = mViews[mCurrentViewNumber].getCurrentOffset();  
    349.   
    350.         if (currentOffset <= rollOffset * -1)  
    351.         {  
    352.             // Snap to previous view  
    353.             mFlingDirection = 1;  
    354.         }  
    355.   
    356.         if (currentOffset >= rollOffset)  
    357.         {  
    358.             // Snap to next view  
    359.             mFlingDirection = -1;  
    360.         }  
    361.     }  
    362.   
    363.     private class FlingGalleryView  
    364.     {  
    365.         private int mViewNumber;  
    366.         private FrameLayout mParentLayout;  
    367.           
    368.         private FrameLayout mInvalidLayout = null;  
    369.         private LinearLayout mInternalLayout = null;  
    370.         private View mExternalView = null;  
    371.   
    372.         public FlingGalleryView(int viewNumber, FrameLayout parentLayout)  
    373.         {  
    374.             mViewNumber = viewNumber;  
    375.             mParentLayout = parentLayout;  
    376.   
    377.             // Invalid layout is used when outside gallery  
    378.             mInvalidLayout = new FrameLayout(mContext);  
    379.             mInvalidLayout.setLayoutParams(new LinearLayout.LayoutParams(   
    380.                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  
    381.   
    382.             // Internal layout is permanent for duration  
    383.             mInternalLayout = new LinearLayout(mContext);  
    384.             mInternalLayout.setLayoutParams(new LinearLayout.LayoutParams(   
    385.                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  
    386.   
    387.             mParentLayout.addView(mInternalLayout);  
    388.         }  
    389.   
    390.         public void recycleView(int newPosition)  
    391.         {  
    392.             if (mExternalView != null)  
    393.             {  
    394.                 mInternalLayout.removeView(mExternalView);  
    395.             }  
    396.   
    397.             if (mAdapter != null)  
    398.             {  
    399.                 if (newPosition >= getFirstPosition() && newPosition <= getLastPosition())  
    400.                 {  
    401.                     mExternalView = mAdapter.getView(newPosition, mExternalView, mInternalLayout);  
    402.                 }  
    403.                 else  
    404.                 {  
    405.                     mExternalView = mInvalidLayout;  
    406.                 }  
    407.             }  
    408.   
    409.             if (mExternalView != null)  
    410.             {  
    411.                 mInternalLayout.addView(mExternalView, new LinearLayout.LayoutParams(   
    412.                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  
    413.             }  
    414.         }  
    415.   
    416.         public void setOffset(int xOffset, int yOffset, int relativeViewNumber)  
    417.         {  
    418.             // Scroll the target view relative to its own position relative to currently displayed view  
    419.             mInternalLayout.scrollTo(getViewOffset(mViewNumber, relativeViewNumber) + xOffset, yOffset);  
    420.         }  
    421.           
    422.         public int getCurrentOffset()  
    423.         {  
    424.             // Return the current scroll position  
    425.             return mInternalLayout.getScrollX();  
    426.         }  
    427.   
    428.         public void requestFocus()  
    429.         {  
    430.             mInternalLayout.requestFocus();  
    431.         }  
    432.     }  
    433.   
    434.     private class FlingGalleryAnimation extends Animation  
    435.     {  
    436.         private boolean mIsAnimationInProgres;  
    437.         private int mRelativeViewNumber;  
    438.         private int mInitialOffset;  
    439.         private int mTargetOffset;  
    440.         private int mTargetDistance;      
    441.    
    442.         public FlingGalleryAnimation()  
    443.         {  
    444.             mIsAnimationInProgres = false;  
    445.             mRelativeViewNumber = 0;  
    446.             mInitialOffset = 0;  
    447.             mTargetOffset = 0;  
    448.             mTargetDistance = 0;  
    449.         }  
    450.    
    451.         public void prepareAnimation(int relativeViewNumber)  
    452.         {  
    453.             // If we are animating relative to a new view  
    454.             if (mRelativeViewNumber != relativeViewNumber)  
    455.             {  
    456.                 if (mIsAnimationInProgres == true)  
    457.                 {  
    458.                     // We only have three views so if requested again to animate in same direction we must snap   
    459.                     int newDirection = (relativeViewNumber == getPrevViewNumber(mRelativeViewNumber)) ? 1 : -1;  
    460.                     int animDirection = (mTargetDistance < 0) ? 1 : -1;   
    461.   
    462.                     // If animation in same direction  
    463.                     if (animDirection == newDirection)  
    464.                     {  
    465.                         // Ran out of time to animate so snap to the target offset  
    466.                         mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);  
    467.                         mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);  
    468.                         mViews[2].setOffset(mTargetOffset, 0, mRelativeViewNumber);   
    469.                     }  
    470.                 }  
    471.       
    472.                 // Set relative view number for animation  
    473.                 mRelativeViewNumber = relativeViewNumber;  
    474.             }  
    475.   
    476.             // Note: In this implementation the targetOffset will always be zero  
    477.             // as we are centering the view; but we include the calculations of  
    478.             // targetOffset and targetDistance for use in future implementations  
    479.   
    480.             mInitialOffset = mViews[mRelativeViewNumber].getCurrentOffset();  
    481.             mTargetOffset = getViewOffset(mRelativeViewNumber, mRelativeViewNumber);  
    482.             mTargetDistance = mTargetOffset - mInitialOffset;  
    483.   
    484.             // Configure base animation properties  
    485.             this.setDuration(mAnimationDuration);  
    486.             this.setInterpolator(mDecelerateInterpolater);  
    487.   
    488.             // Start/continued animation  
    489.             mIsAnimationInProgres = true;  
    490.         }  
    491.   
    492.         @Override  
    493.         protected void applyTransformation(float interpolatedTime, Transformation transformation)  
    494.         {  
    495.             // Ensure interpolatedTime does not over-shoot then calculate new offset  
    496.             interpolatedTime = (interpolatedTime > 1.0f) ? 1.0f : interpolatedTime;  
    497.             int offset = mInitialOffset + (int) (mTargetDistance * interpolatedTime);  
    498.   
    499.             for (int viewNumber = 0; viewNumber < 3; viewNumber++)  
    500.             {  
    501.                 // Only need to animate the visible views as the other view will always be off-screen  
    502.                 if ((mTargetDistance > 0 && viewNumber != getNextViewNumber(mRelativeViewNumber)) ||  
    503.                     (mTargetDistance < 0 && viewNumber != getPrevViewNumber(mRelativeViewNumber)))  
    504.                 {  
    505.                     mViews[viewNumber].setOffset(offset, 0, mRelativeViewNumber);  
    506.                 }  
    507.             }  
    508.         }  
    509.   
    510.         @Override  
    511.         public boolean getTransformation(long currentTime, Transformation outTransformation)  
    512.         {  
    513.             if (super.getTransformation(currentTime, outTransformation) == false)  
    514.             {  
    515.                 // Perform final adjustment to offsets to cleanup animation  
    516.                 mViews[0].setOffset(mTargetOffset, 0, mRelativeViewNumber);  
    517.                 mViews[1].setOffset(mTargetOffset, 0, mRelativeViewNumber);  
    518.                 mViews[2].setOffset(mTargetOffset, 0, mRelativeViewNumber);  
    519.   
    520.                 // Reached the animation target  
    521.                 mIsAnimationInProgres = false;  
    522.   
    523.                 return false;  
    524.             }  
    525.    
    526.             // Cancel if the screen touched  
    527.             if (mIsTouched || mIsDragging)  
    528.             {  
    529.                 // Note that at this point we still consider ourselves to be animating  
    530.                 // because we have not yet reached the target offset; its just that the  
    531.                 // user has temporarily interrupted the animation with a touch gesture  
    532.   
    533.                 return false;  
    534.             }  
    535.   
    536.             return true;  
    537.         }  
    538.     }  
    539.       
    540.     private class InterruptGestureDetectorListener extends GestureDetector.SimpleOnGestureListener {  
    541.           
    542.           
    543.         @Override  
    544.         public boolean onDown(MotionEvent e)  
    545.         {  
    546.             // Stop animation  
    547.             mIsTouched = true;  
    548.   
    549.             // Reset fling state  
    550.             mFlingDirection = 0;  
    551.             return false;  
    552.         }  
    553.           
    554.           
    555.         //返回true由FlingGallery的onTouchEvent(MotionEvent)来处理触摸消息,返回false则先由子view(listview)来处理触摸消息  
    556.         @Override  
    557.         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)  
    558.         {  
    559.             if (e2.getAction() == MotionEvent.ACTION_MOVE)  
    560.             {  
    561.   
    562.                 float maxVelocity = mGalleryWidth / (mAnimationDuration / 1000.0f);  
    563.                 long timestampDelta = System.currentTimeMillis() - mScrollTimestamp;  
    564.                 float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);   
    565.                 float currentScrollDelta = e1.getX() - e2.getX();  
    566.   
    567.                 if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1;  
    568.                 if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta;  
    569.                 if(Math.abs(currentScrollDelta) > mDetectScrollX){//如果当前x方向滚动的距离大于50,则由FlingGallery的onTouchEvent(MotionEvent)来处理触摸消息  
    570.                     mGestureDetectorListener.setDownEvent(e1);//重新设置mGestureDetectorListener的down消息  
    571.                     return true;  
    572.                 }  
    573.             }  
    574.   
    575.             return false;//不打断,交给子view来处理触摸消息  
    576.         }  
    577.     }  
    578.   
    579.     private class FlingGestureDetectorListener extends GestureDetector.SimpleOnGestureListener  
    580.     {  
    581.         private MotionEvent mDownEvent;  
    582.           
    583.           
    584.         public void setDownEvent(MotionEvent downEvent) {//复原丢失的Down触摸消息  
    585.             mDownEvent = downEvent;  
    586.         }  
    587.           
    588.   
    589.         @Override  
    590.         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)  
    591.         {  
    592.             if (e2.getAction() == MotionEvent.ACTION_MOVE)  
    593.             {  
    594.                 if (mIsDragging == false)  
    595.                 {  
    596.                     // Stop animation  
    597.                     mIsTouched = true;  
    598.        
    599.                     // Reconfigure scroll  
    600.                     mIsDragging = true;  
    601.                     mFlingDirection = 0;  
    602.                     mScrollTimestamp = System.currentTimeMillis();  
    603.                     mCurrentOffset = mViews[mCurrentViewNumber].getCurrentOffset();  
    604.                 }  
    605.   
    606.                 float maxVelocity = mGalleryWidth / (mAnimationDuration / 1000.0f);  
    607.                 long timestampDelta = System.currentTimeMillis() - mScrollTimestamp;  
    608.                 float maxScrollDelta = maxVelocity * (timestampDelta / 1000.0f);   
    609.   
    610.                 float currentScrollDelta = mDownEvent.getX() - e2.getX();  
    611.   
    612.                 if (currentScrollDelta < maxScrollDelta * -1) currentScrollDelta = maxScrollDelta * -1;  
    613.                 if (currentScrollDelta > maxScrollDelta) currentScrollDelta = maxScrollDelta;  
    614.                 int scrollOffset = Math.round(mCurrentOffset + currentScrollDelta);  
    615.   
    616.                 // We can't scroll more than the width of our own frame layout  
    617.                 if (scrollOffset >= mGalleryWidth) scrollOffset = mGalleryWidth;  
    618.                 if (scrollOffset <= mGalleryWidth * -1) scrollOffset = mGalleryWidth * -1;  
    619.                   
    620.                 mViews[0].setOffset(scrollOffset, 0, mCurrentViewNumber);  
    621.                 mViews[1].setOffset(scrollOffset, 0, mCurrentViewNumber);  
    622.                 mViews[2].setOffset(scrollOffset, 0, mCurrentViewNumber);  
    623.             }  
    624.   
    625.             return false;  
    626.         }  
    627.   
    628.         @Override  
    629.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)  
    630.         {  
    631.             if (Math.abs(mDownEvent.getY() - e2.getY()) <= swipe_max_off_path)  
    632.             {  
    633.                 if (e2.getX() - mDownEvent.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)  
    634.                 {  
    635.                     movePrevious();  
    636.                 }  
    637.   
    638.                 if(mDownEvent.getX() - e2.getX() > swipe_min_distance && Math.abs(velocityX) > swipe_threshold_veloicty)  
    639.                 {  
    640.                     moveNext();  
    641.                 }  
    642.             }  
    643.   
    644.             return false;  
    645.         }  
    646.   
    647.         @Override  
    648.         public void onLongPress(MotionEvent e)  
    649.         {  
    650.             // Finalise scrolling  
    651.             mFlingDirection = 0;  
    652.             processGesture();  
    653.         }  
    654.   
    655.         @Override  
    656.         public void onShowPress(MotionEvent e)  
    657.         {  
    658.         }  
    659.   
    660.         @Override  
    661.         public boolean onSingleTapUp(MotionEvent e)  
    662.         {  
    663.             // Reset fling state  
    664.             mFlingDirection = 0;  
    665.             return false;  
    666.         }  
    667.     }  
    668. }  
    FlingGalleryActivity.java
    [java] view plaincopy
    1. package com.droidful.flinggallery;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5.   
    6. import android.content.Context;  
    7. import android.graphics.Color;  
    8. import android.util.Log;  
    9. import android.view.Gravity;  
    10. import android.view.MotionEvent;  
    11. import android.view.View;  
    12. import android.view.ViewGroup;  
    13. import android.view.View.OnClickListener;  
    14. import android.widget.ArrayAdapter;  
    15. import android.widget.Button;  
    16. import android.widget.CheckBox;  
    17. import android.widget.EditText;  
    18. import android.widget.LinearLayout;  
    19. import android.widget.ListView;  
    20. import android.widget.TableLayout;  
    21. import android.widget.TextView;  
    22.   
    23. public class FlingGalleryActivity extends Activity  
    24. {  
    25.   
    26.     private final String[] mLabelArray = {"View1""View2""View3"};  
    27.   
    28.     private String[] mAStrings = {  
    29.             "Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi",  
    30.             "Acorn""Adelost""Affidelice au Chablis""Afuega'l Pitu""Airag""Airedale",  
    31.             "Aisy Cendre""Allgauer Emmentaler""Alverca""Ambert""American Cheese",  
    32.             "Ami du Chambertin""Anejo Enchilado""Anneau du Vic-Bilh""Anthoriro""Appenzell",  
    33.             "Aragon""Ardi Gasna""Ardrahan""Armenian String""Aromes au Gene de Marc",  
    34.             "Asadero""Asiago""Aubisque Pyrenees""Autun""Avaxtskyr"};  
    35.     private String[] mBStrings = {"Baby Swiss",  
    36.             "Babybel""Baguette Laonnaise""Bakers""Baladi""Balaton""Bandal""Banon",  
    37.             "Barry's Bay Cheddar""Basing""Basket Cheese""Bath Cheese""Bavarian Bergkase",  
    38.             "Baylough""Beaufort""Beauvoorde""Beenleigh Blue""Beer Cheese""Bel Paese",  
    39.             "Bergader""Bergere Bleue""Berkswell""Beyaz Peynir""Bierkase""Bishop Kennedy",  
    40.             "Blarney""Bleu d'Auvergne""Bleu de Gex""Bleu de Laqueuille",  
    41.             "Bleu de Septmoncel""Bleu Des Causses""Blue""Blue Castello""Blue Rathgore",  
    42.             "Blue Vein (Australian)""Blue Vein Cheeses""Bocconcini""Bocconcini (Australian)",  
    43.             "Boeren Leidenkaas""Bonchester""Bosworth""Bougon""Boule Du Roves",  
    44.             "Boulette d'Avesnes""Boursault""Boursin""Bouyssou""Bra""Braudostur",  
    45.             "Breakfast Cheese""Brebis du Lavort""Brebis du Lochois""Brebis du Puyfaucon",  
    46.             "Bresse Bleu""Brick""Brie""Brie de Meaux""Brie de Melun""Brillat-Savarin",  
    47.             "Brin""Brin d' Amour""Brin d'Amour""Brinza (Burduf Brinza)",  
    48.             "Briquette de Brebis""Briquette du Forez""Broccio""Broccio Demi-Affine",  
    49.             "Brousse du Rove""Bruder Basil""Brusselae Kaas (Fromage de Bruxelles)""Bryndza",  
    50.             "Buchette d'Anjou""Buffalo""Burgos""Butte""Butterkase""Button (Innes)",  
    51.             "Buxton Blue", };  
    52.     private String[] mCStrings = {"Cabecou""Caboc""Cabrales""Cachaille""Caciocavallo""Caciotta",  
    53.             "Caerphilly""Cairnsmore""Calenzana""Cambazola""Camembert de Normandie",  
    54.             "Canadian Cheddar""Canestrato""Cantal""Caprice des Dieux""Capricorn Goat",  
    55.             "Capriole Banon""Carre de l'Est""Casciotta di Urbino""Cashel Blue""Castellano",  
    56.             "Castelleno""Castelmagno""Castelo Branco""Castigliano""Cathelain",  
    57.             "Celtic Promise""Cendre d'Olivet""Cerney""Chabichou""Chabichou du Poitou",  
    58.             "Chabis de Gatine""Chaource""Charolais""Chaumes""Cheddar",  
    59.             "Cheddar Clothbound""Cheshire""Chevres""Chevrotin des Aravis""Chontaleno",  
    60.             "Civray""Coeur de Camembert au Calvados""Coeur de Chevre""Colby""Cold Pack",  
    61.             "Comte""Coolea""Cooleney""Coquetdale""Corleggy""Cornish Pepper",  
    62.             "Cotherstone""Cotija""Cottage Cheese""Cottage Cheese (Australian)",  
    63.             "Cougar Gold""Coulommiers""Coverdale""Crayeux de Roncq""Cream Cheese",  
    64.             "Cream Havarti""Crema Agria""Crema Mexicana""Creme Fraiche""Crescenza",  
    65.             "Croghan""Crottin de Chavignol""Crottin du Chavignol""Crowdie""Crowley",  
    66.             "Cuajada""Curd""Cure Nantais""Curworthy""Cwmtawe Pecorino",  
    67.             "Cypress Grove Chevre"};  
    68.       
    69.     private String[][] strings = {mAStrings,mBStrings,mCStrings};  
    70.       
    71.     private FlingGallery mGallery;  
    72.     private CheckBox mCheckBox;  
    73.   
    74.   
    75.   
    76.     public void onCreate(Bundle savedInstanceState)  
    77.     {  
    78.         super.onCreate(savedInstanceState);  
    79.   
    80.         mGallery = new FlingGallery(this);  
    81.         mGallery.setPaddingWidth(5);  
    82.         mGallery.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, mLabelArray)  
    83.         {  
    84.             @Override  
    85.             public View getView(int position, View convertView, ViewGroup parent)  
    86.             {  
    87.                 ListView lv = new ListView(getApplicationContext());  
    88.                 lv.setAdapter(new ArrayAdapter<String>(getApplicationContext(),  
    89.                         android.R.layout.simple_list_item_1, strings[position]));  
    90.                 return lv;//返回position位置的listview  
    91.             }  
    92.         });  
    93.   
    94.         LinearLayout layout = new LinearLayout(getApplicationContext());  
    95.         layout.setOrientation(LinearLayout.VERTICAL);  
    96.   
    97.         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(  
    98.                 LinearLayout.LayoutParams.MATCH_PARENT,  
    99.                 LinearLayout.LayoutParams.MATCH_PARENT);  
    100.   
    101.         layoutParams.setMargins(10101010);  
    102.         layoutParams.weight = 1.0f;  
    103.     
    104.         layout.addView(mGallery, layoutParams);  
    105.           
    106.         mCheckBox = new CheckBox(getApplicationContext());  
    107.         mCheckBox.setText("Gallery is Circular");  
    108.         mCheckBox.setPadding(5010010);  
    109.         mCheckBox.setTextSize(30);  
    110.         mCheckBox.setChecked(false);  
    111.         mGallery.setIsGalleryCircular(mCheckBox.isChecked());  
    112.         mCheckBox.setOnClickListener(new OnClickListener()  
    113.         {  
    114.             @Override  
    115.             public void onClick(View view)  
    116.             {  
    117.                 mGallery.setIsGalleryCircular(mCheckBox.isChecked());  
    118.             }  
    119.         });  
    120.   
    121.         layout.addView(mCheckBox, new LinearLayout.LayoutParams(  
    122.                 LinearLayout.LayoutParams.MATCH_PARENT,  
    123.                 LinearLayout.LayoutParams.WRAP_CONTENT));  
    124.           
    125.         setContentView(layout);  
    126.     }     
    127.       
    128.       
    129.       
    130.       
    131. }  

    代码解析:

    这里不详细解析分屏效果的实现,只说明ViewGroup对触摸消息的分发规则。

    FlingGallery继承FrameLayout,FrameLayout的父类是ViewGroup,因此FlingGallery是ViewGroup的派生类。

    默认规则下,当触摸消息(MotionEvent)到达ViewGroup时,ViewGroup会先把消息发给子View的onTouchEvent(MotionEvent)方法进行处理,如果子View消耗了消息,那么ViewGroup的onTouchEvent(MotionEvent)将不会接收到消息。

    这个例子我们重载了ViewGroup的onInterceptTouchEvent (MotionEvent ev)方法,如果方法返回true则表示交由ViewGroup的onTouchEvent(MotionEvent)来处理触摸消息,false则按默认规则交由子view处理。我们在此方法中检测是否横向滚动,如果是横向滚动,则返回true,消息传递给ViewGroup的onTouchEvent(MotionEvent),如果不是横向滑动则有子view处理消息。

    希望觉得有用的同学都顶一下,写博客不容易!


  • 相关阅读:
    数据库-第六章 关系数据理论-6.2.1 函数依赖
    数据库-第六章 关系数据理论-6.1 问题的提出
    编译原理-第四章 语法分析-4.4 自顶向下的语法分析
    计算机组成及系统结构-第五章 指令系统
    编译原理-第四章 语法分析-4.3 设计文法
    Java数据结构之堆和优先队列
    进程与线程杂谈
    Java的多态浅谈
    Java的自定义注解使用实例
    elasticsearch6.6.2在Centos6.9的安装
  • 原文地址:https://www.cnblogs.com/walccott/p/4957609.html
Copyright © 2011-2022 走看看