轉載請標明原地址:[http://blog.csdn.net/gaolei1201/article/details/50404941](http://blog.csdn.net/gaolei1201/article/details/50404941)
首先介紹本篇文章的重點:
1.視覺差側滑菜單,即菜單和主界面都滑動,其實也比較常見。有開源項目SlidingMenu,但太復雜了,且在我使用過程中無法完美實現透明狀態欄,中間會有一條分割線。看我簡單實現
2.Activity視覺差動畫
3.支持側滑銷毀Activity,且不用擔心被子控件消耗手勢監聽事件
其實我也是借鑒別人的,自己發明創造畢竟畢竟困難。正所謂天下文章一大抄,看你會抄不會抄,呵呵。
這里側滑菜單SlidingMenu繼承HorizontalScrollView,手勢滑動。還有一種方法時繼承ViewGroup,放入菜單和內容兩個子控件,根據手勢滑動。
效果圖:

下面是側滑菜單主要代碼,里面有注釋:
~~~
<span style="font-size:14px;">package com.gaolei.slidingmenu;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.example.zhy_slidingmenu.R;
import com.nineoldandroids.view.ViewHelper;
public class SlidingMenu extends HorizontalScrollView {
/**
* 屏幕寬度
*/
private int mScreenWidth;
/**
* dp
*/
private int mMenuRightPadding;
/**
* 菜單的寬度
*/
private int mMenuWidth;
private int mHalfMenuWidth;
public static boolean isOpen;
private boolean once;
private ViewGroup mMenu;
private ViewGroup mContent;
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
WindowManager mWM = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE));
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
mWM.getDefaultDisplay().getMetrics(mDisplayMetrics);
mScreenWidth = mDisplayMetrics.widthPixels;
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.SlidingMenu, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
// 默認50
mMenuRightPadding = a.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50f,
getResources().getDisplayMetrics()));// 默認為10DP
// Log.d("gaolei","mMenuRightPadding-------------"+mMenuRightPadding);
break;
}
}
a.recycle();
}
public SlidingMenu(Context context) {
this(context, null, 0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 顯示的設置一個寬度
*/
if (!once) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) wrapper.getChildAt(0);
mContent = (ViewGroup) wrapper.getChildAt(1);
mMenuWidth = mScreenWidth - mMenuRightPadding;
mHalfMenuWidth = mMenuWidth / 2;
mMenu.getLayoutParams().width = mMenuWidth;
mContent.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 將菜單隱藏
this.scrollTo(mMenuWidth, 0);
once = true;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
// Up時,進行判斷,如果顯示區域大于菜單寬度一半則完全顯示,否則隱藏
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
if (scrollX > mHalfMenuWidth) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
MainActivity.shadow_layout.setVisibility(View.GONE);
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
MainActivity.shadow_layout.setVisibility(View.VISIBLE);
}
return true;
case MotionEvent.ACTION_MOVE:
break;
}
return super.onTouchEvent(ev);
}
// 這里是攔截菜單布局滑動
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
if (curY > 0 && curY < 500) {
return false;
}
if (isOpen && curX < mMenuWidth) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
/**
* 打開菜單
*/
public void openMenu() {
if (isOpen)
return;
this.smoothScrollTo(0, 0);
isOpen = true;
MainActivity.shadow_layout.setVisibility(View.VISIBLE);
}
/**
* 關閉菜單
*/
public void closeMenu() {
if (isOpen) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
MainActivity.shadow_layout.setVisibility(View.GONE);
}
}
/**
* 切換菜單狀態
*/
public void toggle() {
if (isOpen) {
closeMenu();
} else {
openMenu();
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenuWidth;
~~~
~~~
//這段代碼是最重要的調用nineoldandroids。jar 來實現菜單視覺差效果,自己可改動 0.7f 試試
ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.7f);
}
}
</span>
~~~
下面要講一下,手勢滑動Activity邊緣銷毀Activity,主要難點是:里面子控件會攔截手勢事件使你監聽不到,那么你也就不能觸發銷毀Activity,看看哥是咋弄的
~~~
<span style="font-size:14px;">/**
* 自定義RelativeLayout 攔截ListView監聽事件
*/
public class CustomRelativeLayout extends RelativeLayout {
private FinishActivityListener finishActivityListener;
private int downX;
public void setFinishActivityListener(FinishActivityListener finishActivityListener) {
this.finishActivityListener = finishActivityListener;
}
public CustomRelativeLayout(Context context) {
super(context);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//onTouchEvent()是獲取不到手勢事件的,因為被ListView消耗了;只有在這判斷手勢監聽事件 ,才能提前ListView獲得
public boolean onInterceptTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//說明將onTouch攔截在此控件,進而執行此控件的onTouchEvent
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
Log.d("gaolei", "moveX-----------------" + moveX);
Log.d("gaolei", "downX-----------------" + downX);
//這里是判斷最小滑動5,然后滑動邊緣0~50彩觸發銷毀Activity,滑動屏幕中間不銷毀
if (moveX - downX > 5 && downX < 50) {
finishActivityListener.onFinishActivity();
}
break;
}
return super.onInterceptTouchEvent(event);
}
}
</span>
~~~
[源碼地址,點擊下載......](https://github.com/gaoleiandroid1201/ParallaxSlidingMenu)