SlidingMenu視覺差動畫簡單版和Activity視覺差動畫 [復制鏈接]

2018-10-18 10:04
hellokenken 閱讀:720 評論:0 贊:0
Tag:  
首先介紹本篇文章的重點:

1.視覺差側滑菜單,即菜單和主界面都滑動,其實也比較常見。有開源項目SlidingMenu,但太復雜了,且在我使用過程中無法完美實現透明狀態欄,中間會有一條分割線。看我簡單實現

2.Activity視覺差動畫

3.支持側滑銷毀Activity,且不用擔心被子控件消耗手勢監聽事件



其實我也是借鑒別人的,自己發明創造畢竟畢竟困難。正所謂天下文章一大抄,看你會抄不會抄,呵呵。

第一種方法:側滑菜單SlidingMenu繼承HorizontalScrollView,手勢滑動。

第二種方法 :側滑菜單SlidingMenu繼承ViewGroup,放入菜單和內容兩個子控件,根據手勢滑動。

第三種方法:利用ViewDragHelper。

效果圖:


        

下面是第一種方法側滑菜單主要代碼,里面有注釋:

[代碼]java代碼:

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

下面是第二種方法SlidingMenu自定義ViewGroup實現方法:

[代碼]java代碼:

public class SlideLayout extends ViewGroup {
	private static String TAG = "SlideMenuLayout";
	
	private Context mContext;
	private Scroller mScroller;    //Android 提供的滑動輔助類
	private int mTouchSlop = 0 ;    //在被判定為滾動之前用戶手指可以移動的最大值
	private VelocityTracker mVelocityTracker;    //用于計算手指滑動的速度
	public static final int SNAP_VELOCITY = 200;    //滾動顯示和隱藏左側布局時,手指滑動需要達到的速度:每秒200個像素點
	private int mMaxScrollX = 0;    //最大滾動距離,等于menu的寬度
	private int menuWidth=0;
	private int scrollX=0;
	private int oldX;
	public static boolean clickMenuToClose=false;
	
	public void setMaxScrollX(int maxScrollX) {
		this.mMaxScrollX = maxScrollX;
	}
 
	private float mDownX;    //一次按下抬起的動作中,按下時的X坐標,用于和抬起時的X比較,判斷移動距離。少于mTouchSlop則判定為原地點擊
	private float mLastX;    //記錄滑動過程中的X坐標
	
	private boolean isMenuOpen = false;    //菜單界面是否被打開,只有完全打開才為true
	public boolean isMenuOpen() {
		return isMenuOpen;
	}
 
	private boolean isTouchFinished = true;
	
	private View mContent;
	
	public SlideLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		init();
	}
	
	private void init() {
		Log.v(TAG, "init start");
		mScroller = new Scroller(mContext);
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
	}
 
	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			scrollX=mScroller.getCurrX();
//			這里是判斷打開菜單時即向右滑動菜單向右滑動 實現視覺差滑動效果,scrollX就是監聽startScroll開始滾動程X的值,因為getScrollX()只是監聽手在屏幕上滑動的過程,手離開后就要在這里監聽,0.7是可以根據需求改動
			if(scrollX 0){
				deltaX = -curScrollX;
			}
//			這里是判斷打手勢滑動開菜單時即向右滑動菜單向右滑動 實現視覺差滑動效果,menuWidth+getScrollX()是菜單滑動時X的變化,手離開后就要在這里監聽,0.7是可以根據需求改動
		
			
			if (deltaX != 0) {
				scrollBy(deltaX, 0);
			}
			//這句話一定要放到scrollBy后面 不然你快速滑動左邊會有空白閃現
                       ViewHelper.setTranslationX(getChildAt(0), (menuWidth+getScrollX())* 0.7f);


下面要講一下,手勢滑動Activity邊緣銷毀Activity,主要難點是:里面子控件會攔截手勢事件使你監聽不到,那么你也就不能觸發銷毀Activity,看看哥是咋弄的

[代碼]java代碼:

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


我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

两码中特期期