1. 程式人生 > >Android從上往下滑動或從下往上滑動結束Activity

Android從上往下滑動或從下往上滑動結束Activity

之前有看過xiaanming寫的側滑返回,於是仿照他的Demo,寫了這個從上往下滑動或者從下往上滑動結束Activity

先附圖一張,由於這臺電腦解析度有問題以及模擬器的緣故,先湊活看吧


先貼程式碼:

從上往下滑動:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.Scroller;

/***
 * 
 * 從上向下滑結束Activity
 * 
 * @author 帽檐遮不住陽光
 * 
 */
public class TopToBottomFinishLayout extends RelativeLayout {
	
	/**
	 * TopToBottomFinishLayout佈局的父佈局
	 */
	private ViewGroup mParentView;
	/**
	 * 滑動的最小距離
	 */
	private int mTouchSlop;
	/**
	 * 按下點的X座標
	 */
	private int downX;
	/**
	 * 按下點的Y座標
	 */
	private int downY;
	/**
	 * 臨時儲存X座標
	 */
	private int tempY;
	/**
	 * 滑動類
	 */
	private Scroller mScroller;
	/**
	 * TopToBottomFinishLayout的寬度
	 */
	private int viewHeight;

	private boolean isSilding;

	private OnFinishListener onFinishListener;
	private boolean isFinish;

	public TopToBottomFinishLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public TopToBottomFinishLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
		mScroller = new Scroller(context);
	}

	/**
	 * 事件攔截操作
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {

		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downX = (int) ev.getRawX();
			downY = tempY = (int) ev.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveY = (int) ev.getRawY();
			// 滿足此條件遮蔽SildingFinishLayout裡面子類的touch事件
			if (Math.abs(moveY - downY) > mTouchSlop
					&& Math.abs((int) ev.getRawX() - downX) < mTouchSlop) {
				return true;
			}
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_MOVE:
			int moveY = (int) event.getRawY();// 觸控點相對於螢幕的位置
			int deltaY = tempY - moveY;
			tempY = moveY;
			if (Math.abs(moveY - downY) > mTouchSlop
					&& Math.abs((int) event.getRawX() - downX) < mTouchSlop) {
				isSilding = true;
			}

			if (moveY - downY >= 0 && isSilding) {
				mParentView.scrollBy(0, deltaY);
			}
			break;
		case MotionEvent.ACTION_UP:
			isSilding = false;
			if (mParentView.getScrollY() <= -viewHeight / 3) {
				isFinish = true;
				scrollBottom();
			} else {
				scrollOrigin();
				isFinish = false;
			}
			break;
		}

		return true;
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			mParentView = (ViewGroup) this.getParent();
			viewHeight = this.getHeight();
		}
	}

	/***
	 * 介面回撥
	 */
	public void setOnFinishListener(
			OnFinishListener onSildingFinishListener) {
		this.onFinishListener = onSildingFinishListener;
	}

	/**
	 * 滾動出界面
	 */
	private void scrollBottom() {
		final int delta = (viewHeight + mParentView.getScrollY());
		mScroller.startScroll(0, mParentView.getScrollY(), 0, -delta + 1,
				Math.abs(delta));
		postInvalidate();
	}

	/**
	 * 滾動到起始位置
	 */
	private void scrollOrigin() {
		int delta = mParentView.getScrollY();
		mScroller.startScroll(0, mParentView.getScrollY(), 0, -delta,
				Math.abs(delta));
		postInvalidate();
	}

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

			if (mScroller.isFinished() && isFinish) {
				if (onFinishListener != null) {
					onFinishListener.onFinish();
				} else {
					// 沒有設定OnSildingFinishListener,讓其滾動到其實位置
					scrollOrigin();
					isFinish = false;
				}
			}
		}
	}

	public interface OnFinishListener {
		public void onFinish();
	}

}


從下往上滑動:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.Scroller;

/***
 * 
 * 從下向上滑結束Activity
 * 
 * @author 帽檐遮不住陽光
 * 
 */
public class BottomToTopFinishLayout extends RelativeLayout {
	
