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();
}
}