自定义四个方向上的SlidingDrawer(抽屉效果)

如果使用SlidingDrawer可以实现从右边和从底部拉出来的抽屉效果

使用如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <SlidingDrawer    
  2.         android:id="@+id/slidingdrawer_rignt"    
  3.         android:layout_width="fill_parent"    
  4.         android:layout_height="fill_parent"    
  5.         android:content="@+id/SettingContent_rignt"    
  6.         android:handle="@+id/sliding_switch_rignt"    
  7.         android:orientation="horizontal" >    
  8.     
  9.         <ImageButton    
  10.             android:id="@id/sliding_switch_rignt"    
  11.             android:layout_width="50dip"    
  12.             android:layout_height="44dip"    
  13.             android:src="@drawable/ic_launcher" />    
  14.     
  15.         <ImageView    
  16.             android:id="@id/SettingContent_rignt"    
  17.             android:layout_width="wrap_content"    
  18.             android:layout_height="wrap_content"    
  19.             android:gravity="center"  
  20.             android:src="@drawable/pic"/>    
  21.     </SlidingDrawer>   

orientation可以改变方向,但是不能实现从顶部和从左边滑出的效果,而且SlidingDrawer在使用的时候提示 过时


下面是使用自定义控件来实现从四个方向可以抽出的效果,拷贝即可以用:效果图如下:





