package external.residemenu; import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Build; import android.view.*; import android.view.animation.AnimationUtils; import android.widget.AdapterView.OnItemClickListener; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ScrollView; import java.util.ArrayList; import java.util.List; import com.aiyou.R; import com.aiyou.utils.AiYouManager; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.AnimatorSet; import com.nineoldandroids.animation.ObjectAnimator; import com.nineoldandroids.view.ViewHelper; /** * User: special Date: 13-12-10 Time: 下午10:44 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_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; /** * 自己加的 */ @SuppressWarnings("unused") private Context context; private int nScreenWidth = 0; private int nScreenHeight = 0; // private int nTotalDistance = 0; // private int nCurrentDistance = 0; // private Handler handler = new Handler(); // private Runnable runnableOpen, runnableClose; private LinearLayout layoutLeftMenu; // private LinearLayout layoutRightMenu; private ScrollView scrollViewLeftMenu; // private ScrollView scrollViewRightMenu; private LinearLayout mRightMenuLLayout; private ListView mRightLV; private View 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 GestureDetector gestureDetector; 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 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); } @SuppressWarnings("deprecation") private void initViews(Context context) { this.context = context; Rect frame = new Rect(); ((Activity) context).getWindow().getDecorView() .getWindowVisibleDisplayFrame(frame); nScreenWidth = AiYouManager.getScreenWidth(); nScreenHeight = AiYouManager.getScreenHeight() - frame.top; if (nScreenWidth == 0 || nScreenHeight == 0) { WindowManager manager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); nScreenWidth = display.getWidth(); nScreenHeight = display.getHeight() - frame.top; } // runnableOpen = new Runnable() { // @Override // public void run() { // Matrix matrix = new Matrix(); // if (nCurrentDistance < 0) { // nCurrentDistance = 0; // } // nCurrentDistance += 20; // if (nCurrentDistance >= nTotalDistance) { // handler.removeCallbacks(this); // } else { // matrix.postTranslate(nCurrentDistance - nTotalDistance, 0); // imageViewBackground.setImageMatrix(matrix); // handler.postDelayed(this, 10); // } // } // }; // runnableClose = new Runnable() { // @Override // public void run() { // Matrix matrix = new Matrix(); // if (nCurrentDistance > 0) { // nCurrentDistance = 0; // } // nCurrentDistance -= 20; // if (nCurrentDistance <= -nTotalDistance) { // handler.removeCallbacks(this); // } else { // matrix.postTranslate(nCurrentDistance, 0); // imageViewBackground.setImageMatrix(matrix); // handler.postDelayed(this, 10); // } // } // }; 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); mRightMenuLLayout = (LinearLayout)findViewById(R.id.right_menu); mRightLV = (ListView)findViewById(R.id.listview); 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); } 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.setScaleType(ScaleType.CENTER_CROP); imageViewBackground.setImageResource(imageResrouce); // Drawable drawable = context.getResources().getDrawable(imageResrouce); // Bitmap bmp = ((BitmapDrawable) drawable).getBitmap(); // int nWidth = bmp.getWidth() * nScreenHeight / bmp.getHeight(); // if (nWidth <= nScreenWidth) { // imageViewBackground.setScaleType(ScaleType.CENTER_CROP); // imageViewBackground.setImageResource(imageResrouce); // return; // } else { // imageViewBackground.setScaleType(ScaleType.MATRIX); //// nTotalDistance = nWidth - nScreenWidth; //// nCurrentDistance = nTotalDistance; // Bitmap bmpBg = Bitmap.createScaledBitmap(bmp, nWidth, // nScreenHeight, true); // imageViewBackground.setImageBitmap(bmpBg); // Matrix matrix = new Matrix(); //// matrix.postTranslate(-nTotalDistance, 0); // imageViewBackground.setImageMatrix(matrix); // } } public void setBackgroundColor(int color) { imageViewBackground.setScaleType(ScaleType.CENTER_CROP); imageViewBackground.setBackgroundColor(color); } /** * the visiblity of shadow under the activity view; * * @param isVisible */ public void setShadowVisible(boolean isVisible) { if (isVisible) { imageViewShadow.setVisibility(View.VISIBLE); imageViewShadow.setImageResource(R.drawable.shadow); } else // imageViewShadow.setImageBitmap(null); imageViewShadow.setVisibility(View.GONE); } /** * add a single items to left menu; * * @param menuItem */ 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); } } public void setAdapter(ListAdapter adapter) { mRightLV.setAdapter(adapter); } public void setOnItemClickListener(OnItemClickListener listener) { mRightLV.setOnItemClickListener(listener); } /** * 增加分隔线 * * @param context * @param height 线高度 * @param strColor 颜色 */ public void addSeparator(Context context, int height, String strColor) { ResideMenuItem item = new ResideMenuItem(context, height, strColor, null); leftMenuItems.add(item); layoutLeftMenu.addView(item); } /** * 清空 */ public void removeAllLeftMenuItem() { leftMenuItems.clear(); layoutLeftMenu.removeAllViews(); } /** * 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(); // handler.post(runnableOpen); } /** * 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(); // handler.post(runnableClose); } @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 = mRightMenuLLayout; 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()) { scrollViewMenu.setVisibility(VISIBLE); if (menuListener != null) menuListener.openMenu(); } } @Override public void onAnimationEnd(Animator animation) { // reset the view; if (isOpened()) { viewActivity.setTouchDisable(true); if (Build.VERSION.SDK_INT > 11) { viewActivity.setOnClickListener(viewActivityOnClickListener); } } else { viewActivity.setTouchDisable(false); if (Build.VERSION.SDK_INT > 11) { viewActivity.setOnClickListener(null); } scrollViewMenu.setVisibility(GONE); 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: // handler.removeCallbacks(runnableClose); // handler.removeCallbacks(runnableOpen); 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); // nCurrentDistance = nTotalDistance * xOffset / nScreenWidth; // // if (nCurrentDistance < -nTotalDistance) { // nCurrentDistance = -nTotalDistance; // } // if (nCurrentDistance > nTotalDistance) { // nCurrentDistance = nTotalDistance; // } // // Matrix matrix = new Matrix(); // if (!isOpened) { // if (nCurrentDistance < 0) { // nCurrentDistance = 0; // } // matrix.postTranslate(nCurrentDistance - nTotalDistance, 0); // } else { // if (nCurrentDistance > 0) { // nCurrentDistance = 0; // } // matrix.postTranslate(nCurrentDistance, 0); // } // imageViewBackground.setImageMatrix(matrix); 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) scrollViewMenu.setVisibility(VISIBLE); 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() { return nScreenHeight; } public int getScreenWidth() { return nScreenWidth; } 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(); } }