The idea of ResideMenu is from Dribbble 1 and 2. It has come true and run in iOS devices. iOS ResideMenu This project is the RefsideMenu Android version. The visual effect is partly referred to iOS version of ResideMenu. And thanks to the authors for the above idea and contribution.
MIT License
2.85k
stars
1.1k
forks
source link
Download the library and replace ResideMenu class with given below code. #159
Mail: specialcyci@gmail.com
*/
public class ResideMenu extends FrameLayout {
public static final int DIRECTION_LEFT = 0;
public static final int DIRECTION_RIGHT = 1;
private static final int PRESSED_MOVE_HORIZONTAL = 2;
private static final int PRESSED_DOWN = 3;
private static final int PRESSED_DONE = 4;
private static final int PRESSED_MOVE_VERTICAL = 5;
Current attaching activity.
*/
private Activity activity;
/**
The DecorView of current activity.
*/
private ViewGroup viewDecor;
private TouchDisableView viewActivity;
/**
The flag of menu opening status.
*/
private boolean isOpened;
private float shadowAdjustScaleX;
private float shadowAdjustScaleY;
/**
Views which need stop to intercept touch events.
*/
private List ignoredViews;
private List leftMenuItems;
private List rightMenuItems;
private DisplayMetrics displayMetrics = new DisplayMetrics();
private OnMenuListener menuListener;
private float lastRawX;
private boolean isInIgnoredView = false;
private int scaleDirection = DIRECTION_LEFT;
private int pressedState = PRESSED_DOWN;
private List disabledSwipeDirection = new ArrayList();
// Valid scale factor is between 0.0f and 1.0f.
private float mScaleValue = 0.5f;
private boolean mUse3D;
private static final int ROTATE_Y_ANGLE = 10;
public ResideMenu(Context context) {
super(context);
mContext=context;
initViews(context, -1, -1);
}
/**
This constructor provides you to create menus with your own custom
layouts, but if you use custom menu then do not call addMenuItem because
it will not be able to find default views
*/
public ResideMenu(Context context, int customLeftMenuId,
int customRightMenuId) {
super(context);
mContext=context;
initViews(context, customLeftMenuId, customRightMenuId);
}
private void initViews(Context context, int customLeftMenuId,
int customRightMenuId) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.residemenu_custom, this);
Returns left menu view so you can findViews and do whatever you want with
*/
public View getLeftMenuView() {
return scrollViewLeftMenu;
}
/**
Returns right menu view so you can findViews and do whatever you want with
*/
public View getRightMenuView() {
return scrollViewRightMenu;
}
@Override
protected boolean fitSystemWindows(Rect insets) {
// Applies the content insets to the view's padding, consuming that
// content (modifying the insets to be 0),
// and returning true. This behavior is off by default and can be
// enabled through setFitsSystemWindows(boolean)
// in api14+ devices.
Point appUsableSize = getAppUsableScreenSize(mContext);
Point realScreenSize = getRealScreenSize(mContext);
boolean hasBackKey=false;
// navigation bar at the bottom
if (appUsableSize.y < realScreenSize.y) {
hasBackKey=true;
}
// This is added to fix soft navigationBar's overlapping to content above LOLLIPOP
int bottomPadding = viewActivity.getPaddingBottom() + insets.bottom;
if (hasBackKey ) {//there's a navigation bar
bottomPadding += getNavigationBarHeight();
}
this.setPadding(viewActivity.getPaddingLeft() + insets.left,
viewActivity.getPaddingTop() + insets.top,
viewActivity.getPaddingRight() + insets.right,
bottomPadding);
insets.left = insets.top = insets.right = insets.bottom = 0;
return true;
}
public static Point getAppUsableScreenSize(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
public static Point getRealScreenSize(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
If there were some view you don't want reside menu
to intercept their touch event, you could add it to
ignored views.
@param v
*/
public void addIgnoredView(View v) {
ignoredViews.add(v);
}
/**
Remove a view from ignored views;
@param v
*/
public void removeIgnoredView(View v) {
ignoredViews.remove(v);
}
/**
Clear the ignored view list;
*/
public void clearIgnoredViewList() {
ignoredViews.clear();
}
/**
If the motion event was relative to the view
which in ignored view list,return true;
@param ev
@return
*/
private boolean isInIgnoredView(MotionEvent ev) {
Rect rect = new Rect();
for (View v : ignoredViews) {
v.getGlobalVisibleRect(rect);
if (rect.contains((int) ev.getX(), (int) ev.getY()))
return true;
}
return false;
}
public int getScreenHeight() {
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.heightPixels;
}
public int getScreenWidth() {
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
public void setScaleValue(float scaleValue) {
this.mScaleValue = scaleValue;
}
public void setUse3D(boolean use3D) {
mUse3D = use3D;
}
public interface OnMenuListener {
/**
* This method will be called at the finished time of opening menu animations.
*/
public void openMenu();
/**
* This method will be called at the finished time of closing menu animations.
*/
public void closeMenu();
Download the library and replace ResideMenu class with given below code.
package com.special.ResideMenu;
import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.os.Build; import android.util.DisplayMetrics; import android.view.; import android.view.animation.AnimationUtils; import android.widget.;
import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.AnimatorSet; import com.nineoldandroids.animation.ObjectAnimator; import com.nineoldandroids.view.ViewHelper;
import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List;
/**
Mail: specialcyci@gmail.com */ public class ResideMenu extends FrameLayout {
public static final int DIRECTION_LEFT = 0; public static final int DIRECTION_RIGHT = 1; private static final int PRESSED_MOVE_HORIZONTAL = 2; private static final int PRESSED_DOWN = 3; private static final int PRESSED_DONE = 4; private static final int PRESSED_MOVE_VERTICAL = 5;
private ImageView imageViewShadow; private ImageView imageViewBackground; private LinearLayout layoutLeftMenu; private LinearLayout layoutRightMenu; private View scrollViewLeftMenu; private View scrollViewRightMenu; private View scrollViewMenu; private Context mContext; /**
private boolean mUse3D; private static final int ROTATE_Y_ANGLE = 10;
public ResideMenu(Context context) { super(context); mContext=context; initViews(context, -1, -1);
}
/**
private void initViews(Context context, int customLeftMenuId, int customRightMenuId) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.residemenu_custom, this);
}
/**
/**
@Override protected boolean fitSystemWindows(Rect insets) { // Applies the content insets to the view's padding, consuming that // content (modifying the insets to be 0), // and returning true. This behavior is off by default and can be // enabled through setFitsSystemWindows(boolean) // in api14+ devices.
}
public static Point getAppUsableScreenSize(Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); Point size = new Point(); display.getSize(size); return size; }
public static Point getRealScreenSize(Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); Point size = new Point();
}
private int getNavigationBarHeight() { Resources resources = getResources(); int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { return resources.getDimensionPixelSize(resourceId); } return 0; }
/**
private void initValue(Activity activity) { this.activity = activity; leftMenuItems = new ArrayList();
rightMenuItems = new ArrayList();
ignoredViews = new ArrayList();
viewDecor = (ViewGroup) activity.getWindow().getDecorView();
viewActivity = new TouchDisableView(this.activity);
}
private void setShadowAdjustScaleXByOrientation() { int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { shadowAdjustScaleX = 0.034f; shadowAdjustScaleY = 0.12f; } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { shadowAdjustScaleX = 0.06f; shadowAdjustScaleY = 0.07f; } }
/**
/**
/**
/**
/**
/**
private void rebuildMenu() { if (layoutLeftMenu != null) { layoutLeftMenu.removeAllViews(); for (ResideMenuItem leftMenuItem : leftMenuItems) layoutLeftMenu.addView(leftMenuItem); }
}
/**
/**
/**
public OnMenuListener getMenuListener() { return menuListener; }
/**
Show the menu; */ public void openMenu(int direction) {
setScaleDirection(direction);
isOpened = true; AnimatorSet scaleDown_activity = buildScaleDownAnimation(viewActivity, mScaleValue, mScaleValue); AnimatorSet scaleDown_shadow = buildScaleDownAnimation(imageViewShadow, mScaleValue + shadowAdjustScaleX, mScaleValue + shadowAdjustScaleY); AnimatorSet alpha_menu = buildMenuAnimation(scrollViewMenu, 1.0f); scaleDown_shadow.addListener(animationListener); scaleDown_activity.playTogether(scaleDown_shadow); scaleDown_activity.playTogether(alpha_menu); scaleDown_activity.start(); }
/**
Close the menu; */ public void closeMenu() {
isOpened = false; AnimatorSet scaleUp_activity = buildScaleUpAnimation(viewActivity, 1.0f, 1.0f); AnimatorSet scaleUp_shadow = buildScaleUpAnimation(imageViewShadow, 1.0f, 1.0f); AnimatorSet alpha_menu = buildMenuAnimation(scrollViewMenu, 0.0f); scaleUp_activity.addListener(animationListener); scaleUp_activity.playTogether(scaleUp_shadow); scaleUp_activity.playTogether(alpha_menu); scaleUp_activity.start(); }
@Deprecated public void setDirectionDisable(int direction) { disabledSwipeDirection.add(direction); }
public void setSwipeDirectionDisable(int direction) { disabledSwipeDirection.add(direction); }
private boolean isInDisableDirection(int direction) { return disabledSwipeDirection.contains(direction); }
private void setScaleDirection(int direction) {
}
/**
private OnClickListener viewActivityOnClickListener = new OnClickListener() { @Override public void onClick(View view) { if (isOpened()) closeMenu(); } };
private Animator.AnimatorListener animationListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { if (isOpened()) { showScrollViewMenu(scrollViewMenu); if (menuListener != null) menuListener.openMenu(); } }
};
/**
@return */ private AnimatorSet buildScaleDownAnimation(View target, float targetScaleX, float targetScaleY) {
AnimatorSet scaleDown = new AnimatorSet(); scaleDown.playTogether( ObjectAnimator.ofFloat(target, "scaleX", targetScaleX), ObjectAnimator.ofFloat(target, "scaleY", targetScaleY) );
if (mUse3D) { int angle = scaleDirection == DIRECTION_LEFT ? -ROTATE_Y_ANGLE : ROTATE_Y_ANGLE; scaleDown.playTogether(ObjectAnimator.ofFloat(target, "rotationY", angle)); }
scaleDown.setInterpolator(AnimationUtils.loadInterpolator(activity, android.R.anim.decelerate_interpolator)); scaleDown.setDuration(250); return scaleDown; }
/**
@return */ private AnimatorSet buildScaleUpAnimation(View target, float targetScaleX, float targetScaleY) {
AnimatorSet scaleUp = new AnimatorSet(); scaleUp.playTogether( ObjectAnimator.ofFloat(target, "scaleX", targetScaleX), ObjectAnimator.ofFloat(target, "scaleY", targetScaleY) );
if (mUse3D) { scaleUp.playTogether(ObjectAnimator.ofFloat(target, "rotationY", 0)); }
scaleUp.setDuration(250); return scaleUp; }
private AnimatorSet buildMenuAnimation(View target, float alpha) {
}
/**
/**
/**
/**
private void setScaleDirectionByRawX(float currentRawX) { if (currentRawX < lastRawX) setScaleDirection(DIRECTION_RIGHT); else setScaleDirection(DIRECTION_LEFT); }
private float getTargetScale(float currentRawX) { float scaleFloatX = ((currentRawX - lastRawX) / getScreenWidth()) * 0.75f; scaleFloatX = scaleDirection == DIRECTION_RIGHT ? -scaleFloatX : scaleFloatX;
}
private float lastActionDownX, lastActionDownY;
@Override public boolean dispatchTouchEvent(MotionEvent ev) { float currentActivityScaleX = ViewHelper.getScaleX(viewActivity); if (currentActivityScaleX == 1.0f) setScaleDirectionByRawX(ev.getRawX());
}
public int getScreenHeight() { activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.heightPixels; }
public int getScreenWidth() { activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); return displayMetrics.widthPixels; }
public void setScaleValue(float scaleValue) { this.mScaleValue = scaleValue; }
public void setUse3D(boolean use3D) { mUse3D = use3D; }
public interface OnMenuListener {
}
private void showScrollViewMenu(View scrollViewMenu) { if (scrollViewMenu != null && scrollViewMenu.getParent() == null) { addView(scrollViewMenu); } }
private void hideScrollViewMenu(View scrollViewMenu) { if (scrollViewMenu != null && scrollViewMenu.getParent() != null) { removeView(scrollViewMenu); } } }
Originally posted by @niteshsirohi1 in https://github.com/SpecialCyCi/AndroidResideMenu/issues/127#issuecomment-298280467