关键代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.xy.slidingdrawer;  
  2.   
  3. import android.content.Context;    
  4. import android.content.res.TypedArray;    
  5. import android.graphics.Bitmap;    
  6. import android.graphics.Canvas;    
  7. import android.graphics.Rect;    
  8. import android.os.Handler;    
  9. import android.os.Message;    
  10. import android.os.SystemClock;    
  11. import android.util.AttributeSet;    
  12. import android.util.Log;    
  13. import android.view.MotionEvent;    
  14. import android.view.SoundEffectConstants;    
  15. import android.view.VelocityTracker;    
  16. import android.view.View;    
  17. import android.view.ViewGroup;    
  18. import android.view.accessibility.AccessibilityEvent;    
  19.     
  20.     
  21. public class MultiDirectionSlidingDrawer extends ViewGroup {    
  22.         
  23.     public static final int             ORIENTATION_RTL     = 0;    
  24.     public static final int             ORIENTATION_BTT     = 1;    
  25.     public static final int             ORIENTATION_LTR     = 2;    
  26.     public static final int             ORIENTATION_TTB     = 3;    
  27.         
  28.     private static final int            TAP_THRESHOLD                   = 6;    
  29.     private static final float          MAXIMUM_TAP_VELOCITY            = 100.0f;    
  30.     private static final float          MAXIMUM_MINOR_VELOCITY      = 150.0f;    
  31.     private static final float          MAXIMUM_MAJOR_VELOCITY      = 200.0f;    
  32.     private static final float          MAXIMUM_ACCELERATION            = 2000.0f;    
  33.     private static final int            VELOCITY_UNITS                  = 1000;    
  34.     private static final int            MSG_ANIMATE                     = 1000;    
  35.     private static final int            ANIMATION_FRAME_DURATION    = 1000 / 60;    
  36.         
  37.     private static final int            EXPANDED_FULL_OPEN          = -10001;    
  38.     private static final int            COLLAPSED_FULL_CLOSED       = -10002;    
  39.         
  40.     private final int                       mHandleId;    
  41.     private final int                       mContentId;    
  42.         
  43.     private View                            mHandle;    
  44.     private View                            mContent;    
  45.         
  46.     private final Rect                  mFrame                          = new Rect();    
  47.     private final Rect                  mInvalidate                     = new Rect();    
  48.     private boolean                     mTracking;    
  49.     private boolean                     mLocked;    
  50.         
  51.     private VelocityTracker             mVelocityTracker;    
  52.         
  53.     private boolean                     mInvert;    
  54.     private boolean                     mVertical;    
  55.     private boolean                     mExpanded;    
  56.     private int                             mBottomOffset;    
  57.     private int                             mTopOffset;    
  58.     private int                             mHandleHeight;    
  59.     private int                             mHandleWidth;    
  60.         
  61.     private OnDrawerOpenListener        mOnDrawerOpenListener;    
  62.     private OnDrawerCloseListener       mOnDrawerCloseListener;    
  63.     private OnDrawerScrollListener  mOnDrawerScrollListener;    
  64.         
  65.     private final Handler               mHandler                            = new SlidingHandler();    
  66.     private float                           mAnimatedAcceleration;    
  67.     private float                           mAnimatedVelocity;    
  68.     private float                           mAnimationPosition;    
  69.     private long                            mAnimationLastTime;    
  70.     private long                            mCurrentAnimationTime;    
  71.     private int                             mTouchDelta;    
  72.     private boolean                     mAnimating;    
  73.     private boolean                     mAllowSingleTap;    
  74.     private boolean                     mAnimateOnClick;    
  75.         
  76.     private final int                       mTapThreshold;    
  77.     private final int                       mMaximumTapVelocity;    
  78.     private int                             mMaximumMinorVelocity;    
  79.     private int                             mMaximumMajorVelocity;    
  80.     private int                             mMaximumAcceleration;    
  81.     private final int                       mVelocityUnits;    
  82.         
  83.     /**  
  84.      * Callback invoked when the drawer is opened.  
  85.      */    
  86.     public static interface OnDrawerOpenListener {    
  87.             
  88.         /**  
  89.          * Invoked when the drawer becomes fully open.  
  90.          */    
  91.         public void onDrawerOpened();    
  92.     }    
  93.         
  94.     /**  
  95.      * Callback invoked when the drawer is closed.  
  96.      */    
  97.     public static interface OnDrawerCloseListener {    
  98.             
  99.         /**  
  100.          * Invoked when the drawer becomes fully closed.  
  101.          */    
  102.         public void onDrawerClosed();    
  103.     }    
  104.         
  105.     /**  
  106.      * Callback invoked when the drawer is scrolled.  
  107.      */    
  108.     public static interface OnDrawerScrollListener {    
  109.             
  110.         /**  
  111.          * Invoked when the user starts dragging/flinging the drawer's handle.  
  112.          */    
  113.         public void onScrollStarted();    
  114.             
  115.         /**  
  116.          * Invoked when the user stops dragging/flinging the drawer's handle.  
  117.          */    
  118.         public void onScrollEnded();    
  119.     }    
  120.         
  121.     /**  
  122.      * Creates a new SlidingDrawer from a specified set of attributes defined in  
  123.      * XML.  
  124.      *   
  125.      * @param context  
  126.      *           The application's environment.  
  127.      * @param attrs  
  128.      *           The attributes defined in XML.  
  129.      */    
  130.     public MultiDirectionSlidingDrawer( Context context, AttributeSet attrs )    
  131.     {    
  132.         this( context, attrs, 0 );    
  133.     }    
  134.         
  135.     /**  
  136.      * Creates a new SlidingDrawer from a specified set of attributes defined in  
  137.      * XML.  
  138.      *   
  139.      * @param context  
  140.      *           The application's environment.  
  141.      * @param attrs  
  142.      *           The attributes defined in XML.  
  143.      * @param defStyle  
  144.      *           The style to apply to this widget.  
  145.      */    
  146.     public MultiDirectionSlidingDrawer( Context context, AttributeSet attrs, int defStyle )    
  147.     {    
  148.         super( context, attrs, defStyle );    
  149.         TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.MultiDirectionSlidingDrawer, defStyle, 0 );    
  150.             
  151.         int orientation = a.getInt( R.styleable.MultiDirectionSlidingDrawer_direction, ORIENTATION_BTT );    
  152.         mVertical = ( orientation == ORIENTATION_BTT || orientation == ORIENTATION_TTB );    
  153.         mBottomOffset = (int)a.getDimension( R.styleable.MultiDirectionSlidingDrawer_bottomOffset, 0.0f );    
  154.         mTopOffset = (int)a.getDimension( R.styleable.MultiDirectionSlidingDrawer_topOffset, 0.0f );    
  155.         mAllowSingleTap = a.getBoolean( R.styleable.MultiDirectionSlidingDrawer_allowSingleTap, true );    
  156.         mAnimateOnClick = a.getBoolean( R.styleable.MultiDirectionSlidingDrawer_animateOnClick, true );    
  157.         mInvert = ( orientation == ORIENTATION_TTB || orientation == ORIENTATION_LTR );    
  158.             
  159.         int handleId = a.getResourceId( R.styleable.MultiDirectionSlidingDrawer_handle, 0 );    
  160.         if ( handleId == 0 ) { throw new IllegalArgumentException( "The handle attribute is required and must refer "    
  161.                 + "to a valid child." ); }    
  162.             
  163.         int contentId = a.getResourceId( R.styleable.MultiDirectionSlidingDrawer_content, 0 );    
  164.         if ( contentId == 0 ) { throw new IllegalArgumentException( "The content attribute is required and must refer "    
  165.                 + "to a valid child." ); }    
  166.             
  167.         if ( handleId == contentId ) { throw new IllegalArgumentException( "The content and handle attributes must refer "    
  168.                 + "to different children." ); }    
  169.         mHandleId = handleId;    
  170.         mContentId = contentId;    
  171.             
  172.         final float density = getResources().getDisplayMetrics().density;    
  173.         mTapThreshold = (int)( TAP_THRESHOLD * density + 0.5f );    
  174.         mMaximumTapVelocity = (int)( MAXIMUM_TAP_VELOCITY * density + 0.5f );    
  175.         mMaximumMinorVelocity = (int)( MAXIMUM_MINOR_VELOCITY * density + 0.5f );    
  176.         mMaximumMajorVelocity = (int)( MAXIMUM_MAJOR_VELOCITY * density + 0.5f );    
  177.         mMaximumAcceleration = (int)( MAXIMUM_ACCELERATION * density + 0.5f );    
  178.         mVelocityUnits = (int)( VELOCITY_UNITS * density + 0.5f );    
  179.             
  180.         if( mInvert ) {    
  181.             mMaximumAcceleration = -mMaximumAcceleration;    
  182.             mMaximumMajorVelocity = -mMaximumMajorVelocity;    
  183.             mMaximumMinorVelocity = -mMaximumMinorVelocity;    
  184.         }    
  185.             
  186.         a.recycle();    
  187.         setAlwaysDrawnWithCacheEnabled( false );    
  188.     }    
  189.         
  190.     @Override    
  191.     protected void onFinishInflate()    
  192.     {    
  193.         mHandle = findViewById( mHandleId );    
  194.         if ( mHandle == null ) { throw new IllegalArgumentException( "The handle attribute is must refer to an" + " existing child." ); }    
  195.         mHandle.setOnClickListener( new DrawerToggler() );    
  196.             
  197.         mContent = findViewById( mContentId );    
  198.         if ( mContent == null ) { throw new IllegalArgumentException( "The content attribute is must refer to an"    
  199.                 + " existing child." ); }    
  200.         mContent.setVisibility( View.GONE );    
  201.     }    
  202.         
  203.     @Override    
  204.     protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )    
  205.     {    
  206.         int widthSpecMode = MeasureSpec.getMode( widthMeasureSpec );    
  207.         int widthSpecSize = MeasureSpec.getSize( widthMeasureSpec );    
  208.             
  209.         int heightSpecMode = MeasureSpec.getMode( heightMeasureSpec );    
  210.         int heightSpecSize = MeasureSpec.getSize( heightMeasureSpec );    
  211.             
  212.         if ( widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED ) { throw new RuntimeException(    
  213.                 "SlidingDrawer cannot have UNSPECIFIED dimensions" ); }    
  214.             
  215.         final View handle = mHandle;    
  216.         measureChild( handle, widthMeasureSpec, heightMeasureSpec );    
  217.             
  218.         if ( mVertical ) {    
  219.             int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset;    
  220.             mContent.measure( MeasureSpec.makeMeasureSpec( widthSpecSize, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY ) );    
  221.         } else {    
  222.             int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset;    
  223.             mContent.measure( MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( heightSpecSize, MeasureSpec.EXACTLY ) );    
  224.         }    
  225.             
  226.         setMeasuredDimension( widthSpecSize, heightSpecSize );    
  227.     }    
  228.         
  229.     @Override    
  230.     protected void dispatchDraw( Canvas canvas )    
  231.     {    
  232.         final long drawingTime = getDrawingTime();    
  233.         final View handle = mHandle;    
  234.         final boolean isVertical = mVertical;    
  235.             
  236.         drawChild( canvas, handle, drawingTime );    
  237.             
  238.         if ( mTracking || mAnimating ) {    
  239.             final Bitmap cache = mContent.getDrawingCache();    
  240.             if ( cache != null ) {    
  241.                 if ( isVertical ) {    
  242.                     if( mInvert ) {    
  243.                         canvas.drawBitmap( cache, 0, handle.getTop() - (getBottom() - getTop()) + mHandleHeight, null );    
  244.                     } else {    
  245.                         canvas.drawBitmap( cache, 0, handle.getBottom(), null );    
  246.                     }    
  247.                 } else {    
  248.                     canvas.drawBitmap( cache, mInvert ? handle.getLeft() - cache.getWidth() : handle.getRight(), 0null );    
  249.                 }    
  250.             } else {    
  251.                 canvas.save();    
  252.                 if( mInvert ) {    
  253.                     canvas.translate( isVertical ? 0 : handle.getLeft() - mTopOffset - mContent.getMeasuredWidth(), isVertical ? handle.getTop() - mTopOffset - mContent.getMeasuredHeight() : 0 );    
  254.                 } else {    
  255.                     canvas.translate( isVertical ? 0 : handle.getLeft() - mTopOffset, isVertical ? handle.getTop() - mTopOffset : 0 );    
  256.                 }    
  257.                 drawChild( canvas, mContent, drawingTime );    
  258.                 canvas.restore();    
  259.             }    
  260.             invalidate();    
  261.         } else if ( mExpanded ) {    
  262.             drawChild( canvas, mContent, drawingTime );    
  263.         }    
  264.     }    
  265.         
  266.     public static final String  LOG_TAG = "Sliding";    
  267.         
  268.     @Override    
  269.     protected void onLayout( boolean changed, int l, int t, int r, int b )    
  270.     {    
  271.         if ( mTracking ) { return; }    
  272.             
  273.         final int width = r - l;    
  274.         final int height = b - t;    
  275.             
  276.         final View handle = mHandle;    
  277.             
  278.         int handleWidth = handle.getMeasuredWidth();    
  279.         int handleHeight = handle.getMeasuredHeight();    
  280.             
  281.         Log.d( LOG_TAG, "handleHeight: " + handleHeight );    
  282.             
  283.         int handleLeft;    
  284.         int handleTop;    
  285.             
  286.         final View content = mContent;    
  287.             
  288.         if ( mVertical ) {    
  289.             handleLeft = ( width - handleWidth ) / 2;    
  290.             if ( mInvert ) {    
  291.                 Log.d( LOG_TAG, "content.layout(1)" );    
  292.                 handleTop = mExpanded ? height - mBottomOffset - handleHeight : mTopOffset;    
  293.                 content.layout( 0, mTopOffset, content.getMeasuredWidth(), mTopOffset + content.getMeasuredHeight() );    
  294.             } else {    
  295.                 handleTop = mExpanded ? mTopOffset : height - handleHeight + mBottomOffset;    
  296.                 content.layout( 0, mTopOffset + handleHeight, content.getMeasuredWidth(), mTopOffset + handleHeight + content.getMeasuredHeight() );    
  297.             }    
  298.         } else {    
  299.             handleTop = ( height - handleHeight ) / 2;    
  300.             if( mInvert ) {    
  301.                 handleLeft = mExpanded ? width - mBottomOffset - handleWidth : mTopOffset;    
  302.                 content.layout( mTopOffset, 0, mTopOffset + content.getMeasuredWidth(), content.getMeasuredHeight() );    
  303.             } else {    
  304.                 handleLeft = mExpanded ? mTopOffset : width - handleWidth + mBottomOffset;    
  305.                 content.layout( mTopOffset + handleWidth, 0, mTopOffset + handleWidth + content.getMeasuredWidth(), content.getMeasuredHeight() );    
  306.             }    
  307.         }    
  308.             
  309.         handle.layout( handleLeft, handleTop, handleLeft + handleWidth, handleTop + handleHeight );    
  310.         mHandleHeight = handle.getHeight();    
  311.         mHandleWidth = handle.getWidth();    
  312.     }    
  313.         
  314.     @Override    
  315.     public boolean onInterceptTouchEvent( MotionEvent event )    
  316.     {    
  317.         if ( mLocked ) { return false; }    
  318.             
  319.         final int action = event.getAction();    
  320.             
  321.         float x = event.getX();    
  322.         float y = event.getY();    
  323.             
  324.         final Rect frame = mFrame;    
  325.         final View handle = mHandle;    
  326.             
  327.         handle.getHitRect( frame );    
  328.         if ( !mTracking && !frame.contains( (int)x, (int)y ) ) { return false; }    
  329.             
  330.         if ( action == MotionEvent.ACTION_DOWN ) {    
  331.             mTracking = true;    
  332.                 
  333.             handle.setPressed( true );    
  334.             // Must be called before prepareTracking()    
  335.             prepareContent();    
  336.                 
  337.             // Must be called after prepareContent()    
  338.             if ( mOnDrawerScrollListener != null ) {    
  339.                 mOnDrawerScrollListener.onScrollStarted();    
  340.             }    
  341.                 
  342.             if ( mVertical ) {    
  343.                 final int top = mHandle.getTop();    
  344.                 mTouchDelta = (int)y - top;    
  345.                 prepareTracking( top );    
  346.             } else {    
  347.                 final int left = mHandle.getLeft();    
  348.                 mTouchDelta = (int)x - left;    
  349.                 prepareTracking( left );    
  350.             }    
  351.             mVelocityTracker.addMovement( event );    
  352.         }    
  353.             
  354.         return true;    
  355.     }    
  356.         
  357.     @Override    
  358.     public boolean onTouchEvent( MotionEvent event )    
  359.     {    
  360.         if ( mLocked ) { return true; }    
  361.             
  362.         if ( mTracking ) {    
  363.             mVelocityTracker.addMovement( event );    
  364.             final int action = event.getAction();    
  365.             switch ( action ) {    
  366.                 case MotionEvent.ACTION_MOVE:    
  367.                     moveHandle( (int)( mVertical ? event.getY() : event.getX() ) - mTouchDelta );    
  368.                     break;    
  369.                 case MotionEvent.ACTION_UP:    
  370.                 case MotionEvent.ACTION_CANCEL: {    
  371.                     final VelocityTracker velocityTracker = mVelocityTracker;    
  372.                     velocityTracker.computeCurrentVelocity( mVelocityUnits );    
  373.                         
  374.                     float yVelocity = velocityTracker.getYVelocity();    
  375.                     float xVelocity = velocityTracker.getXVelocity();    
  376.                     boolean negative;    
  377.                         
  378.                     final boolean vertical = mVertical;    
  379.                     if ( vertical ) {    
  380.                         negative = yVelocity < 0;    
  381.                         if ( xVelocity < 0 ) {    
  382.                             xVelocity = -xVelocity;    
  383.                         }    
  384.                         // fix by Maciej Ciemięga.    
  385.                         if ( (!mInvert && xVelocity > mMaximumMinorVelocity) || (mInvert && xVelocity < mMaximumMinorVelocity) ) {    
  386.                             xVelocity = mMaximumMinorVelocity;    
  387.                         }    
  388.                     } else {    
  389.                         negative = xVelocity < 0;    
  390.                         if ( yVelocity < 0 ) {    
  391.                             yVelocity = -yVelocity;    
  392.                         }    
  393.                         // fix by Maciej Ciemięga.    
  394.                         if ( (!mInvert && yVelocity > mMaximumMinorVelocity) || (mInvert && yVelocity < mMaximumMinorVelocity) ) {    
  395.                             yVelocity = mMaximumMinorVelocity;    
  396.                         }    
  397.                     }    
  398.                         
  399.                     float velocity = (float)Math.hypot( xVelocity, yVelocity );    
  400.                     if ( negative ) {    
  401.                         velocity = -velocity;    
  402.                     }    
  403.                         
  404.                     final int handleTop = mHandle.getTop();    
  405.                     final int handleLeft = mHandle.getLeft();    
  406.                     final int handleBottom = mHandle.getBottom();    
  407.                     final int handleRight = mHandle.getRight();    
  408.                         
  409.                     if ( Math.abs( velocity ) < mMaximumTapVelocity ) {    
  410.                         boolean c1;    
  411.                         boolean c2;    
  412.                         boolean c3;    
  413.                         boolean c4;    
  414.                             
  415.                         if( mInvert ) {    
  416.                             c1 = ( mExpanded && (getBottom() - handleBottom ) < mTapThreshold + mBottomOffset );    
  417.                             c2 = ( !mExpanded && handleTop < mTopOffset + mHandleHeight - mTapThreshold );    
  418.                             c3 = ( mExpanded && (getRight() - handleRight ) < mTapThreshold + mBottomOffset );    
  419.                             c4 = ( !mExpanded && handleLeft > mTopOffset + mHandleWidth + mTapThreshold );    
  420.                         } else {    
  421.                             c1 = ( mExpanded && handleTop < mTapThreshold + mTopOffset );    
  422.                             c2 = ( !mExpanded && handleTop > mBottomOffset + getBottom() - getTop() - mHandleHeight - mTapThreshold );    
  423.                             c3 = ( mExpanded && handleLeft < mTapThreshold + mTopOffset );    
  424.                             c4 = ( !mExpanded && handleLeft > mBottomOffset + getRight() - getLeft() - mHandleWidth - mTapThreshold );    
  425.                         }    
  426.                             
  427.                         Log.d( LOG_TAG, "ACTION_UP: " + "c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 + ", c4: " + c4 );    
  428.                             
  429.                         if ( vertical ? c1 || c2 : c3 || c4 ) {    
  430.                                 
  431.                             if ( mAllowSingleTap ) {    
  432.                                 playSoundEffect( SoundEffectConstants.CLICK );    
  433.                                     
  434.                                 if ( mExpanded ) {    
  435.                                     animateClose( vertical ? handleTop : handleLeft );    
  436.                                 } else {    
  437.                                     animateOpen( vertical ? handleTop : handleLeft );    
  438.                                 }    
  439.                             } else {    
  440.                                 performFling( vertical ? handleTop : handleLeft, velocity, false );    
  441.                             }    
  442.                         } else {    
  443.                             performFling( vertical ? handleTop : handleLeft, velocity, false );    
  444.                         }    
  445.                     } else {    
  446.                         performFling( vertical ? handleTop : handleLeft, velocity, false );    
  447.                     }    
  448.                 }    
  449.                     break;    
  450.             }    
  451.         }    
  452.             
  453.         return mTracking || mAnimating || super.onTouchEvent( event );    
  454.     }    
  455.         
  456.     private void animateClose( int position )    
  457.     {    
  458.         prepareTracking( position );    
  459.         performFling( position, mMaximumAcceleration, true );    
  460.     }    
  461.         
  462.     private void animateOpen( int position )    
  463.     {    
  464.         prepareTracking( position );    
  465.         performFling( position, -mMaximumAcceleration, true );    
  466.     }    
  467.         
  468.     private void performFling( int position, float velocity, boolean always )    
  469.     {    
  470.         mAnimationPosition = position;    
  471.         mAnimatedVelocity = velocity;    
  472.             
  473.         boolean c1;    
  474.         boolean c2;    
  475.         boolean c3;    
  476.             
  477.         if ( mExpanded )     
  478.         {    
  479.             int bottom = mVertical ? getBottom() : getRight();    
  480.             int handleHeight = mVertical ? mHandleHeight : mHandleWidth;    
  481.                 
  482.             Log.d( LOG_TAG, "position: " + position + ", velocity: " + velocity + ", mMaximumMajorVelocity: " + mMaximumMajorVelocity );    
  483.             c1 = mInvert ? velocity < mMaximumMajorVelocity : velocity > mMaximumMajorVelocity;    
  484.             c2 = mInvert ? ( bottom - (position + handleHeight) ) + mBottomOffset > handleHeight : position > mTopOffset + ( mVertical ? mHandleHeight : mHandleWidth );    
  485.             c3 = mInvert ? velocity < -mMaximumMajorVelocity : velocity > -mMaximumMajorVelocity;    
  486.             Log.d( LOG_TAG, "EXPANDED. c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 );    
  487.             if ( always || ( c1 || ( c2 && c3 ) ) ) {    
  488.                 // We are expanded, So animate to CLOSE!    
  489.                 mAnimatedAcceleration = mMaximumAcceleration;    
  490.                 if( mInvert )    
  491.                 {    
  492.                     if ( velocity > 0 ) {    
  493.                         mAnimatedVelocity = 0;    
  494.                     }    
  495.                 } else {    
  496.                     if ( velocity < 0 ) {    
  497.                         mAnimatedVelocity = 0;    
  498.                     }    
  499.                 }    
  500.             } else {    
  501.                 // We are expanded, but they didn't move sufficiently to cause    
  502.                 // us to retract. Animate back to the expanded position. so animate BACK to expanded!    
  503.                 mAnimatedAcceleration = -mMaximumAcceleration;    
  504.                     
  505.                 if( mInvert ) {    
  506.                     if ( velocity < 0 ) {    
  507.                         mAnimatedVelocity = 0;    
  508.                     }    
  509.                 } else {    
  510.                     if ( velocity > 0 ) {    
  511.                         mAnimatedVelocity = 0;    
  512.                     }    
  513.                 }    
  514.             }    
  515.         } else {    
  516.                 
  517.             // WE'RE COLLAPSED    
  518.                 
  519.             c1 = mInvert ? velocity < mMaximumMajorVelocity : velocity > mMaximumMajorVelocity;    
  520.             c2 = mInvert ? ( position < ( mVertical ? getHeight() : getWidth() ) / 2 ) : ( position > ( mVertical ? getHeight() : getWidth() ) / 2 );    
  521.             c3 = mInvert ? velocity < -mMaximumMajorVelocity : velocity > -mMaximumMajorVelocity;    
  522.                 
  523.             Log.d( LOG_TAG, "COLLAPSED. position: " + position + ", velocity: " + velocity + ", mMaximumMajorVelocity: " + mMaximumMajorVelocity );    
  524.             Log.d( LOG_TAG, "COLLAPSED. always: " + always + ", c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 );    
  525.                 
  526.             if ( !always && ( c1 || ( c2 && c3 ) ) ) {    
  527.                 mAnimatedAcceleration = mMaximumAcceleration;    
  528.                     
  529.                 if( mInvert ) {    
  530.                     if ( velocity > 0 ) {    
  531.                         mAnimatedVelocity = 0;    
  532.                     }    
  533.                 } else {    
  534.                     if ( velocity < 0 ) {    
  535.                         mAnimatedVelocity = 0;    
  536.                     }    
  537.                 }    
  538.             } else {    
  539.                 mAnimatedAcceleration = -mMaximumAcceleration;    
  540.                     
  541.                 if( mInvert ) {    
  542.                     if ( velocity < 0 ) {    
  543.                         mAnimatedVelocity = 0;    
  544.                     }    
  545.                 } else {    
  546.                     if ( velocity > 0 ) {    
  547.                         mAnimatedVelocity = 0;    
  548.                     }    
  549.                 }    
  550.             }    
  551.         }    
  552.             
  553.         long now = SystemClock.uptimeMillis();    
  554.         mAnimationLastTime = now;    
  555.         mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;    
  556.         mAnimating = true;    
  557.         mHandler.removeMessages( MSG_ANIMATE );    
  558.         mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );    
  559.         stopTracking();    
  560.     }    
  561.         
  562.     private void prepareTracking( int position )    
  563.     {    
  564.         mTracking = true;    
  565.         mVelocityTracker = VelocityTracker.obtain();    
  566.         boolean opening = !mExpanded;    
  567.             
  568.         if ( opening ) {    
  569.             mAnimatedAcceleration = mMaximumAcceleration;    
  570.             mAnimatedVelocity = mMaximumMajorVelocity;    
  571.             if( mInvert )    
  572.                 mAnimationPosition = mTopOffset;    
  573.             else    
  574.                 mAnimationPosition = mBottomOffset + ( mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth );    
  575.             moveHandle( (int)mAnimationPosition );    
  576.             mAnimating = true;    
  577.             mHandler.removeMessages( MSG_ANIMATE );    
  578.             long now = SystemClock.uptimeMillis();    
  579.             mAnimationLastTime = now;    
  580.             mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;    
  581.             mAnimating = true;    
  582.         } else {    
  583.             if ( mAnimating ) {    
  584.                 mAnimating = false;    
  585.                 mHandler.removeMessages( MSG_ANIMATE );    
  586.             }    
  587.             moveHandle( position );    
  588.         }    
  589.     }    
  590.         
  591.     private void moveHandle( int position )    
  592.     {    
  593.         final View handle = mHandle;    
  594.             
  595.         if ( mVertical ) {    
  596.             if ( position == EXPANDED_FULL_OPEN ) {    
  597.                 if( mInvert )    
  598.                     handle.offsetTopAndBottom( mBottomOffset + getBottom() - getTop() - mHandleHeight );    
  599.                 else    
  600.                     handle.offsetTopAndBottom( mTopOffset - handle.getTop() );    
  601.                 invalidate();    
  602.             } else if ( position == COLLAPSED_FULL_CLOSED ) {    
  603.                 if( mInvert ) {    
  604.                     handle.offsetTopAndBottom( mTopOffset - handle.getTop() );    
  605.                 } else {    
  606.                     handle.offsetTopAndBottom( mBottomOffset + getBottom() - getTop() - mHandleHeight - handle.getTop() );    
  607.                 }    
  608.                 invalidate();    
  609.             } else     
  610.             {    
  611.                 final int top = handle.getTop();    
  612.                 int deltaY = position - top;    
  613.                 if ( position < mTopOffset ) {    
  614.                     deltaY = mTopOffset - top;    
  615.                 } else if ( deltaY > mBottomOffset + getBottom() - getTop() - mHandleHeight - top ) {    
  616.                     deltaY = mBottomOffset + getBottom() - getTop() - mHandleHeight - top;    
  617.                 }    
  618.                     
  619.                 handle.offsetTopAndBottom( deltaY );    
  620.                     
  621.                 final Rect frame = mFrame;    
  622.                 final Rect region = mInvalidate;    
  623.                     
  624.                 handle.getHitRect( frame );    
  625.                 region.set( frame );    
  626.                     
  627.                 region.union( frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY );    
  628.                 region.union( 0, frame.bottom - deltaY, getWidth(), frame.bottom - deltaY + mContent.getHeight() );    
  629.                     
  630.                 invalidate( region );    
  631.             }    
  632.         } else {    
  633.             if ( position == EXPANDED_FULL_OPEN ) {    
  634.                 if( mInvert )    
  635.                     handle.offsetLeftAndRight( mBottomOffset + getRight() - getLeft() - mHandleWidth );    
  636.                 else    
  637.                     handle.offsetLeftAndRight( mTopOffset - handle.getLeft() );    
  638.                 invalidate();    
  639.             } else if ( position == COLLAPSED_FULL_CLOSED ) {    
  640.                 if( mInvert )    
  641.                     handle.offsetLeftAndRight( mTopOffset - handle.getLeft() );    
  642.                 else    
  643.                     handle.offsetLeftAndRight( mBottomOffset + getRight() - getLeft() - mHandleWidth - handle.getLeft() );    
  644.                 invalidate();    
  645.             } else {    
  646.                 final int left = handle.getLeft();    
  647.                 int deltaX = position - left;    
  648.                 if ( position < mTopOffset ) {    
  649.                     deltaX = mTopOffset - left;    
  650.                 } else if ( deltaX > mBottomOffset + getRight() - getLeft() - mHandleWidth - left ) {    
  651.                     deltaX = mBottomOffset + getRight() - getLeft() - mHandleWidth - left;    
  652.                 }    
  653.                 handle.offsetLeftAndRight( deltaX );    
  654.                     
  655.                 final Rect frame = mFrame;    
  656.                 final Rect region = mInvalidate;    
  657.                     
  658.                 handle.getHitRect( frame );    
  659.                 region.set( frame );    
  660.                     
  661.                 region.union( frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom );    
  662.                 region.union( frame.right - deltaX, 0, frame.right - deltaX + mContent.getWidth(), getHeight() );    
  663.                     
  664.                 invalidate( region );    
  665.             }    
  666.         }    
  667.     }    
  668.         
  669.     private void prepareContent()    
  670.     {    
  671.         if ( mAnimating ) { return; }    
  672.             
  673.         // Something changed in the content, we need to honor the layout request    
  674.         // before creating the cached bitmap    
  675.         final View content = mContent;    
  676.         if ( content.isLayoutRequested() ) {    
  677.                 
  678.             if ( mVertical ) {    
  679.                 final int handleHeight = mHandleHeight;    
  680.                 int height = getBottom() - getTop() - handleHeight - mTopOffset;    
  681.                 content.measure( MeasureSpec.makeMeasureSpec( getRight() - getLeft(), MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY ) );    
  682.                     
  683.                 Log.d( LOG_TAG, "content.layout(2)" );    
  684.                     
  685.                 if ( mInvert )     
  686.                     content.layout( 0, mTopOffset, content.getMeasuredWidth(), mTopOffset + content.getMeasuredHeight() );    
  687.                 else     
  688.                     content.layout( 0, mTopOffset + handleHeight, content.getMeasuredWidth(), mTopOffset + handleHeight + content.getMeasuredHeight() );    
  689.                 
  690.             } else {    
  691.                     
  692.                 final int handleWidth = mHandle.getWidth();    
  693.                 int width = getRight() - getLeft() - handleWidth - mTopOffset;    
  694.                 content.measure( MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( getBottom() - getTop(), MeasureSpec.EXACTLY ) );    
  695.                     
  696.                 if( mInvert )    
  697.                     content.layout( mTopOffset, 0, mTopOffset + content.getMeasuredWidth(), content.getMeasuredHeight() );    
  698.                 else    
  699.                     content.layout( handleWidth + mTopOffset, 0, mTopOffset + handleWidth + content.getMeasuredWidth(), content.getMeasuredHeight() );    
  700.             }    
  701.         }    
  702.         // Try only once... we should really loop but it's not a big deal    
  703.         // if the draw was cancelled, it will only be temporary anyway    
  704.         content.getViewTreeObserver().dispatchOnPreDraw();    
  705.         content.buildDrawingCache();    
  706.             
  707.         content.setVisibility( View.GONE );    
  708.     }    
  709.         
  710.     private void stopTracking()    
  711.     {    
  712.         mHandle.setPressed( false );    
  713.         mTracking = false;    
  714.             
  715.         if ( mOnDrawerScrollListener != null ) {    
  716.             mOnDrawerScrollListener.onScrollEnded();    
  717.         }    
  718.             
  719.         if ( mVelocityTracker != null ) {    
  720.             mVelocityTracker.recycle();    
  721.             mVelocityTracker = null;    
  722.         }    
  723.     }    
  724.         
  725.     private void doAnimation()    
  726.     {    
  727.         if ( mAnimating ) {    
  728.             incrementAnimation();    
  729.                 
  730.             if( mInvert )    
  731.             {    
  732.                 if ( mAnimationPosition < mTopOffset ) {    
  733.                     mAnimating = false;    
  734.                     closeDrawer();    
  735.                 } else if ( mAnimationPosition >= mTopOffset + ( mVertical ? getHeight() : getWidth() ) - 1 ) {    
  736.                     mAnimating = false;    
  737.                     openDrawer();    
  738.                 } else {    
  739.                     moveHandle( (int)mAnimationPosition );    
  740.                     mCurrentAnimationTime += ANIMATION_FRAME_DURATION;    
  741.                     mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );    
  742.                 }                   
  743.             } else {    
  744.                 if ( mAnimationPosition >= mBottomOffset + ( mVertical ? getHeight() : getWidth() ) - 1 ) {    
  745.                     mAnimating = false;    
  746.                     closeDrawer();    
  747.                 } else if ( mAnimationPosition < mTopOffset ) {    
  748.                     mAnimating = false;    
  749.                     openDrawer();    
  750.                 } else {    
  751.                     moveHandle( (int)mAnimationPosition );    
  752.                     mCurrentAnimationTime += ANIMATION_FRAME_DURATION;    
  753.                     mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );    
  754.                 }    
  755.             }    
  756.         }    
  757.     }    
  758.         
  759.     private void incrementAnimation()    
  760.     {    
  761.         long now = SystemClock.uptimeMillis();    
  762.         float t = ( now - mAnimationLastTime ) / 1000.0f; // ms -> s    
  763.         final float position = mAnimationPosition;    
  764.         final float v = mAnimatedVelocity; // px/s    
  765.         final float a = mInvert ? mAnimatedAcceleration : mAnimatedAcceleration; // px/s/s    
  766.         mAnimationPosition = position + ( v * t ) + ( 0.5f * a * t * t ); // px    
  767.         mAnimatedVelocity = v + ( a * t ); // px/s    
  768.         mAnimationLastTime = now; // ms    
  769.     }    
  770.         
  771.     /**  
  772.      * Toggles the drawer open and close. Takes effect immediately.  
  773.      *   
  774.      * @see #open()  
  775.      * @see #close()  
  776.      * @see #animateClose()  
  777.      * @see #animateOpen()  
  778.      * @see #animateToggle()  
  779.      */    
  780.     public void toggle()    
  781.     {    
  782.         if ( !mExpanded ) {    
  783.             openDrawer();    
  784.         } else {    
  785.             closeDrawer();    
  786.         }    
  787.         invalidate();    
  788.         requestLayout();    
  789.     }    
  790.         
  791.     /**  
  792.      * Toggles the drawer open and close with an animation.  
  793.      *   
  794.      * @see #open()  
  795.      * @see #close()  
  796.      * @see #animateClose()  
  797.      * @see #animateOpen()  
  798.      * @see #toggle()  
  799.      */    
  800.     public void animateToggle()    
  801.     {    
  802.         if ( !mExpanded ) {    
  803.             animateOpen();    
  804.         } else {    
  805.             animateClose();    
  806.         }    
  807.     }    
  808.         
  809.     /**  
  810.      * Opens the drawer immediately.  
  811.      *   
  812.      * @see #toggle()  
  813.      * @see #close()  
  814.      * @see #animateOpen()  
  815.      */    
  816.     public void open()    
  817.     {    
  818.         openDrawer();    
  819.         invalidate();    
  820.         requestLayout();    
  821.             
  822.         sendAccessibilityEvent( AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED );    
  823.     }    
  824.         
  825.     /**  
  826.      * Closes the drawer immediately.  
  827.      *   
  828.      * @see #toggle()  
  829.      * @see #open()  
  830.      * @see #animateClose()  
  831.      */    
  832.     public void close()    
  833.     {    
  834.         closeDrawer();    
  835.         invalidate();    
  836.         requestLayout();    
  837.     }    
  838.         
  839.     /**  
  840.      * Closes the drawer with an animation.  
  841.      *   
  842.      * @see #close()  
  843.      * @see #open()  
  844.      * @see #animateOpen()  
  845.      * @see #animateToggle()  
  846.      * @see #toggle()  
  847.      */    
  848.     public void animateClose()    
  849.     {    
  850.         prepareContent();    
  851.         final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;    
  852.         if ( scrollListener != null ) {    
  853.             scrollListener.onScrollStarted();    
  854.         }    
  855.         animateClose( mVertical ? mHandle.getTop() : mHandle.getLeft() );    
  856.             
  857.         if ( scrollListener != null ) {    
  858.             scrollListener.onScrollEnded();    
  859.         }    
  860.     }    
  861.         
  862.     /**  
  863.      * Opens the drawer with an animation.  
  864.      *   
  865.      * @see #close()  
  866.      * @see #open()  
  867.      * @see #animateClose()  
  868.      * @see #animateToggle()  
  869.      * @see #toggle()  
  870.      */    
  871.     public void animateOpen()    
  872.     {    
  873.         prepareContent();    
  874.         final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;    
  875.         if ( scrollListener != null ) {    
  876.             scrollListener.onScrollStarted();    
  877.         }    
  878.         animateOpen( mVertical ? mHandle.getTop() : mHandle.getLeft() );    
  879.             
  880.         sendAccessibilityEvent( AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED );    
  881.             
  882.         if ( scrollListener != null ) {    
  883.             scrollListener.onScrollEnded();    
  884.         }    
  885.     }    
  886.         
  887.     private void closeDrawer()    
  888.     {    
  889.         moveHandle( COLLAPSED_FULL_CLOSED );    
  890.         mContent.setVisibility( View.GONE );    
  891.         mContent.destroyDrawingCache();    
  892.             
  893.         if ( !mExpanded ) { return; }    
  894.             
  895.         mExpanded = false;    
  896.         if ( mOnDrawerCloseListener != null ) {    
  897.             mOnDrawerCloseListener.onDrawerClosed();    
  898.         }    
  899.     }    
  900.         
  901.     private void openDrawer()    
  902.     {    
  903.         moveHandle( EXPANDED_FULL_OPEN );    
  904.         mContent.setVisibility( View.VISIBLE );    
  905.             
  906.         if ( mExpanded ) { return; }    
  907.             
  908.         mExpanded = true;    
  909.             
  910.         if ( mOnDrawerOpenListener != null ) {    
  911.             mOnDrawerOpenListener.onDrawerOpened();    
  912.         }    
  913.     }    
  914.         
  915.     /**  
  916.      * Sets the listener that receives a notification when the drawer becomes  
  917.      * open.  
  918.      *   
  919.      * @param onDrawerOpenListener  
  920.      *           The listener to be notified when the drawer is opened.  
  921.      */    
  922.     public void setOnDrawerOpenListener( OnDrawerOpenListener onDrawerOpenListener )    
  923.     {    
  924.         mOnDrawerOpenListener = onDrawerOpenListener;    
  925.     }    
  926.         
  927.     /**  
  928.      * Sets the listener that receives a notification when the drawer becomes  
  929.      * close.  
  930.      *   
  931.      * @param onDrawerCloseListener  
  932.      *           The listener to be notified when the drawer is closed.  
  933.      */    
  934.     public void setOnDrawerCloseListener( OnDrawerCloseListener onDrawerCloseListener )    
  935.     {    
  936.         mOnDrawerCloseListener = onDrawerCloseListener;    
  937.     }    
  938.         
  939.     /**  
  940.      * Sets the listener that receives a notification when the drawer starts or  
  941.      * ends a scroll. A fling is considered as a scroll. A fling will also  
  942.      * trigger a drawer opened or drawer closed event.  
  943.      *   
  944.      * @param onDrawerScrollListener  
  945.      *           The listener to be notified when scrolling starts or stops.  
  946.      */    
  947.     public void setOnDrawerScrollListener( OnDrawerScrollListener onDrawerScrollListener )    
  948.     {    
  949.         mOnDrawerScrollListener = onDrawerScrollListener;    
  950.     }    
  951.         
  952.     /**  
  953.      * Returns the handle of the drawer.  
  954.      *   
  955.      * @return The View reprenseting the handle of the drawer, identified by the  
  956.      *         "handle" id in XML.  
  957.      */    
  958.     public View getHandle()    
  959.     {    
  960.         return mHandle;    
  961.     }    
  962.         
  963.     /**  
  964.      * Returns the content of the drawer.  
  965.      *   
  966.      * @return The View reprenseting the content of the drawer, identified by the  
  967.      *         "content" id in XML.  
  968.      */    
  969.     public View getContent()    
  970.     {    
  971.         return mContent;    
  972.     }    
  973.         
  974.     /**  
  975.      * Unlocks the SlidingDrawer so that touch events are processed.  
  976.      *   
  977.      * @see #lock()  
  978.      */    
  979.     public void unlock()    
  980.     {    
  981.         mLocked = false;    
  982.     }    
  983.         
  984.     /**  
  985.      * Locks the SlidingDrawer so that touch events are ignores.  
  986.      *   
  987.      * @see #unlock()  
  988.      */    
  989.     public void lock()    
  990.     {    
  991.         mLocked = true;    
  992.     }    
  993.         
  994.     /**  
  995.      * Indicates whether the drawer is currently fully opened.  
  996.      *   
  997.      * @return True if the drawer is opened, false otherwise.  
  998.      */    
  999.     public boolean isOpened()    
  1000.     {    
  1001.         return mExpanded;    
  1002.     }    
  1003.         
  1004.     /**  
  1005.      * Indicates whether the drawer is scrolling or flinging.  
  1006.      *   
  1007.      * @return True if the drawer is scroller or flinging, false otherwise.  
  1008.      */    
  1009.     public boolean isMoving()    
  1010.     {    
  1011.         return mTracking || mAnimating;    
  1012.     }    
  1013.         
  1014.     private class DrawerToggler implements OnClickListener {    
  1015.             
  1016.         public void onClick( View v )    
  1017.         {    
  1018.             if ( mLocked ) { return; }    
  1019.             // mAllowSingleTap isn't relevant here; you're *always*    
  1020.             // allowed to open/close the drawer by clicking with the    
  1021.             // trackball.    
  1022.                 
  1023.             if ( mAnimateOnClick ) {    
  1024.                 animateToggle();    
  1025.             } else {    
  1026.                 toggle();    
  1027.             }    
  1028.         }    
  1029.     }    
  1030.         
  1031.     private class SlidingHandler extends Handler {    
  1032.             
  1033.         public void handleMessage( Message m )    
  1034.         {    
  1035.             switch ( m.what ) {    
  1036.                 case MSG_ANIMATE:    
  1037.                     doAnimation();    
  1038.                     break;    
  1039.             }    
  1040.         }    
  1041.     }    
  1042. }    


csdn下载地址:点击打开链接

git下载地址:点击打开链接


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值