Back to project page android_app.
The source code is released under:
Apache License
If you think the Android project android_app listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package models; /* The MIT License (MIT) Copyright (c) 2013 SpecialCyCi//from w w w .j a v a 2s . com Modified by Dan Lin 10/3/14 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.*; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import com.example.t_danbubbletea.R; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.AnimatorSet; import com.nineoldandroids.animation.ObjectAnimator; import com.nineoldandroids.view.ViewHelper; import java.util.ArrayList; import java.util.List; 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_HORIZANTAL = 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 ScrollView scrollViewLeftMenu; private ScrollView scrollViewRightMenu; private ScrollView scrollViewMenu; /** the activity that view attach to */ private Activity activity; /** the decorview of the activity */ private ViewGroup viewDecor; /** the viewgroup of the activity */ private TouchDisableView viewActivity; /** the flag of menu open status */ private boolean isOpened; private float shadowAdjustScaleX; private float shadowAdjustScaleY; /** the view which don't want to intercept touch event */ private List<View> ignoredViews; private List<ResideMenuItem> leftMenuItems; private List<ResideMenuItem> 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<Integer> disabledSwipeDirection = new ArrayList<Integer>(); //valid scale factor is between 0.0f and 1.0f. private float mScaleValue = 0.5f; public ResideMenu(Context context) { super(context); initViews(context); } private void initViews(Context context){ LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.residemenu, this); scrollViewLeftMenu = (ScrollView) findViewById(R.id.sv_left_menu); scrollViewRightMenu = (ScrollView) findViewById(R.id.sv_right_menu); imageViewShadow = (ImageView) findViewById(R.id.iv_shadow); layoutLeftMenu = (LinearLayout) findViewById(R.id.layout_left_menu); layoutRightMenu = (LinearLayout) findViewById(R.id.layout_right_menu); imageViewBackground = (ImageView) findViewById(R.id.iv_background); } /** * use the method to set up the activity which residemenu need to show; * * @param activity */ public void attachToActivity(Activity activity){ initValue(activity); setShadowAdjustScaleXByOrientation(); viewDecor.addView(this, 0); setViewPadding(); } private void initValue(Activity activity){ this.activity = activity; leftMenuItems = new ArrayList<ResideMenuItem>(); rightMenuItems = new ArrayList<ResideMenuItem>(); ignoredViews = new ArrayList<View>(); viewDecor = (ViewGroup) activity.getWindow().getDecorView(); viewActivity = new TouchDisableView(this.activity); View mContent = viewDecor.getChildAt(0); viewDecor.removeViewAt(0); viewActivity.setContent(mContent); addView(viewActivity); ViewGroup parent = (ViewGroup) scrollViewLeftMenu.getParent(); parent.removeView(scrollViewLeftMenu); parent.removeView(scrollViewRightMenu); } 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; } } /** * set the menu background picture; * * @param imageResrouce */ public void setBackground(int imageResrouce){ imageViewBackground.setImageResource(imageResrouce); } /** * the visiblity of shadow under the activity view; * * @param isVisible */ public void setShadowVisible(boolean isVisible){ imageViewShadow.setImageBitmap(null); } /** * add a single items to left menu; * * @param menuItem */ @Deprecated public void addMenuItem(ResideMenuItem menuItem){ this.leftMenuItems.add(menuItem); layoutLeftMenu.addView(menuItem); } /** * add a single items; * * @param menuItem * @param direction */ public void addMenuItem(ResideMenuItem menuItem, int direction){ if (direction == DIRECTION_LEFT){ this.leftMenuItems.add(menuItem); layoutLeftMenu.addView(menuItem); }else{ this.rightMenuItems.add(menuItem); layoutRightMenu.addView(menuItem); } } /** * set the menu items by array list to left menu; * * @param menuItems */ @Deprecated public void setMenuItems(List<ResideMenuItem> menuItems){ this.leftMenuItems = menuItems; rebuildMenu(); } /** * set the menu items by array list; * * @param menuItems * @param direction */ public void setMenuItems(List<ResideMenuItem> menuItems, int direction){ if (direction == DIRECTION_LEFT) this.leftMenuItems = menuItems; else this.rightMenuItems = menuItems; rebuildMenu(); } private void rebuildMenu(){ layoutLeftMenu.removeAllViews(); layoutRightMenu.removeAllViews(); for(int i = 0; i < leftMenuItems.size() ; i ++) layoutLeftMenu.addView(leftMenuItems.get(i), i); for(int i = 0; i < rightMenuItems.size() ; i ++) layoutRightMenu.addView(rightMenuItems.get(i), i); } /** * get the left menu items; * * @return */ @Deprecated public List<ResideMenuItem> getMenuItems() { return leftMenuItems; } /** * get the menu items; * * @return */ public List<ResideMenuItem> getMenuItems(int direction) { if ( direction == DIRECTION_LEFT) return leftMenuItems; else return rightMenuItems; } /** * if you need to do something on the action of closing or opening * menu, set the listener here. * * @return */ public void setMenuListener(OnMenuListener menuListener) { this.menuListener = menuListener; } public OnMenuListener getMenuListener() { return menuListener; } /** * we need the call the method before the menu show, because the * padding of activity can't get at the moment of onCreateView(); */ private void setViewPadding(){ this.setPadding(viewActivity.getPaddingLeft(), viewActivity.getPaddingTop(), viewActivity.getPaddingRight(), viewActivity.getPaddingBottom()); } /** * show the reside 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 reslide 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){ int screenWidth = getScreenWidth(); float pivotX; float pivotY = getScreenHeight() * 0.5f; if (direction == DIRECTION_LEFT){ scrollViewMenu = scrollViewLeftMenu; pivotX = screenWidth * 1.5f; }else{ scrollViewMenu = scrollViewRightMenu; pivotX = screenWidth * -0.5f; } ViewHelper.setPivotX(viewActivity, pivotX); ViewHelper.setPivotY(viewActivity, pivotY); ViewHelper.setPivotX(imageViewShadow, pivotX); ViewHelper.setPivotY(imageViewShadow, pivotY); scaleDirection = direction; } /** * return the flag of menu status; * * @return */ public boolean isOpened() { return isOpened; } 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(); if (menuListener != null) menuListener.openMenu(); } } @Override public void onAnimationEnd(Animator animation) { // reset the view; if(isOpened()){ viewActivity.setTouchDisable(true); viewActivity.setOnClickListener(viewActivityOnClickListener); }else{ viewActivity.setTouchDisable(false); viewActivity.setOnClickListener(null); hideScrollViewMenu(); if (menuListener != null) menuListener.closeMenu(); } } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }; /** * a helper method to build scale down animation; * * @param target * @param targetScaleX * @param targetScaleY * @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) ); scaleDown.setInterpolator(AnimationUtils.loadInterpolator(activity, android.R.anim.decelerate_interpolator)); scaleDown.setDuration(250); return scaleDown; } /** * a helper method to build scale up animation; * * @param target * @param targetScaleX * @param targetScaleY * @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) ); scaleUp.setDuration(250); return scaleUp; } private AnimatorSet buildMenuAnimation(View target, float alpha){ AnimatorSet alphaAnimation = new AnimatorSet(); alphaAnimation.playTogether( ObjectAnimator.ofFloat(target, "alpha", alpha) ); alphaAnimation.setDuration(250); return alphaAnimation; } /** * if there ware some view you don't want reside menu * to intercept their touch event,you can use the method * to set. * * @param v */ public void addIgnoredView(View v){ ignoredViews.add(v); } /** * remove the view from ignored view list; * @param v */ public void removeIgnoredView(View v){ ignoredViews.remove(v); } /** * clear the ignored view list; */ public void clearIgnoredViewList(){ ignoredViews.clear(); } /** * if the motion evnent 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; } 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; float targetScale = ViewHelper.getScaleX(viewActivity) - scaleFloatX; targetScale = targetScale > 1.0f ? 1.0f : targetScale; targetScale = targetScale < 0.5f ? 0.5f : targetScale; return targetScale; } private float lastActionDownX, lastActionDownY; @Override public boolean dispatchTouchEvent(MotionEvent ev) { float currentActivityScaleX = ViewHelper.getScaleX(viewActivity); if (currentActivityScaleX == 1.0f) setScaleDirectionByRawX(ev.getRawX()); switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: lastActionDownX = ev.getX(); lastActionDownY = ev.getY(); isInIgnoredView = isInIgnoredView(ev) && !isOpened(); pressedState = PRESSED_DOWN; break; case MotionEvent.ACTION_MOVE: if (isInIgnoredView || isInDisableDirection(scaleDirection)) break; if(pressedState != PRESSED_DOWN && pressedState != PRESSED_MOVE_HORIZANTAL) break; int xOffset = (int) (ev.getX() - lastActionDownX); int yOffset = (int) (ev.getY() - lastActionDownY); if(pressedState == PRESSED_DOWN) { if(yOffset > 25 || yOffset < -25) { pressedState = PRESSED_MOVE_VERTICAL; break; } if(xOffset < -50 || xOffset > 50) { pressedState = PRESSED_MOVE_HORIZANTAL; ev.setAction(MotionEvent.ACTION_CANCEL); } } else if(pressedState == PRESSED_MOVE_HORIZANTAL) { if (currentActivityScaleX < 0.95) showScrollViewMenu(); float targetScale = getTargetScale(ev.getRawX()); ViewHelper.setScaleX(viewActivity, targetScale); ViewHelper.setScaleY(viewActivity, targetScale); ViewHelper.setScaleX(imageViewShadow, targetScale + shadowAdjustScaleX); ViewHelper.setScaleY(imageViewShadow, targetScale + shadowAdjustScaleY); ViewHelper.setAlpha(scrollViewMenu, (1 - targetScale) * 2.0f); lastRawX = ev.getRawX(); return true; } break; case MotionEvent.ACTION_UP: if (isInIgnoredView) break; if (pressedState != PRESSED_MOVE_HORIZANTAL) break; pressedState = PRESSED_DONE; if (isOpened()){ if (currentActivityScaleX > 0.56f) closeMenu(); else openMenu(scaleDirection); }else{ if (currentActivityScaleX < 0.94f){ openMenu(scaleDirection); }else{ closeMenu(); } } break; } lastRawX = ev.getRawX(); return super.dispatchTouchEvent(ev); } 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 interface OnMenuListener{ /** * the method will call on the finished time of opening menu's animation. */ public void openMenu(); /** * the method will call on the finished time of closing menu's animation . */ public void closeMenu(); } private void showScrollViewMenu(){ if (scrollViewMenu != null && scrollViewMenu.getParent() == null){ addView(scrollViewMenu); } } private void hideScrollViewMenu(){ if (scrollViewMenu != null && scrollViewMenu.getParent() != null){ removeView(scrollViewMenu); } } }