package com.adamnickle.deck;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.FrameLayout;
public class SlidingFrameLayout extends FrameLayout
{
private enum State
{
COLLAPSED,
COLLAPSING,
EXPANDED,
EXPANDING,
}
private static final int ANIMATOR_DURATION = 500;
private State mCurrentState;
private final ObjectAnimator mSlidingAnimator;
public SlidingFrameLayout( Context context )
{
this( context, null );
}
public SlidingFrameLayout( Context context, AttributeSet attrs )
{
this( context, attrs, 0 );
}
public SlidingFrameLayout( Context context, AttributeSet attrs, int defStyle )
{
super( context, attrs, defStyle );
this.setFocusableInTouchMode( true );
mCurrentState = State.COLLAPSED;
mSlidingAnimator = ObjectAnimator.ofFloat( this, "Y", 0.0f, 0.0f )
.setDuration( ANIMATOR_DURATION );
mSlidingAnimator.addListener( new AnimatorListenerAdapter()
{
@Override
public void onAnimationEnd( Animator animation )
{
switch( mCurrentState )
{
case EXPANDING:
mCurrentState = State.EXPANDED;
break;
case COLLAPSING:
mCurrentState = State.COLLAPSED;
break;
}
}
} );
}
@Override
protected void onLayout( boolean changed, int left, int top, int right, int bottom )
{
super.onLayout( changed, left, top, right, bottom );
switch( mCurrentState )
{
case EXPANDING:
mCurrentState = State.EXPANDED;
case EXPANDED:
expandFrame( false );
break;
case COLLAPSING:
mCurrentState = State.COLLAPSED;
case COLLAPSED:
collapseFrame( false );
break;
}
}
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event)
{
if( KeyEvent.KEYCODE_BACK == keyCode && this.isOpen() )
{
event.startTracking();
return true;
}
return super.onKeyDown( keyCode, event );
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if( KeyEvent.KEYCODE_BACK == keyCode && !event.isCanceled() && this.isOpen() )
{
this.collapseFrame();
return true;
}
return super.onKeyUp( keyCode, event );
}
public void expandFrame()
{
expandFrame( true );
}
public void expandFrame( boolean animate )
{
mSlidingAnimator.cancel();
if( animate )
{
mCurrentState = State.EXPANDING;
mSlidingAnimator.setFloatValues( this.getY(), 0.0f );
mSlidingAnimator.start();
}
else
{
this.setY( 0.0f );
mCurrentState = State.EXPANDED;
}
}
public void collapseFrame()
{
collapseFrame( true );
}
public void collapseFrame( boolean animate )
{
mSlidingAnimator.cancel();
if( animate )
{
mCurrentState = State.COLLAPSING;
mSlidingAnimator.setFloatValues( this.getY(), -this.getHeight() );
mSlidingAnimator.start();
}
else
{
this.setY( -this.getHeight() );
mCurrentState = State.COLLAPSED;
}
}
public void toggleState()
{
switch( mCurrentState )
{
case EXPANDED:
case EXPANDING:
collapseFrame();
break;
case COLLAPSED:
case COLLAPSING:
expandFrame();
break;
}
}
public boolean isOpen()
{
return mCurrentState == State.EXPANDED || mCurrentState == State.EXPANDING;
}
@Override
protected Parcelable onSaveInstanceState()
{
SavedState savedState = new SavedState( super.onSaveInstanceState() );
savedState.isOpen = isOpen();
return savedState;
}
@Override
protected void onRestoreInstanceState( Parcelable state )
{
if( state instanceof SavedState )
{
super.onRestoreInstanceState( ( (SavedState) state ).getSuperState() );
mCurrentState = ( (SavedState) state ).isOpen ? State.EXPANDED : State.COLLAPSED;
}
else
{
super.onRestoreInstanceState( state );
}
}
public static class SavedState extends BaseSavedState
{
boolean isOpen;
public SavedState( Parcel source )
{
super( source );
isOpen = source.readInt() != 0;
}
public SavedState( Parcelable superState )
{
super( superState );
}
@Override
public void writeToParcel( @NonNull Parcel destination, int flags )
{
super.writeToParcel( destination, flags );
destination.writeInt( isOpen ? 1 : 0 );
}
public static final Creator< SavedState > CREATOR = new Creator< SavedState >()
{
@Override
public SavedState createFromParcel( Parcel source )
{
return new SavedState( source );
}
@Override
public SavedState[] newArray( int size )
{
return new SavedState[ size ];
}
};
}
}