您的位置:首页 > 其它

解决ResizeMenu与viewpager滑动冲突

2014-12-29 13:56 190 查看
ResizeMenu实现了QQ5.0的侧边栏效果,很是炫丽,只可惜我使用的时候出现了一些小问题,记录如下:

我是将ResizeMenu与viewPager搭配一起使用,这一搭配问题就来了,我稍微一滑动,侧边栏就出来了,可实际上我只是想切换tab,滑动监听的事完全被ResizeMenu抢去了。

又是一番痛苦的百度后,发现ResizeMenu根本就没有像SlidingMenu一样可以设置边缘滑动触发的属性,没办法了,只好来查看源码看看能不能修改啦。

在源码中切换的动作主要放在dispatchTouchEvent(MotionEvent ev)中,既然要实现边缘触发,那么不在边缘的触发我就直接忽略掉算了,带着这样的想法,我在ACTION_DOWN事件中加了如下判断,不过这个判断要先取得屏幕的宽度:

@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:
if(ev.getX()>50&&ev.getX()<mScreenWidth-50){//修改为边缘触发滑动
//此处为空,不需要添加代码
}else{
lastActionDownX = ev.getX();
lastActionDownY = ev.getY();
isInIgnoredView = isInIgnoredView(ev) && !isOpened();
pressedState    = PRESSED_DOWN;
}
break;


取得屏幕宽度的代码可以放在这里(attachToActivity),下面代码最后几句代码就是获取屏幕的大小:

public void attachToActivity(Activity activity){
initValue(activity);
setShadowAdjustScaleXByOrientation();
viewDecor.addView(this, 0);
}

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

//设置屏幕的大小
DisplayMetrics metric = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
mScreenWidth = metric.widthPixels;
mScreenHeight = metric.heightPixels;
}


这么几句简单的修改后,ResizeMenu就可以变成边缘触发了,最后还是把修改后ResizeMenu.java的代码公布一下(图省事就可以直接复制粘贴拿去用了):
package com.special.ResideMenu;

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.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;

/**
* 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;
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 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 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;

//屏幕宽高
private int mScreenWidth;
private int mScreenHeight;

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

@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.
this.setPadding(viewActivity.getPaddingLeft() + insets.left, viewActivity.getPaddingTop() + insets.top,
viewActivity.getPaddingRight() + insets.right, viewActivity.getPaddingBottom() + insets.bottom);
insets.left = insets.top = insets.right = insets.bottom = 0;
return true;
}

/**
* 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);
}

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

//设置屏幕的大小
DisplayMetrics metric = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
mScreenWidth = metric.widthPixels;
mScreenHeight = metric.heightPixels;
}

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){
if (isVisible)
imageViewShadow.setBackgroundResource(R.drawable.shadow);
else
imageViewShadow.setBackgroundResource(0);
}

/**
* 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;
}

/**
* 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(scrollViewMenu);
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(scrollViewLeftMenu);
hideScrollViewMenu(scrollViewRightMenu);
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: if(ev.getX()>50&&ev.getX()<mScreenWidth-50){//修改为边缘触发滑动 //此处为空,不需要添加代码 }else{ 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(scrollViewMenu);

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(ScrollView scrollViewMenu){
if (scrollViewMenu != null && scrollViewMenu.getParent() == null){
addView(scrollViewMenu);
}
}

private void hideScrollViewMenu(ScrollView scrollViewMenu){
if (scrollViewMenu != null && scrollViewMenu.getParent() != null){
removeView(scrollViewMenu);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: