Android 高仿QQ HD mini左右滑动菜单栏效果

来源:互联网 发布:中南大学教务网络平台 编辑:程序博客网 时间:2024/05/16 01:45

Android 高仿QQ HD mini左右滑动菜单栏,动画逼真。首先来看看几张效果图:

1.进入程序时,首先显示中间菜单,即QQHD mini的最近会话列表。

Android 高仿QQ HD mini左右滑动菜单栏效果

2.向左滑动,或者点击左上角图标,可以展开左边菜单栏,即QQ HD mini的好友列表,有动画效果。

Android 高仿QQ HD mini左右滑动菜单栏效果

3.向右滑动或者点击右上角图标,可以展开右边菜单,即QQ HD mini的设置之类的布局,这里我放了一个自定义view,作为例子。

Android 高仿QQ HD mini左右滑动菜单栏效果

下面让我们来看看最重要的那个自定义view的源码:

/** 
* 可左右切换菜单栏的LinearLayout 

* @author way 

*/ 
public class CenterLayout extends LinearLayout {

private final static String TAG = "CenterLayout";

public static final int LEFT = 0x001;// 当前显示左菜单栏

public static final int RIGHT = 0x002;// 当前显示右菜单栏

public static final int MIDDLE = 0x000;// 当前显示中间主界面

private int mCurState = MIDDLE;// 当前显示的view

public final int MENU_border_Width = 50;// 边栏宽度

private Scroller mScroller;

private LinearLayout leftLayout, rightLayout, childLayout;

private Context context;

private boolean fling;

private boolean mIsBeingDragged = false;

private int mTouchSlop; 
/** 
* Position of the last motion event. 
*/ 
private float mLastMotionX, mLastMotionY;

/** 
* ID of the active pointer. This is used to retain consistency during 
* drags/flings if multiple pointers are used. 
*/ 
private int mActivePointerId = INVALID_POINTER;

/** 
* Sentinel value for no current active pointer. Used by 
* {@link #mActivePointerId}. 
*/ 
private static final int INVALID_POINTER = -1;

int menuWidth = 0; 
int moveWidth = 0;

// 3个构造器 
public CenterLayout(Context context, AttributeSet attrs) { 
super(context, attrs); 
initView(context); 
}

public CenterLayout(Context context) { 
super(context); 
initView(context); 
}

public Scroller getScroller() { 
return mScroller; 
}

// 初始化view 
public void initView(Context context) { 
this.context = context; 
this.menuWidth = MENU_border_Width; 
this.mScroller = new Scroller(context, AnimationUtils.loadInterpolator( 
context, android.R.anim.overshoot_interpolator));

final ViewConfiguration configuration = ViewConfiguration.get(context); 
mTouchSlop = configuration.getScaledTouchSlop(); 
mCurState = MIDDLE;// 初始化默认状态 
}

/** 
* 获取屏幕宽度 

* @param context 
* @return 
*/ 
private int getViewWidthInPix(Context context) { 
int viewWidthInPix = -1; 
if (viewWidthInPix == -1) { 
WindowManager manager = (WindowManager) context 
.getSystemService(Context.WINDOW_SERVICE); 
viewWidthInPix = manager.getDefaultDisplay().getWidth(); 

return viewWidthInPix; 
}

@Override 
protected void onLayout(boolean changed, int left, int top, int right, 
int bottom) { 
super.onLayout(changed, left, top, right, bottom);

for (int i = 0; i < getChildCount(); i++) { 
View child = getChildAt(i); 
child.layout(child.getLeft() + moveWidth, child.getTop(), 
child.getRight() + moveWidth, child.getBottom()); 
}

}

@Override 
public void computeScroll() { 
if (mScroller.computeScrollOffset()) { 
scrollTo(mScroller.getCurrX(), 0); 
postInvalidate(); 

}

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
// TODO Auto-generated method stub 
// Log.i(TAG, "onInterceptTouchEvent------>" + ev.getAction()); 
final int action = ev.getAction(); 
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { 
return true;// 拦截不传递给child view 
}

switch (action & MotionEvent.ACTION_MASK) { 
case MotionEvent.ACTION_DOWN: { 
final float x = ev.getX(); 
final float y = ev.getY(); 
if (!inChild((int) x, (int) y)) { 
mIsBeingDragged = false; 
break; 
// 超出边界,return false传递给子view处理 
}

/* 
* Remember location of down touch. ACTION_DOWN always refers to 
* pointer index 0. 
*/ 
mLastMotionX = x; 
mLastMotionY = y; 
mActivePointerId = ev.getPointerId(0);

/* 
* If being flinged and user touches the screen, initiate drag; 
* otherwise don't. mScroller.isFinished should be false when being 
* flinged. 
*/ 
mIsBeingDragged = !mScroller.isFinished(); 
break; 

case MotionEvent.ACTION_MOVE: { 
/* 
* mIsBeingDragged == false, otherwise the shortcut would have 
* caught it. Check whether the user has moved far enough from his 
* original down touch. 
*/

/* 
* Locally do absolute value. mLastMotionY is set to the y value of 
* the down event. 
*/ 
final int activePointerId = mActivePointerId; 
if (activePointerId == INVALID_POINTER) { 
// If we don't have a valid id, the touch down wasn't on 
// content. 
break; 
}

final int pointerIndex = ev.findPointerIndex(activePointerId); 
final float x = ev.getX(pointerIndex); 
final float y = ev.getY(pointerIndex); 
final int xDiff = (int) Math.abs(x - mLastMotionX); 
final int yDiff = (int) Math.abs(y - mLastMotionY); 
if (xDiff > mTouchSlop && yDiff < xDiff) { 
mIsBeingDragged = true; 

break; 

case MotionEvent.ACTION_CANCEL: 
case MotionEvent.ACTION_UP: 
mIsBeingDragged = false; 
mActivePointerId = INVALID_POINTER; 
scrollToScreen(); 
break; 

return mIsBeingDragged; 
}

@Override 
public boolean onTouchEvent(MotionEvent event) {

// Log.i(TAG, "onTouchEvent ---->>>>>" + event.getAction()); 
if (event.getAction() == MotionEvent.ACTION_DOWN 
&& !inChild((int) event.getX(), (int) event.getY())) { 
// Don't handle edge touches immediately -- they may actually belong 
// to one of our 
// descendants. 
return false; 
}

switch (event.getAction() & MotionEvent.ACTION_MASK) { 
case MotionEvent.ACTION_DOWN: 
return true; // 本VIEW消化掉

case MotionEvent.ACTION_MOVE: 
final int activePointerIndex = event 
.findPointerIndex(mActivePointerId);

final float x = event.getX(activePointerIndex); 
final float y = event.getY(activePointerIndex);

final int distanceX = (int) /* Math.abs */-(x - mLastMotionX);

// 在滑动过程中,就需要显示新的brotherView,不然显示的还是之前的brotherView,最后松开手时会突然变称新brotherView,影响体验 
if (distanceX < 0 && getScrollX() < 0 && leftLayout != null) { 
setBrotherVisibility(LEFT); 
} else if (distanceX > 0 && getScrollX() > 0 && rightLayout != null) { 
setBrotherVisibility(RIGHT); 
} else { 
setBrotherVisibility(MIDDLE); 
}

scrollBy((int) distanceX, 0);

mLastMotionX = x; 
mLastMotionY = y; 
break;

case MotionEvent.ACTION_UP: 
mIsBeingDragged = false; 
mActivePointerId = INVALID_POINTER; 
scrollToScreen(); 
break;

default: 
return super.onTouchEvent(event); 

return mIsBeingDragged;

}

@Override 
protected void onScrollChanged(int l, int t, int oldl, int oldt) { 
// TODO Auto-generated method stub 
super.onScrollChanged(l, t, oldl, oldt); 
}

private void scrollToScreen() {

int scrollDistance = 0;

if (Math.abs(getScrollX()) > getWidth() / 2) 
scrollDistance = (getScrollX() > 0) ? getWidth() - menuWidth 
- getScrollX() : -(getWidth() - menuWidth - Math 
.abs(getScrollX())); 
else 
scrollDistance = -getScrollX();

int distance = scrollDistance + getScrollX(); 
Log.i(TAG, " distance = " + distance); 
if (distance > 0) { 
mCurState = RIGHT; 
} else if (distance < 0) { 
mCurState = LEFT; 
} else { 
mCurState = MIDDLE; 

mScroller.startScroll(getScrollX(), 0, scrollDistance, 0, 
Math.abs(scrollDistance) * 2); 
invalidate();

}

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
float velocityY) { 
if (Math.abs(velocityX) > ViewConfiguration.get(context) 
.getScaledMinimumFlingVelocity()) { 
fling = true; 
scrollToScreen(); 
}

return fling; 
}

private boolean inChild(int x, int y) { 
if (getChildCount() > 0) { 
final int scrollX = mScroller.getCurrX(); 
final View child = getChildAt(0);

return !(scrollX + x < 0 || scrollX + x > getWidth() || y < 0 || y > getHeight());


return false; 
}

/** 
* 设置当前显示的view 

* @param whichpg 
*/ 
public void setPage(int whichpg) { 
int targetX = 0, moveDistance = 0;

if (whichpg == LEFT) { 
targetX = -(getViewWidthInPix(context) - menuWidth); 
mCurState = LEFT; 
} else if (whichpg == RIGHT) { 
targetX = getViewWidthInPix(context) - menuWidth; 
mCurState = RIGHT; 
} else { 
mCurState = MIDDLE; 

setBrotherVisibility(whichpg); 
moveDistance = targetX - getScrollX(); 
mScroller.startScroll(getScrollX(), 0, moveDistance, 0, 
Math.abs(moveDistance) * 2); 
invalidate(); 
}

/** 
* 返回当前显示的view 

* @return 
*/ 
public int getPage() { 
return mCurState; 
}

public void addChildView(View child) { 
this.childLayout.addView(child); 
}

/** 
* 设置BrotherView 

* @param left 
* @param right 
*/ 
public void setBrotherLayout(LinearLayout left, LinearLayout right) { 
this.leftLayout = left; 
this.rightLayout = right; 
}

/** 
* 根据当前状态显示或隐藏view 

* @param state 
*/ 
private void setBrotherVisibility(int state) { 
switch (state) { 
case LEFT: 
rightLayout.setVisibility(View.GONE); 
leftLayout.setVisibility(View.VISIBLE); 
break; 
case RIGHT: 
rightLayout.setVisibility(View.VISIBLE); 
leftLayout.setVisibility(View.GONE); 
break; 
case MIDDLE: 
break; 
default: 
break; 


}

好了,高仿QQ HD mini左右滑动菜单栏效果 源码地址:

免费下载地址在 http://linux.linuxidc.com/

用户名与密码都是www.linuxidc.com

具体下载目录在 /2013年资料/5月/2日/高仿QQ HD mini左右滑动菜单栏效果



转自:http://www.linuxidc.com/Linux/2013-05/83724.htm

0 0