	/**
	 * BottomFinishLayout佈局的父佈局
	 */
	private ViewGroup mParentView;
	/**
	 * 滑動的最小距離
	 */
	private int mTouchSlop;
	/**
	 * 按下點的X座標
	 */
	private int downX;
	/**
	 * 按下點的Y座標
	 */
	private int downY;
	/**
	 * 臨時儲存X座標
	 */
	private int tempY;
	/**
	 * 滑動類
	 */
	private Scroller mScroller;
	/**
	 * BottomFinishLayout的寬度
	 */
	private int viewHeight;

	private boolean isSilding;

	private OnFinishListener onFinishListener;
	private boolean isFinish;

	public BottomToTopFinishLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public BottomToTopFinishLayout(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);

		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
		mScroller = new Scroller(context);
	}

	/**
	 * 事件攔截操作
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {

		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downX = (int) ev.getRawX();
			downY = tempY = (int) ev.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveY = (int) ev.getRawY();
			// 滿足此條件遮蔽SildingFinishLayout裡面子類的touch事件
			if (Math.abs(downY - moveY) > mTouchSlop
					&& Math.abs((int) ev.getRawX() - downX) < mTouchSlop) {
				return true;
			}
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_MOVE:
			int moveY = (int) event.getRawY();// 觸控點相對於螢幕的位置
			int deltaY = moveY - tempY;
			tempY = moveY;
			if (Math.abs(downY - moveY) > mTouchSlop
					&& Math.abs((int) event.getRawX() - downX) < mTouchSlop) {
				isSilding = true;
			}

			if (downY - moveY >= 0 && isSilding) {
				mParentView.scrollBy(0, -deltaY);
			}
			break;
		case MotionEvent.ACTION_UP:
			isSilding = false;
			System.out.println("vvv===========" + mParentView.getScrollY());
			System.out.println("/3============" + viewHeight / 3);
			if (mParentView.getScrollY() >= viewHeight / 3) {
				isFinish = true;
				scrollTop();
			} else {
				scrollOrigin();
				isFinish = false;
			}
			break;
		}
		return true;
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			mParentView = (ViewGroup) this.getParent();
			viewHeight = this.getHeight();
		}
	}

	/***
	 * 介面回撥
	 */
	public void setOnFinishListener(OnFinishListener onSildingFinishListener) {
		this.onFinishListener = onSildingFinishListener;
	}

	/**
	 * 滾動出界面
	 */
	private void scrollTop() {
		final int delta = (viewHeight - mParentView.getScrollY());
		mScroller.startScroll(0, mParentView.getScrollY(), 0, delta - 1,
				Math.abs(delta));
		postInvalidate();
	}

	/**
	 * 滾動到起始位置
	 */
	private void scrollOrigin() {
		int delta = mParentView.getScrollY();
		mScroller.startScroll(0, mParentView.getScrollY(), 0, -delta,
				Math.abs(delta));
		postInvalidate();
	}

	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {
			mParentView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
			if (mScroller.isFinished() && isFinish) {
				if (onFinishListener != null) {
					onFinishListener.onFinish();
				} else {
					// 沒有設定OnSildingFinishListener,讓其滾動到其實位置
					scrollOrigin();
					isFinish = false;
				}
			}
		}
	}

	public interface OnFinishListener {
		public void onFinish();
	}

}
Activity:
 public class FromTopActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_from_top);
TopToBottomFinishLayout bottomFinishLayout = (TopToBottomFinishLayout) findViewById(R.id.layout);
bottomFinishLayout.setOnFinishListener(new OnFinishListener() {


@Override
public void onFinish() {
finish();
}
});
}


}

layout:
<?xml version="1.0" encoding="utf-8"?>
<com.example.mytest.TopToBottomFinishLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#5DC890"
    android:orientation="vertical" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="TestActivity"
        android:textColor="#ff8840" />

</com.example.mytest.TopToBottomFinishLayout>



要實現其實很簡單,在onTouchEvent裡判斷手指移動的距離,如果大於自己設定的臨界值,則滾動到頂部或者底部,否則回到初始位置。所以這裡用到了Scroller,scroller.startScroll後,postInvalidate重新整理介面。

最後重寫computeScroll,在computeScroll裡判斷Scroller是否已經finish以及手指移動的距離是否大於自己設定的臨界值。

最後一定要記得,在AndroidManifest.xml裡要將Activity的Theme設定為Theme.Translucent,否則看不到效果

Demo:http://download.csdn.net/detail/qq_18612815/9615890