package com.ijoomer.menubuilder;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import com.ijoomer.src.R;
public abstract class MenuDrawer extends ViewGroup {
/**
* Callback interface for changing state of the drawer.
*/
public interface OnDrawerStateChangeListener {
/**
* Called when the drawer state changes.
*
* @param oldState
* The old drawer state.
* @param newState
* The new drawer state.
*/
void onDrawerStateChange(int oldState, int newState);
}
/**
* Callback that is invoked when the drawer is in the process of deciding
* whether it should intercept the touch event. This lets the listener
* decide if the pointer is on a view that would disallow dragging of the
* drawer. This is only called when the touch mode is
* {@link #TOUCH_MODE_FULLSCREEN}.
*/
public interface OnInterceptMoveEventListener {
/**
* Called for each child the pointer i on when the drawer is deciding
* whether to intercept the touch event.
*
* @param v
* View to test for draggability
* @param dx
* Delta drag in pixels
* @param x
* X coordinate of the active touch point
* @param y
* Y coordinate of the active touch point
* @return true if view is draggable by delta dx.
*/
boolean isViewDraggable(View v, int dx, int x, int y);
}
/**
* Tag used when logging.
*/
private static final String TAG = "MenuDrawer";
/**
* Indicates whether debug code should be enabled.
*/
private static final boolean DEBUG = false;
/**
* The time between each frame when animating the drawer.
*/
protected static final int ANIMATION_DELAY = 1000 / 60;
/**
* The default touch bezel size of the drawer in dp.
*/
private static final int DEFAULT_DRAG_BEZEL_DP = 24;
/**
* The default drop shadow size in dp.
*/
private static final int DEFAULT_DROP_SHADOW_DP = 6;
/**
* Drag mode for sliding only the content view.
*/
public static final int MENU_DRAG_CONTENT = 0;
/**
* Drag mode for sliding the entire window.
*/
public static final int MENU_DRAG_WINDOW = 1;
/**
* Disallow opening the drawer by dragging the screen.
*/
public static final int TOUCH_MODE_NONE = 0;
/**
* Allow opening drawer only by dragging on the edge of the screen.
*/
public static final int TOUCH_MODE_BEZEL = 1;
/**
* Allow opening drawer by dragging anywhere on the screen.
*/
public static final int TOUCH_MODE_FULLSCREEN = 2;
/**
* Indicates that the drawer is currently closed.
*/
public static final int STATE_CLOSED = 0;
/**
* Indicates that the drawer is currently closing.
*/
public static final int STATE_CLOSING = 1;
/**
* Indicates that the drawer is currently being dragged by the user.
*/
public static final int STATE_DRAGGING = 2;
/**
* Indicates that the drawer is currently opening.
*/
public static final int STATE_OPENING = 4;
/**
* Indicates that the drawer is currently open.
*/
public static final int STATE_OPEN = 8;
/**
* Indicates whether to use {@link View#setTranslationX(float)} when
* positioning views.
*/
static final boolean USE_TRANSLATIONS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
/**
* Time to animate the indicator to the new active view.
*/
static final int INDICATOR_ANIM_DURATION = 800;
/**
* The maximum animation duration.
*/
private static final int DEFAULT_ANIMATION_DURATION = 600;
/**
* Interpolator used when animating the drawer open/closed.
*/
protected static final Interpolator SMOOTH_INTERPOLATOR = new SmoothInterpolator();
/**
* Drawable used as menu overlay.
*/
protected Drawable mMenuOverlay;
/**
* Defines whether the drop shadow is enabled.
*/
protected boolean mDropShadowEnabled;
/**
* Drawable used as content drop shadow onto the menu.
*/
protected Drawable mDropShadowDrawable;
/**
* The size of the content drop shadow.
*/
protected int mDropShadowSize;
/**
* Bitmap used to indicate the active view.
*/
protected Bitmap mActiveIndicator;
/**
* The currently active view.
*/
protected View mActiveView;
/**
* Position of the active view. This is compared to
* View#getTag(R.id.mdActiveViewPosition) when drawing the indicator.
*/
protected int mActivePosition;
/**
* Whether the indicator should be animated between positions.
*/
private boolean mAllowIndicatorAnimation;
/**
* Used when reading the position of the active view.
*/
protected final Rect mActiveRect = new Rect();
/**
* Temporary {@link Rect} used for deciding whether the view should be
* invalidated so the indicator can be redrawn.
*/
private final Rect mTempRect = new Rect();
/**
* The custom menu view set by the user.
*/
private View mMenuView;
/**
* The parent of the menu view.
*/
protected BuildLayerFrameLayout mMenuContainer;
/**
* The parent of the content view.
*/
protected BuildLayerFrameLayout mContentContainer;
/**
* The size of the menu (width or height depending on the gravity).
*/
protected int mMenuSize;
/**
* Indicates whether the menu size has been set explicity either via the
* theme or by calling {@link #setMenuSize(int)}.
*/
protected boolean mMenuSizeSet;
/**
* Indicates whether the menu is currently visible.
*/
protected boolean mMenuVisible;
/**
* The drag mode of the drawer. Can be either {@link #MENU_DRAG_CONTENT} or
* {@link #MENU_DRAG_WINDOW}.
*/
private int mDragMode = MENU_DRAG_CONTENT;
/**
* The current drawer state.
*
* @see #STATE_CLOSED
* @see #STATE_CLOSING
* @see #STATE_DRAGGING
* @see #STATE_OPENING
* @see #STATE_OPEN
*/
protected int mDrawerState = STATE_CLOSED;
/**
* The touch bezel size of the drawer in px.
*/
protected int mTouchBezelSize;
/**
* The touch area size of the drawer in px.
*/
protected int mTouchSize;
/**
* Listener used to dispatch state change events.
*/
private OnDrawerStateChangeListener mOnDrawerStateChangeListener;
/**
* Touch mode for the Drawer. Possible values are {@link #TOUCH_MODE_NONE},
* {@link #TOUCH_MODE_BEZEL} or {@link #TOUCH_MODE_FULLSCREEN} Default:
* {@link #TOUCH_MODE_BEZEL}
*/
protected int mTouchMode = TOUCH_MODE_BEZEL;
/**
* Indicates whether to use {@link View#LAYER_TYPE_HARDWARE} when animating
* the drawer.
*/
protected boolean mHardwareLayersEnabled = true;
/**
* The Activity the drawer is attached to.
*/
private Activity mActivity;
/**
* Scroller used when animating the indicator to a new position.
*/
private FloatScroller mIndicatorScroller;
/**
* Runnable used when animating the indicator to a new position.
*/
private Runnable mIndicatorRunnable = new Runnable() {
@Override
public void run() {
animateIndicatorInvalidate();
}
};
/**
* The start position of the indicator when animating it to a new position.
*/
protected int mIndicatorStartPos;
/**
* [0..1] value indicating the current progress of the animation.
*/
protected float mIndicatorOffset;
/**
* Whether the indicator is currently animating.
*/
protected boolean mIndicatorAnimating;
/**
* Bundle used to hold the drawers state.
*/
protected Bundle mState;
/**
* The maximum duration of open/close animations.
*/
protected int mMaxAnimationDuration = DEFAULT_ANIMATION_DURATION;
/**
* Callback that lets the listener override intercepting of touch events.
*/
protected OnInterceptMoveEventListener mOnInterceptMoveEventListener;
/**
* Attaches the MenuDrawer to the Activity.
*
* @param activity
* The activity that the MenuDrawer will be attached to.
* @return The created MenuDrawer instance.
*/
public static MenuDrawer attach(Activity activity) {
return attach(activity, MENU_DRAG_CONTENT);
}
/**
* Attaches the MenuDrawer to the Activity.
*
* @param activity
* The activity the menu drawer will be attached to.
* @param dragMode
* The drag mode of the drawer. Can be either
* {@link MenuDrawer#MENU_DRAG_CONTENT} or
* {@link MenuDrawer#MENU_DRAG_WINDOW}.
* @return The created MenuDrawer instance.
*/
public static MenuDrawer attach(Activity activity, int dragMode) {
return attach(activity, dragMode, Position.LEFT);
}
/**
* Attaches the MenuDrawer to the Activity.
*
* @param activity
* The activity the menu drawer will be attached to.
* @param position
* Where to position the menu.
* @return The created MenuDrawer instance.
*/
public static MenuDrawer attach(Activity activity, Position position) {
return attach(activity, MENU_DRAG_CONTENT, position);
}
/**
* Attaches the MenuDrawer to the Activity.
*
* @param activity
* The activity the menu drawer will be attached to.
* @param dragMode
* The drag mode of the drawer. Can be either
* {@link MenuDrawer#MENU_DRAG_CONTENT} or
* {@link MenuDrawer#MENU_DRAG_WINDOW}.
* @param position
* Where to position the menu.
* @return The created MenuDrawer instance.
*/
public static MenuDrawer attach(Activity activity, int dragMode, Position position) {
return attach(activity, dragMode, position, false);
}
/**
* Attaches the MenuDrawer to the Activity.
*
* @param activity
* The activity the menu drawer will be attached to.
* @param dragMode
* The drag mode of the drawer. Can be either
* {@link MenuDrawer#MENU_DRAG_CONTENT} or
* {@link MenuDrawer#MENU_DRAG_WINDOW}.
* @param position
* Where to position the menu.
* @param attachStatic
* Whether a static (non-draggable, always visible) drawer should
* be used.
* @return The created MenuDrawer instance.
*/
public static MenuDrawer attach(Activity activity, int dragMode, Position position, boolean attachStatic) {
MenuDrawer menuDrawer = createMenuDrawer(activity, dragMode, position, attachStatic);
menuDrawer.setId(R.id.md__drawer);
switch (dragMode) {
case MenuDrawer.MENU_DRAG_CONTENT:
attachToContent(activity, menuDrawer);
break;
case MenuDrawer.MENU_DRAG_WINDOW:
attachToDecor(activity, menuDrawer);
break;
default:
throw new RuntimeException("Unknown menu mode: " + dragMode);
}
return menuDrawer;
}
/**
* Constructs the appropriate MenuDrawer based on the position.
*/
private static MenuDrawer createMenuDrawer(Activity activity, int dragMode, Position position, boolean attachStatic) {
if (attachStatic) {
switch (position) {
case LEFT:
return new LeftStaticDrawer(activity, dragMode);
case RIGHT:
return new RightStaticDrawer(activity, dragMode);
case TOP:
return new TopStaticDrawer(activity, dragMode);
case BOTTOM:
return new BottomStaticDrawer(activity, dragMode);
default:
throw new IllegalArgumentException("position must be one of LEFT, TOP, RIGHT or BOTTOM");
}
}
switch (position) {
case LEFT:
return new LeftDrawer(activity, dragMode);
case RIGHT:
return new RightDrawer(activity, dragMode);
case TOP:
return new TopDrawer(activity, dragMode);
case BOTTOM:
return new BottomDrawer(activity, dragMode);
default:
throw new IllegalArgumentException("position must be one of LEFT, TOP, RIGHT or BOTTOM");
}
}
/**
* Attaches the menu drawer to the content view.
*/
private static void attachToContent(Activity activity, MenuDrawer menuDrawer) {
/**
* Do not call mActivity#setContentView. E.g. if using with a
* ListActivity, Activity#setContentView is overridden and dispatched to
* MenuDrawer#setContentView, which then again would call
* Activity#setContentView.
*/
ViewGroup content = (ViewGroup) activity.findViewById(android.R.id.content);
content.removeAllViews();
content.addView(menuDrawer, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
/**
* Attaches the menu drawer to the window.
*/
private static void attachToDecor(Activity activity, MenuDrawer menuDrawer) {
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
ViewGroup decorChild = (ViewGroup) decorView.getChildAt(0);
decorView.removeAllViews();
decorView.addView(menuDrawer, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
menuDrawer.mContentContainer.addView(decorChild, decorChild.getLayoutParams());
}
MenuDrawer(Activity activity, int dragMode) {
this(activity);
mActivity = activity;
mDragMode = dragMode;
}
public MenuDrawer(Context context) {
this(context, null);
}
public MenuDrawer(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.menuDrawerStyle);
}
public MenuDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initDrawer(context, attrs, defStyle);
}
@SuppressWarnings("deprecation")
protected void initDrawer(Context context, AttributeSet attrs, int defStyle) {
setWillNotDraw(false);
setFocusable(false);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MenuDrawer, R.attr.menuDrawerStyle, R.style.Widget_MenuDrawer);
final Drawable contentBackground = a.getDrawable(R.styleable.MenuDrawer_mdContentBackground);
final Drawable menuBackground = a.getDrawable(R.styleable.MenuDrawer_mdMenuBackground);
mMenuSize = a.getDimensionPixelSize(R.styleable.MenuDrawer_mdMenuSize, -1);
mMenuSizeSet = mMenuSize != -1;
final int indicatorResId = a.getResourceId(R.styleable.MenuDrawer_mdActiveIndicator, 0);
if (indicatorResId != 0) {
mActiveIndicator = BitmapFactory.decodeResource(getResources(), indicatorResId);
}
mDropShadowEnabled = a.getBoolean(R.styleable.MenuDrawer_mdDropShadowEnabled, true);
mDropShadowDrawable = a.getDrawable(R.styleable.MenuDrawer_mdDropShadow);
if (mDropShadowDrawable == null) {
final int dropShadowColor = a.getColor(R.styleable.MenuDrawer_mdDropShadowColor, 0xFF000000);
setDropShadowColor(dropShadowColor);
}
mDropShadowSize = a.getDimensionPixelSize(R.styleable.MenuDrawer_mdDropShadowSize, dpToPx(DEFAULT_DROP_SHADOW_DP));
mTouchBezelSize = a.getDimensionPixelSize(R.styleable.MenuDrawer_mdTouchBezelSize, dpToPx(DEFAULT_DRAG_BEZEL_DP));
mAllowIndicatorAnimation = a.getBoolean(R.styleable.MenuDrawer_mdAllowIndicatorAnimation, false);
mMaxAnimationDuration = a.getInt(R.styleable.MenuDrawer_mdMaxAnimationDuration, DEFAULT_ANIMATION_DURATION);
a.recycle();
mMenuContainer = new BuildLayerFrameLayout(context);
mMenuContainer.setId(R.id.md__menu);
mMenuContainer.setBackgroundDrawable(menuBackground);
super.addView(mMenuContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mContentContainer = new NoClickThroughFrameLayout(context);
mContentContainer.setId(R.id.md__content);
mContentContainer.setBackgroundDrawable(contentBackground);
super.addView(mContentContainer, -1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
mMenuOverlay = new ColorDrawable(0xFF000000);
mIndicatorScroller = new FloatScroller(SMOOTH_INTERPOLATOR);
}
@Override
public void addView(View child, int index, LayoutParams params) {
int childCount = mMenuContainer.getChildCount();
if (childCount == 0) {
mMenuContainer.addView(child, index, params);
return;
}
childCount = mContentContainer.getChildCount();
if (childCount == 0) {
mContentContainer.addView(child, index, params);
return;
}
throw new IllegalStateException("MenuDrawer can only hold two child views");
}
protected int dpToPx(int dp) {
return (int) (getResources().getDisplayMetrics().density * dp + 0.5f);
}
protected boolean isViewDescendant(View v) {
ViewParent parent = v.getParent();
while (parent != null) {
if (parent == this) {
return true;
}
parent = parent.getParent();
}
return false;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnScrollChangedListener(mScrollListener);
}
@Override
protected void onDetachedFromWindow() {
getViewTreeObserver().removeOnScrollChangedListener(mScrollListener);
super.onDetachedFromWindow();
}
/**
* Toggles the menu open and close with animation.
*/
public void toggleMenu() {
toggleMenu(true);
}
/**
* Toggles the menu open and close.
*
* @param animate
* Whether open/close should be animated.
*/
public abstract void toggleMenu(boolean animate);
/**
* Animates the menu open.
*/
public void openMenu() {
openMenu(true);
}
/**
* Opens the menu.
*
* @param animate
* Whether open/close should be animated.
*/
public abstract void openMenu(boolean animate);
/**
* Animates the menu closed.
*/
public void closeMenu() {
closeMenu(true);
}
/**
* Closes the menu.
*
* @param animate
* Whether open/close should be animated.
*/
public abstract void closeMenu(boolean animate);
/**
* Indicates whether the menu is currently visible.
*
* @return True if the menu is open, false otherwise.
*/
public abstract boolean isMenuVisible();
/**
* Set the size of the menu drawer when open.
*
* @param size
* The size of the menu.
*/
public abstract void setMenuSize(int size);
/**
* Returns the size of the menu.
*
* @return The size of the menu.
*/
public int getMenuSize() {
return mMenuSize;
}
/**
* Set the active view. If the mdActiveIndicator attribute is set, this View
* will have the indicator drawn next to it.
*
* @param v
* The active view.
*/
public void setActiveView(View v) {
setActiveView(v, 0);
}
/**
* Set the active view. If the mdActiveIndicator attribute is set, this View
* will have the indicator drawn next to it.
*
* @param v
* The active view.
* @param position
* Optional position, usually used with ListView.
* v.setTag(R.id.mdActiveViewPosition, position) must be called
* first.
*/
public void setActiveView(View v, int position) {
final View oldView = mActiveView;
mActiveView = v;
mActivePosition = position;
if (mAllowIndicatorAnimation && oldView != null) {
startAnimatingIndicator();
}
invalidate();
}
/**
* Sets whether the indicator should be animated between active views.
*
* @param animate
* Whether the indicator should be animated between active views.
*/
public void setAllowIndicatorAnimation(boolean animate) {
if (animate != mAllowIndicatorAnimation) {
mAllowIndicatorAnimation = animate;
completeAnimatingIndicator();
}
}
/**
* Indicates whether the indicator should be animated between active views.
*
* @return Whether the indicator should be animated between active views.
*/
public boolean getAllowIndicatorAnimation() {
return mAllowIndicatorAnimation;
}
/**
* Scroll listener that checks whether the active view has moved before the
* drawer is invalidated.
*/
private ViewTreeObserver.OnScrollChangedListener mScrollListener = new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
if (mActiveView != null && isViewDescendant(mActiveView)) {
mActiveView.getDrawingRect(mTempRect);
offsetDescendantRectToMyCoords(mActiveView, mTempRect);
if (mTempRect.left != mActiveRect.left || mTempRect.top != mActiveRect.top || mTempRect.right != mActiveRect.right || mTempRect.bottom != mActiveRect.bottom) {
invalidate();
}
}
}
};
/**
* Starts animating the indicator to a new position.
*/
private void startAnimatingIndicator() {
mIndicatorStartPos = getIndicatorStartPos();
mIndicatorAnimating = true;
mIndicatorScroller.startScroll(0.0f, 1.0f, INDICATOR_ANIM_DURATION);
animateIndicatorInvalidate();
}
/**
* Returns the start position of the indicator.
*
* @return The start position of the indicator.
*/
protected abstract int getIndicatorStartPos();
/**
* Callback when each frame in the indicator animation should be drawn.
*/
private void animateIndicatorInvalidate() {
if (mIndicatorScroller.computeScrollOffset()) {
mIndicatorOffset = mIndicatorScroller.getCurr();
invalidate();
if (!mIndicatorScroller.isFinished()) {
postOnAnimation(mIndicatorRunnable);
return;
}
}
completeAnimatingIndicator();
}
/**
* Called when the indicator animation has completed.
*/
private void completeAnimatingIndicator() {
mIndicatorOffset = 1.0f;
mIndicatorAnimating = false;
invalidate();
}
/**
* Enables or disables offsetting the menu when dragging the drawer.
*
* @param offsetMenu
* True to offset the menu, false otherwise.
*/
public abstract void setOffsetMenuEnabled(boolean offsetMenu);
/**
* Indicates whether the menu is being offset when dragging the drawer.
*
* @return True if the menu is being offset, false otherwise.
*/
public abstract boolean getOffsetMenuEnabled();
public int getDrawerState() {
return mDrawerState;
}
/**
* Register a callback to be invoked when the drawer state changes.
*
* @param listener
* The callback that will run.
*/
public void setOnDrawerStateChangeListener(OnDrawerStateChangeListener listener) {
mOnDrawerStateChangeListener = listener;
}
/**
* Register a callback that will be invoked when the drawer is about to
* intercept touch events.
*
* @param listener
* The callback that will be invoked.
*/
public void setOnInterceptMoveEventListener(OnInterceptMoveEventListener listener) {
mOnInterceptMoveEventListener = listener;
}
/**
* Defines whether the drop shadow is enabled.
*
* @param enabled
* Whether the drop shadow is enabled.
*/
public void setDropShadowEnabled(boolean enabled) {
mDropShadowEnabled = enabled;
invalidate();
}
/**
* Sets the color of the drop shadow.
*
* @param color
* The color of the drop shadow.
*/
public abstract void setDropShadowColor(int color);
/**
* Sets the drawable of the drop shadow.
*
* @param drawable
* The drawable of the drop shadow.
*/
public void setDropShadow(Drawable drawable) {
mDropShadowDrawable = drawable;
invalidate();
}
/**
* Sets the drawable of the drop shadow.
*
* @param resId
* The resource identifier of the the drawable.
*/
public void setDropShadow(int resId) {
setDropShadow(getResources().getDrawable(resId));
}
/**
* Returns the drawable of the drop shadow.
*/
public Drawable getDropShadow() {
return mDropShadowDrawable;
}
/**
* Sets the size of the drop shadow.
*
* @param size
* The size of the drop shadow in px.
*/
public void setDropShadowSize(int size) {
mDropShadowSize = size;
invalidate();
}
/**
* Animates the drawer slightly open until the user opens the drawer.
*/
public abstract void peekDrawer();
/**
* Animates the drawer slightly open. If delay is larger than 0, this
* happens until the user opens the drawer.
*
* @param delay
* The delay (in milliseconds) between each run of the animation.
* If 0, this animation is only run once.
*/
public abstract void peekDrawer(long delay);
/**
* Animates the drawer slightly open. If delay is larger than 0, this
* happens until the user opens the drawer.
*
* @param startDelay
* The delay (in milliseconds) until the animation is first run.
* @param delay
* The delay (in milliseconds) between each run of the animation.
* If 0, this animation is only run once.
*/
public abstract void peekDrawer(long startDelay, long delay);
/**
* Enables or disables the user of {@link View#LAYER_TYPE_HARDWARE} when
* animations views.
*
* @param enabled
* Whether hardware layers are enabled.
*/
public abstract void setHardwareLayerEnabled(boolean enabled);
/**
* Sets the maximum duration of open/close animations.
*
* @param duration
* The maximum duration in milliseconds.
*/
public void setMaxAnimationDuration(int duration) {
mMaxAnimationDuration = duration;
}
/**
* Returns the ViewGroup used as a parent for the menu view.
*
* @return The menu view's parent.
*/
public ViewGroup getMenuContainer() {
return mMenuContainer;
}
/**
* Returns the ViewGroup used as a parent for the content view.
*
* @return The content view's parent.
*/
public ViewGroup getContentContainer() {
if (mDragMode == MENU_DRAG_CONTENT) {
return mContentContainer;
} else {
return (ViewGroup) findViewById(android.R.id.content);
}
}
/**
* Set the menu view from a layout resource.
*
* @param layoutResId
* Resource ID to be inflated.
*/
public void setMenuView(int layoutResId) {
mMenuContainer.removeAllViews();
mMenuView = LayoutInflater.from(getContext()).inflate(layoutResId, mMenuContainer, false);
mMenuContainer.addView(mMenuView);
}
/**
* Set the menu view to an explicit view.
*
* @param view
* The menu view.
*/
public void setMenuView(View view) {
setMenuView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
/**
* Set the menu view to an explicit view.
*
* @param view
* The menu view.
* @param params
* Layout parameters for the view.
*/
public void setMenuView(View view, LayoutParams params) {
mMenuView = view;
mMenuContainer.removeAllViews();
mMenuContainer.addView(view, params);
}
/**
* Returns the menu view.
*
* @return The menu view.
*/
public View getMenuView() {
return mMenuView;
}
/**
* Set the content from a layout resource.
*
* @param layoutResId
* Resource ID to be inflated.
*/
public void setContentView(int layoutResId) {
switch (mDragMode) {
case MenuDrawer.MENU_DRAG_CONTENT:
mContentContainer.removeAllViews();
LayoutInflater.from(getContext()).inflate(layoutResId, mContentContainer, true);
break;
case MenuDrawer.MENU_DRAG_WINDOW:
mActivity.setContentView(layoutResId);
break;
}
}
/**
* Set the content to an explicit view.
*
* @param view
* The desired content to display.
*/
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
/**
* Set the content to an explicit view.
*
* @param view
* The desired content to display.
* @param params
* Layout parameters for the view.
*/
public void setContentView(View view, LayoutParams params) {
switch (mDragMode) {
case MenuDrawer.MENU_DRAG_CONTENT:
mContentContainer.removeAllViews();
mContentContainer.addView(view, params);
break;
case MenuDrawer.MENU_DRAG_WINDOW:
mActivity.setContentView(view, params);
break;
}
}
protected void setDrawerState(int state) {
if (state != mDrawerState) {
final int oldState = mDrawerState;
mDrawerState = state;
if (mOnDrawerStateChangeListener != null)
mOnDrawerStateChangeListener.onDrawerStateChange(oldState, state);
if (DEBUG)
logDrawerState(state);
}
}
protected void logDrawerState(int state) {
switch (state) {
case STATE_CLOSED:
Log.d(TAG, "[DrawerState] STATE_CLOSED");
break;
case STATE_CLOSING:
Log.d(TAG, "[DrawerState] STATE_CLOSING");
break;
case STATE_DRAGGING:
Log.d(TAG, "[DrawerState] STATE_DRAGGING");
break;
case STATE_OPENING:
Log.d(TAG, "[DrawerState] STATE_OPENING");
break;
case STATE_OPEN:
Log.d(TAG, "[DrawerState] STATE_OPEN");
break;
default:
Log.d(TAG, "[DrawerState] Unknown: " + state);
}
}
/**
* Returns the touch mode.
*/
public abstract int getTouchMode();
/**
* Sets the drawer touch mode. Possible values are {@link #TOUCH_MODE_NONE},
* {@link #TOUCH_MODE_BEZEL} or {@link #TOUCH_MODE_FULLSCREEN}.
*
* @param mode
* The touch mode.
*/
public abstract void setTouchMode(int mode);
/**
* Sets the size of the touch bezel.
*
* @param size
* The touch bezel size in px.
*/
public abstract void setTouchBezelSize(int size);
/**
* Returns the size of the touch bezel in px.
*/
public abstract int getTouchBezelSize();
@Override
public void postOnAnimation(Runnable action) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
super.postOnAnimation(action);
} else {
postDelayed(action, ANIMATION_DELAY);
}
}
@Override
protected boolean fitSystemWindows(Rect insets) {
if (mDragMode == MENU_DRAG_WINDOW) {
mMenuContainer.setPadding(0, insets.top, 0, 0);
}
return super.fitSystemWindows(insets);
}
/**
* Saves the state of the drawer.
*
* @return Returns a Parcelable containing the drawer state.
*/
public final Parcelable saveState() {
if (mState == null)
mState = new Bundle();
saveState(mState);
return mState;
}
void saveState(Bundle state) {
// State saving isn't required for subclasses.
}
/**
* Restores the state of the drawer.
*
* @param in
* A parcelable containing the drawer state.
*/
public void restoreState(Parcelable in) {
mState = (Bundle) in;
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState state = new SavedState(superState);
if (mState == null)
mState = new Bundle();
saveState(mState);
state.mState = mState;
return state;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
restoreState(savedState.mState);
}
static class SavedState extends BaseSavedState {
Bundle mState;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel in) {
super(in);
mState = in.readBundle();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeBundle(mState);
}
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}