如果使用SlidingDrawer可以实现从右边和从底部拉出来的抽屉效果
使用如下:
- <SlidingDrawer
- android:id="@+id/slidingdrawer_rignt"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:content="@+id/SettingContent_rignt"
- android:handle="@+id/sliding_switch_rignt"
- android:orientation="horizontal" >
- <ImageButton
- android:id="@id/sliding_switch_rignt"
- android:layout_width="50dip"
- android:layout_height="44dip"
- android:src="@drawable/ic_launcher" />
- <ImageView
- android:id="@id/SettingContent_rignt"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:src="@drawable/pic"/>
- </SlidingDrawer>
orientation可以改变方向,但是不能实现从顶部和从左边滑出的效果,而且SlidingDrawer在使用的时候提示 过时
下面是使用自定义控件来实现从四个方向可以抽出的效果,拷贝即可以用:效果图如下:
关键代码如下:
- package com.xy.slidingdrawer;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Rect;
- import android.os.Handler;
- import android.os.Message;
- import android.os.SystemClock;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.SoundEffectConstants;
- import android.view.VelocityTracker;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.accessibility.AccessibilityEvent;
- public class MultiDirectionSlidingDrawer extends ViewGroup {
- public static final int ORIENTATION_RTL = 0;
- public static final int ORIENTATION_BTT = 1;
- public static final int ORIENTATION_LTR = 2;
- public static final int ORIENTATION_TTB = 3;
- private static final int TAP_THRESHOLD = 6;
- private static final float MAXIMUM_TAP_VELOCITY = 100.0f;
- private static final float MAXIMUM_MINOR_VELOCITY = 150.0f;
- private static final float MAXIMUM_MAJOR_VELOCITY = 200.0f;
- private static final float MAXIMUM_ACCELERATION = 2000.0f;
- private static final int VELOCITY_UNITS = 1000;
- private static final int MSG_ANIMATE = 1000;
- private static final int ANIMATION_FRAME_DURATION = 1000 / 60;
- private static final int EXPANDED_FULL_OPEN = -10001;
- private static final int COLLAPSED_FULL_CLOSED = -10002;
- private final int mHandleId;
- private final int mContentId;
- private View mHandle;
- private View mContent;
- private final Rect mFrame = new Rect();
- private final Rect mInvalidate = new Rect();
- private boolean mTracking;
- private boolean mLocked;
- private VelocityTracker mVelocityTracker;
- private boolean mInvert;
- private boolean mVertical;
- private boolean mExpanded;
- private int mBottomOffset;
- private int mTopOffset;
- private int mHandleHeight;
- private int mHandleWidth;
- private OnDrawerOpenListener mOnDrawerOpenListener;
- private OnDrawerCloseListener mOnDrawerCloseListener;
- private OnDrawerScrollListener mOnDrawerScrollListener;
- private final Handler mHandler = new SlidingHandler();
- private float mAnimatedAcceleration;
- private float mAnimatedVelocity;
- private float mAnimationPosition;
- private long mAnimationLastTime;
- private long mCurrentAnimationTime;
- private int mTouchDelta;
- private boolean mAnimating;
- private boolean mAllowSingleTap;
- private boolean mAnimateOnClick;
- private final int mTapThreshold;
- private final int mMaximumTapVelocity;
- private int mMaximumMinorVelocity;
- private int mMaximumMajorVelocity;
- private int mMaximumAcceleration;
- private final int mVelocityUnits;
- /**
- * Callback invoked when the drawer is opened.
- */
- public static interface OnDrawerOpenListener {
- /**
- * Invoked when the drawer becomes fully open.
- */
- public void onDrawerOpened();
- }
- /**
- * Callback invoked when the drawer is closed.
- */
- public static interface OnDrawerCloseListener {
- /**
- * Invoked when the drawer becomes fully closed.
- */
- public void onDrawerClosed();
- }
- /**
- * Callback invoked when the drawer is scrolled.
- */
- public static interface OnDrawerScrollListener {
- /**
- * Invoked when the user starts dragging/flinging the drawer's handle.
- */
- public void onScrollStarted();
- /**
- * Invoked when the user stops dragging/flinging the drawer's handle.
- */
- public void onScrollEnded();
- }
- /**
- * Creates a new SlidingDrawer from a specified set of attributes defined in
- * XML.
- *
- * @param context
- * The application's environment.
- * @param attrs
- * The attributes defined in XML.
- */
- public MultiDirectionSlidingDrawer( Context context, AttributeSet attrs )
- {
- this( context, attrs, 0 );
- }
- /**
- * Creates a new SlidingDrawer from a specified set of attributes defined in
- * XML.
- *
- * @param context
- * The application's environment.
- * @param attrs
- * The attributes defined in XML.
- * @param defStyle
- * The style to apply to this widget.
- */
- public MultiDirectionSlidingDrawer( Context context, AttributeSet attrs, int defStyle )
- {
- super( context, attrs, defStyle );
- TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.MultiDirectionSlidingDrawer, defStyle, 0 );
- int orientation = a.getInt( R.styleable.MultiDirectionSlidingDrawer_direction, ORIENTATION_BTT );
- mVertical = ( orientation == ORIENTATION_BTT || orientation == ORIENTATION_TTB );
- mBottomOffset = (int)a.getDimension( R.styleable.MultiDirectionSlidingDrawer_bottomOffset, 0.0f );
- mTopOffset = (int)a.getDimension( R.styleable.MultiDirectionSlidingDrawer_topOffset, 0.0f );
- mAllowSingleTap = a.getBoolean( R.styleable.MultiDirectionSlidingDrawer_allowSingleTap, true );
- mAnimateOnClick = a.getBoolean( R.styleable.MultiDirectionSlidingDrawer_animateOnClick, true );
- mInvert = ( orientation == ORIENTATION_TTB || orientation == ORIENTATION_LTR );
- int handleId = a.getResourceId( R.styleable.MultiDirectionSlidingDrawer_handle, 0 );
- if ( handleId == 0 ) { throw new IllegalArgumentException( "The handle attribute is required and must refer "
- + "to a valid child." ); }
- int contentId = a.getResourceId( R.styleable.MultiDirectionSlidingDrawer_content, 0 );
- if ( contentId == 0 ) { throw new IllegalArgumentException( "The content attribute is required and must refer "
- + "to a valid child." ); }
- if ( handleId == contentId ) { throw new IllegalArgumentException( "The content and handle attributes must refer "
- + "to different children." ); }
- mHandleId = handleId;
- mContentId = contentId;
- final float density = getResources().getDisplayMetrics().density;
- mTapThreshold = (int)( TAP_THRESHOLD * density + 0.5f );
- mMaximumTapVelocity = (int)( MAXIMUM_TAP_VELOCITY * density + 0.5f );
- mMaximumMinorVelocity = (int)( MAXIMUM_MINOR_VELOCITY * density + 0.5f );
- mMaximumMajorVelocity = (int)( MAXIMUM_MAJOR_VELOCITY * density + 0.5f );
- mMaximumAcceleration = (int)( MAXIMUM_ACCELERATION * density + 0.5f );
- mVelocityUnits = (int)( VELOCITY_UNITS * density + 0.5f );
- if( mInvert ) {
- mMaximumAcceleration = -mMaximumAcceleration;
- mMaximumMajorVelocity = -mMaximumMajorVelocity;
- mMaximumMinorVelocity = -mMaximumMinorVelocity;
- }
- a.recycle();
- setAlwaysDrawnWithCacheEnabled( false );
- }
- @Override
- protected void onFinishInflate()
- {
- mHandle = findViewById( mHandleId );
- if ( mHandle == null ) { throw new IllegalArgumentException( "The handle attribute is must refer to an" + " existing child." ); }
- mHandle.setOnClickListener( new DrawerToggler() );
- mContent = findViewById( mContentId );
- if ( mContent == null ) { throw new IllegalArgumentException( "The content attribute is must refer to an"
- + " existing child." ); }
- mContent.setVisibility( View.GONE );
- }
- @Override
- protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
- {
- int widthSpecMode = MeasureSpec.getMode( widthMeasureSpec );
- int widthSpecSize = MeasureSpec.getSize( widthMeasureSpec );
- int heightSpecMode = MeasureSpec.getMode( heightMeasureSpec );
- int heightSpecSize = MeasureSpec.getSize( heightMeasureSpec );
- if ( widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED ) { throw new RuntimeException(
- "SlidingDrawer cannot have UNSPECIFIED dimensions" ); }
- final View handle = mHandle;
- measureChild( handle, widthMeasureSpec, heightMeasureSpec );
- if ( mVertical ) {
- int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset;
- mContent.measure( MeasureSpec.makeMeasureSpec( widthSpecSize, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY ) );
- } else {
- int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset;
- mContent.measure( MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( heightSpecSize, MeasureSpec.EXACTLY ) );
- }
- setMeasuredDimension( widthSpecSize, heightSpecSize );
- }
- @Override
- protected void dispatchDraw( Canvas canvas )
- {
- final long drawingTime = getDrawingTime();
- final View handle = mHandle;
- final boolean isVertical = mVertical;
- drawChild( canvas, handle, drawingTime );
- if ( mTracking || mAnimating ) {
- final Bitmap cache = mContent.getDrawingCache();
- if ( cache != null ) {
- if ( isVertical ) {
- if( mInvert ) {
- canvas.drawBitmap( cache, 0, handle.getTop() - (getBottom() - getTop()) + mHandleHeight, null );
- } else {
- canvas.drawBitmap( cache, 0, handle.getBottom(), null );
- }
- } else {
- canvas.drawBitmap( cache, mInvert ? handle.getLeft() - cache.getWidth() : handle.getRight(), 0, null );
- }
- } else {
- canvas.save();
- if( mInvert ) {
- canvas.translate( isVertical ? 0 : handle.getLeft() - mTopOffset - mContent.getMeasuredWidth(), isVertical ? handle.getTop() - mTopOffset - mContent.getMeasuredHeight() : 0 );
- } else {
- canvas.translate( isVertical ? 0 : handle.getLeft() - mTopOffset, isVertical ? handle.getTop() - mTopOffset : 0 );
- }
- drawChild( canvas, mContent, drawingTime );
- canvas.restore();
- }
- invalidate();
- } else if ( mExpanded ) {
- drawChild( canvas, mContent, drawingTime );
- }
- }
- public static final String LOG_TAG = "Sliding";
- @Override
- protected void onLayout( boolean changed, int l, int t, int r, int b )
- {
- if ( mTracking ) { return; }
- final int width = r - l;
- final int height = b - t;
- final View handle = mHandle;
- int handleWidth = handle.getMeasuredWidth();
- int handleHeight = handle.getMeasuredHeight();
- Log.d( LOG_TAG, "handleHeight: " + handleHeight );
- int handleLeft;
- int handleTop;
- final View content = mContent;
- if ( mVertical ) {
- handleLeft = ( width - handleWidth ) / 2;
- if ( mInvert ) {
- Log.d( LOG_TAG, "content.layout(1)" );
- handleTop = mExpanded ? height - mBottomOffset - handleHeight : mTopOffset;
- content.layout( 0, mTopOffset, content.getMeasuredWidth(), mTopOffset + content.getMeasuredHeight() );
- } else {
- handleTop = mExpanded ? mTopOffset : height - handleHeight + mBottomOffset;
- content.layout( 0, mTopOffset + handleHeight, content.getMeasuredWidth(), mTopOffset + handleHeight + content.getMeasuredHeight() );
- }
- } else {
- handleTop = ( height - handleHeight ) / 2;
- if( mInvert ) {
- handleLeft = mExpanded ? width - mBottomOffset - handleWidth : mTopOffset;
- content.layout( mTopOffset, 0, mTopOffset + content.getMeasuredWidth(), content.getMeasuredHeight() );
- } else {
- handleLeft = mExpanded ? mTopOffset : width - handleWidth + mBottomOffset;
- content.layout( mTopOffset + handleWidth, 0, mTopOffset + handleWidth + content.getMeasuredWidth(), content.getMeasuredHeight() );
- }
- }
- handle.layout( handleLeft, handleTop, handleLeft + handleWidth, handleTop + handleHeight );
- mHandleHeight = handle.getHeight();
- mHandleWidth = handle.getWidth();
- }
- @Override
- public boolean onInterceptTouchEvent( MotionEvent event )
- {
- if ( mLocked ) { return false; }
- final int action = event.getAction();
- float x = event.getX();
- float y = event.getY();
- final Rect frame = mFrame;
- final View handle = mHandle;
- handle.getHitRect( frame );
- if ( !mTracking && !frame.contains( (int)x, (int)y ) ) { return false; }
- if ( action == MotionEvent.ACTION_DOWN ) {
- mTracking = true;
- handle.setPressed( true );
- // Must be called before prepareTracking()
- prepareContent();
- // Must be called after prepareContent()
- if ( mOnDrawerScrollListener != null ) {
- mOnDrawerScrollListener.onScrollStarted();
- }
- if ( mVertical ) {
- final int top = mHandle.getTop();
- mTouchDelta = (int)y - top;
- prepareTracking( top );
- } else {
- final int left = mHandle.getLeft();
- mTouchDelta = (int)x - left;
- prepareTracking( left );
- }
- mVelocityTracker.addMovement( event );
- }
- return true;
- }
- @Override
- public boolean onTouchEvent( MotionEvent event )
- {
- if ( mLocked ) { return true; }
- if ( mTracking ) {
- mVelocityTracker.addMovement( event );
- final int action = event.getAction();
- switch ( action ) {
- case MotionEvent.ACTION_MOVE:
- moveHandle( (int)( mVertical ? event.getY() : event.getX() ) - mTouchDelta );
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL: {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity( mVelocityUnits );
- float yVelocity = velocityTracker.getYVelocity();
- float xVelocity = velocityTracker.getXVelocity();
- boolean negative;
- final boolean vertical = mVertical;
- if ( vertical ) {
- negative = yVelocity < 0;
- if ( xVelocity < 0 ) {
- xVelocity = -xVelocity;
- }
- // fix by Maciej Ciemięga.
- if ( (!mInvert && xVelocity > mMaximumMinorVelocity) || (mInvert && xVelocity < mMaximumMinorVelocity) ) {
- xVelocity = mMaximumMinorVelocity;
- }
- } else {
- negative = xVelocity < 0;
- if ( yVelocity < 0 ) {
- yVelocity = -yVelocity;
- }
- // fix by Maciej Ciemięga.
- if ( (!mInvert && yVelocity > mMaximumMinorVelocity) || (mInvert && yVelocity < mMaximumMinorVelocity) ) {
- yVelocity = mMaximumMinorVelocity;
- }
- }
- float velocity = (float)Math.hypot( xVelocity, yVelocity );
- if ( negative ) {
- velocity = -velocity;
- }
- final int handleTop = mHandle.getTop();
- final int handleLeft = mHandle.getLeft();
- final int handleBottom = mHandle.getBottom();
- final int handleRight = mHandle.getRight();
- if ( Math.abs( velocity ) < mMaximumTapVelocity ) {
- boolean c1;
- boolean c2;
- boolean c3;
- boolean c4;
- if( mInvert ) {
- c1 = ( mExpanded && (getBottom() - handleBottom ) < mTapThreshold + mBottomOffset );
- c2 = ( !mExpanded && handleTop < mTopOffset + mHandleHeight - mTapThreshold );
- c3 = ( mExpanded && (getRight() - handleRight ) < mTapThreshold + mBottomOffset );
- c4 = ( !mExpanded && handleLeft > mTopOffset + mHandleWidth + mTapThreshold );
- } else {
- c1 = ( mExpanded && handleTop < mTapThreshold + mTopOffset );
- c2 = ( !mExpanded && handleTop > mBottomOffset + getBottom() - getTop() - mHandleHeight - mTapThreshold );
- c3 = ( mExpanded && handleLeft < mTapThreshold + mTopOffset );
- c4 = ( !mExpanded && handleLeft > mBottomOffset + getRight() - getLeft() - mHandleWidth - mTapThreshold );
- }
- Log.d( LOG_TAG, "ACTION_UP: " + "c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 + ", c4: " + c4 );
- if ( vertical ? c1 || c2 : c3 || c4 ) {
- if ( mAllowSingleTap ) {
- playSoundEffect( SoundEffectConstants.CLICK );
- if ( mExpanded ) {
- animateClose( vertical ? handleTop : handleLeft );
- } else {
- animateOpen( vertical ? handleTop : handleLeft );
- }
- } else {
- performFling( vertical ? handleTop : handleLeft, velocity, false );
- }
- } else {
- performFling( vertical ? handleTop : handleLeft, velocity, false );
- }
- } else {
- performFling( vertical ? handleTop : handleLeft, velocity, false );
- }
- }
- break;
- }
- }
- return mTracking || mAnimating || super.onTouchEvent( event );
- }
- private void animateClose( int position )
- {
- prepareTracking( position );
- performFling( position, mMaximumAcceleration, true );
- }
- private void animateOpen( int position )
- {
- prepareTracking( position );
- performFling( position, -mMaximumAcceleration, true );
- }
- private void performFling( int position, float velocity, boolean always )
- {
- mAnimationPosition = position;
- mAnimatedVelocity = velocity;
- boolean c1;
- boolean c2;
- boolean c3;
- if ( mExpanded )
- {
- int bottom = mVertical ? getBottom() : getRight();
- int handleHeight = mVertical ? mHandleHeight : mHandleWidth;
- Log.d( LOG_TAG, "position: " + position + ", velocity: " + velocity + ", mMaximumMajorVelocity: " + mMaximumMajorVelocity );
- c1 = mInvert ? velocity < mMaximumMajorVelocity : velocity > mMaximumMajorVelocity;
- c2 = mInvert ? ( bottom - (position + handleHeight) ) + mBottomOffset > handleHeight : position > mTopOffset + ( mVertical ? mHandleHeight : mHandleWidth );
- c3 = mInvert ? velocity < -mMaximumMajorVelocity : velocity > -mMaximumMajorVelocity;
- Log.d( LOG_TAG, "EXPANDED. c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 );
- if ( always || ( c1 || ( c2 && c3 ) ) ) {
- // We are expanded, So animate to CLOSE!
- mAnimatedAcceleration = mMaximumAcceleration;
- if( mInvert )
- {
- if ( velocity > 0 ) {
- mAnimatedVelocity = 0;
- }
- } else {
- if ( velocity < 0 ) {
- mAnimatedVelocity = 0;
- }
- }
- } else {
- // We are expanded, but they didn't move sufficiently to cause
- // us to retract. Animate back to the expanded position. so animate BACK to expanded!
- mAnimatedAcceleration = -mMaximumAcceleration;
- if( mInvert ) {
- if ( velocity < 0 ) {
- mAnimatedVelocity = 0;
- }
- } else {
- if ( velocity > 0 ) {
- mAnimatedVelocity = 0;
- }
- }
- }
- } else {
- // WE'RE COLLAPSED
- c1 = mInvert ? velocity < mMaximumMajorVelocity : velocity > mMaximumMajorVelocity;
- c2 = mInvert ? ( position < ( mVertical ? getHeight() : getWidth() ) / 2 ) : ( position > ( mVertical ? getHeight() : getWidth() ) / 2 );
- c3 = mInvert ? velocity < -mMaximumMajorVelocity : velocity > -mMaximumMajorVelocity;
- Log.d( LOG_TAG, "COLLAPSED. position: " + position + ", velocity: " + velocity + ", mMaximumMajorVelocity: " + mMaximumMajorVelocity );
- Log.d( LOG_TAG, "COLLAPSED. always: " + always + ", c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 );
- if ( !always && ( c1 || ( c2 && c3 ) ) ) {
- mAnimatedAcceleration = mMaximumAcceleration;
- if( mInvert ) {
- if ( velocity > 0 ) {
- mAnimatedVelocity = 0;
- }
- } else {
- if ( velocity < 0 ) {
- mAnimatedVelocity = 0;
- }
- }
- } else {
- mAnimatedAcceleration = -mMaximumAcceleration;
- if( mInvert ) {
- if ( velocity < 0 ) {
- mAnimatedVelocity = 0;
- }
- } else {
- if ( velocity > 0 ) {
- mAnimatedVelocity = 0;
- }
- }
- }
- }
- long now = SystemClock.uptimeMillis();
- mAnimationLastTime = now;
- mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
- mAnimating = true;
- mHandler.removeMessages( MSG_ANIMATE );
- mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );
- stopTracking();
- }
- private void prepareTracking( int position )
- {
- mTracking = true;
- mVelocityTracker = VelocityTracker.obtain();
- boolean opening = !mExpanded;
- if ( opening ) {
- mAnimatedAcceleration = mMaximumAcceleration;
- mAnimatedVelocity = mMaximumMajorVelocity;
- if( mInvert )
- mAnimationPosition = mTopOffset;
- else
- mAnimationPosition = mBottomOffset + ( mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth );
- moveHandle( (int)mAnimationPosition );
- mAnimating = true;
- mHandler.removeMessages( MSG_ANIMATE );
- long now = SystemClock.uptimeMillis();
- mAnimationLastTime = now;
- mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
- mAnimating = true;
- } else {
- if ( mAnimating ) {
- mAnimating = false;
- mHandler.removeMessages( MSG_ANIMATE );
- }
- moveHandle( position );
- }
- }
- private void moveHandle( int position )
- {
- final View handle = mHandle;
- if ( mVertical ) {
- if ( position == EXPANDED_FULL_OPEN ) {
- if( mInvert )
- handle.offsetTopAndBottom( mBottomOffset + getBottom() - getTop() - mHandleHeight );
- else
- handle.offsetTopAndBottom( mTopOffset - handle.getTop() );
- invalidate();
- } else if ( position == COLLAPSED_FULL_CLOSED ) {
- if( mInvert ) {
- handle.offsetTopAndBottom( mTopOffset - handle.getTop() );
- } else {
- handle.offsetTopAndBottom( mBottomOffset + getBottom() - getTop() - mHandleHeight - handle.getTop() );
- }
- invalidate();
- } else
- {
- final int top = handle.getTop();
- int deltaY = position - top;
- if ( position < mTopOffset ) {
- deltaY = mTopOffset - top;
- } else if ( deltaY > mBottomOffset + getBottom() - getTop() - mHandleHeight - top ) {
- deltaY = mBottomOffset + getBottom() - getTop() - mHandleHeight - top;
- }
- handle.offsetTopAndBottom( deltaY );
- final Rect frame = mFrame;
- final Rect region = mInvalidate;
- handle.getHitRect( frame );
- region.set( frame );
- region.union( frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY );
- region.union( 0, frame.bottom - deltaY, getWidth(), frame.bottom - deltaY + mContent.getHeight() );
- invalidate( region );
- }
- } else {
- if ( position == EXPANDED_FULL_OPEN ) {
- if( mInvert )
- handle.offsetLeftAndRight( mBottomOffset + getRight() - getLeft() - mHandleWidth );
- else
- handle.offsetLeftAndRight( mTopOffset - handle.getLeft() );
- invalidate();
- } else if ( position == COLLAPSED_FULL_CLOSED ) {
- if( mInvert )
- handle.offsetLeftAndRight( mTopOffset - handle.getLeft() );
- else
- handle.offsetLeftAndRight( mBottomOffset + getRight() - getLeft() - mHandleWidth - handle.getLeft() );
- invalidate();
- } else {
- final int left = handle.getLeft();
- int deltaX = position - left;
- if ( position < mTopOffset ) {
- deltaX = mTopOffset - left;
- } else if ( deltaX > mBottomOffset + getRight() - getLeft() - mHandleWidth - left ) {
- deltaX = mBottomOffset + getRight() - getLeft() - mHandleWidth - left;
- }
- handle.offsetLeftAndRight( deltaX );
- final Rect frame = mFrame;
- final Rect region = mInvalidate;
- handle.getHitRect( frame );
- region.set( frame );
- region.union( frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom );
- region.union( frame.right - deltaX, 0, frame.right - deltaX + mContent.getWidth(), getHeight() );
- invalidate( region );
- }
- }
- }
- private void prepareContent()
- {
- if ( mAnimating ) { return; }
- // Something changed in the content, we need to honor the layout request
- // before creating the cached bitmap
- final View content = mContent;
- if ( content.isLayoutRequested() ) {
- if ( mVertical ) {
- final int handleHeight = mHandleHeight;
- int height = getBottom() - getTop() - handleHeight - mTopOffset;
- content.measure( MeasureSpec.makeMeasureSpec( getRight() - getLeft(), MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY ) );
- Log.d( LOG_TAG, "content.layout(2)" );
- if ( mInvert )
- content.layout( 0, mTopOffset, content.getMeasuredWidth(), mTopOffset + content.getMeasuredHeight() );
- else
- content.layout( 0, mTopOffset + handleHeight, content.getMeasuredWidth(), mTopOffset + handleHeight + content.getMeasuredHeight() );
- } else {
- final int handleWidth = mHandle.getWidth();
- int width = getRight() - getLeft() - handleWidth - mTopOffset;
- content.measure( MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( getBottom() - getTop(), MeasureSpec.EXACTLY ) );
- if( mInvert )
- content.layout( mTopOffset, 0, mTopOffset + content.getMeasuredWidth(), content.getMeasuredHeight() );
- else
- content.layout( handleWidth + mTopOffset, 0, mTopOffset + handleWidth + content.getMeasuredWidth(), content.getMeasuredHeight() );
- }
- }
- // Try only once... we should really loop but it's not a big deal
- // if the draw was cancelled, it will only be temporary anyway
- content.getViewTreeObserver().dispatchOnPreDraw();
- content.buildDrawingCache();
- content.setVisibility( View.GONE );
- }
- private void stopTracking()
- {
- mHandle.setPressed( false );
- mTracking = false;
- if ( mOnDrawerScrollListener != null ) {
- mOnDrawerScrollListener.onScrollEnded();
- }
- if ( mVelocityTracker != null ) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
- private void doAnimation()
- {
- if ( mAnimating ) {
- incrementAnimation();
- if( mInvert )
- {
- if ( mAnimationPosition < mTopOffset ) {
- mAnimating = false;
- closeDrawer();
- } else if ( mAnimationPosition >= mTopOffset + ( mVertical ? getHeight() : getWidth() ) - 1 ) {
- mAnimating = false;
- openDrawer();
- } else {
- moveHandle( (int)mAnimationPosition );
- mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
- mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );
- }
- } else {
- if ( mAnimationPosition >= mBottomOffset + ( mVertical ? getHeight() : getWidth() ) - 1 ) {
- mAnimating = false;
- closeDrawer();
- } else if ( mAnimationPosition < mTopOffset ) {
- mAnimating = false;
- openDrawer();
- } else {
- moveHandle( (int)mAnimationPosition );
- mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
- mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );
- }
- }
- }
- }
- private void incrementAnimation()
- {
- long now = SystemClock.uptimeMillis();
- float t = ( now - mAnimationLastTime ) / 1000.0f; // ms -> s
- final float position = mAnimationPosition;
- final float v = mAnimatedVelocity; // px/s
- final float a = mInvert ? mAnimatedAcceleration : mAnimatedAcceleration; // px/s/s
- mAnimationPosition = position + ( v * t ) + ( 0.5f * a * t * t ); // px
- mAnimatedVelocity = v + ( a * t ); // px/s
- mAnimationLastTime = now; // ms
- }
- /**
- * Toggles the drawer open and close. Takes effect immediately.
- *
- * @see #open()
- * @see #close()
- * @see #animateClose()
- * @see #animateOpen()
- * @see #animateToggle()
- */
- public void toggle()
- {
- if ( !mExpanded ) {
- openDrawer();
- } else {
- closeDrawer();
- }
- invalidate();
- requestLayout();
- }
- /**
- * Toggles the drawer open and close with an animation.
- *
- * @see #open()
- * @see #close()
- * @see #animateClose()
- * @see #animateOpen()
- * @see #toggle()
- */
- public void animateToggle()
- {
- if ( !mExpanded ) {
- animateOpen();
- } else {
- animateClose();
- }
- }
- /**
- * Opens the drawer immediately.
- *
- * @see #toggle()
- * @see #close()
- * @see #animateOpen()
- */
- public void open()
- {
- openDrawer();
- invalidate();
- requestLayout();
- sendAccessibilityEvent( AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED );
- }
- /**
- * Closes the drawer immediately.
- *
- * @see #toggle()
- * @see #open()
- * @see #animateClose()
- */
- public void close()
- {
- closeDrawer();
- invalidate();
- requestLayout();
- }
- /**
- * Closes the drawer with an animation.
- *
- * @see #close()
- * @see #open()
- * @see #animateOpen()
- * @see #animateToggle()
- * @see #toggle()
- */
- public void animateClose()
- {
- prepareContent();
- final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
- if ( scrollListener != null ) {
- scrollListener.onScrollStarted();
- }
- animateClose( mVertical ? mHandle.getTop() : mHandle.getLeft() );
- if ( scrollListener != null ) {
- scrollListener.onScrollEnded();
- }
- }
- /**
- * Opens the drawer with an animation.
- *
- * @see #close()
- * @see #open()
- * @see #animateClose()
- * @see #animateToggle()
- * @see #toggle()
- */
- public void animateOpen()
- {
- prepareContent();
- final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
- if ( scrollListener != null ) {
- scrollListener.onScrollStarted();
- }
- animateOpen( mVertical ? mHandle.getTop() : mHandle.getLeft() );
- sendAccessibilityEvent( AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED );
- if ( scrollListener != null ) {
- scrollListener.onScrollEnded();
- }
- }
- private void closeDrawer()
- {
- moveHandle( COLLAPSED_FULL_CLOSED );
- mContent.setVisibility( View.GONE );
- mContent.destroyDrawingCache();
- if ( !mExpanded ) { return; }
- mExpanded = false;
- if ( mOnDrawerCloseListener != null ) {
- mOnDrawerCloseListener.onDrawerClosed();
- }
- }
- private void openDrawer()
- {
- moveHandle( EXPANDED_FULL_OPEN );
- mContent.setVisibility( View.VISIBLE );
- if ( mExpanded ) { return; }
- mExpanded = true;
- if ( mOnDrawerOpenListener != null ) {
- mOnDrawerOpenListener.onDrawerOpened();
- }
- }
- /**
- * Sets the listener that receives a notification when the drawer becomes
- * open.
- *
- * @param onDrawerOpenListener
- * The listener to be notified when the drawer is opened.
- */
- public void setOnDrawerOpenListener( OnDrawerOpenListener onDrawerOpenListener )
- {
- mOnDrawerOpenListener = onDrawerOpenListener;
- }
- /**
- * Sets the listener that receives a notification when the drawer becomes
- * close.
- *
- * @param onDrawerCloseListener
- * The listener to be notified when the drawer is closed.
- */
- public void setOnDrawerCloseListener( OnDrawerCloseListener onDrawerCloseListener )
- {
- mOnDrawerCloseListener = onDrawerCloseListener;
- }
- /**
- * Sets the listener that receives a notification when the drawer starts or
- * ends a scroll. A fling is considered as a scroll. A fling will also
- * trigger a drawer opened or drawer closed event.
- *
- * @param onDrawerScrollListener
- * The listener to be notified when scrolling starts or stops.
- */
- public void setOnDrawerScrollListener( OnDrawerScrollListener onDrawerScrollListener )
- {
- mOnDrawerScrollListener = onDrawerScrollListener;
- }
- /**
- * Returns the handle of the drawer.
- *
- * @return The View reprenseting the handle of the drawer, identified by the
- * "handle" id in XML.
- */
- public View getHandle()
- {
- return mHandle;
- }
- /**
- * Returns the content of the drawer.
- *
- * @return The View reprenseting the content of the drawer, identified by the
- * "content" id in XML.
- */
- public View getContent()
- {
- return mContent;
- }
- /**
- * Unlocks the SlidingDrawer so that touch events are processed.
- *
- * @see #lock()
- */
- public void unlock()
- {
- mLocked = false;
- }
- /**
- * Locks the SlidingDrawer so that touch events are ignores.
- *
- * @see #unlock()
- */
- public void lock()
- {
- mLocked = true;
- }
- /**
- * Indicates whether the drawer is currently fully opened.
- *
- * @return True if the drawer is opened, false otherwise.
- */
- public boolean isOpened()
- {
- return mExpanded;
- }
- /**
- * Indicates whether the drawer is scrolling or flinging.
- *
- * @return True if the drawer is scroller or flinging, false otherwise.
- */
- public boolean isMoving()
- {
- return mTracking || mAnimating;
- }
- private class DrawerToggler implements OnClickListener {
- public void onClick( View v )
- {
- if ( mLocked ) { return; }
- // mAllowSingleTap isn't relevant here; you're *always*
- // allowed to open/close the drawer by clicking with the
- // trackball.
- if ( mAnimateOnClick ) {
- animateToggle();
- } else {
- toggle();
- }
- }
- }
- private class SlidingHandler extends Handler {
- public void handleMessage( Message m )
- {
- switch ( m.what ) {
- case MSG_ANIMATE:
- doAnimation();
- break;
- }
- }
- }
- }
csdn下载地址:点击打开链接
git下载地址:点击打开链接