滑動退出Activity的兩種方法
阿新 • • 發佈:2019-01-29
最近遇到需求,需要滑動退出Activity,參考了大蝦們的方案後整理出了兩種主流的方法:
- 使用OnTouchEvent,處理觸控事件實現滑動退出
- 使用ViewDragHelper拖動實現滑動退出
兩種方法各有利弊,遇到介面上的滑動或滾動事件產生衝突的需要自己處理,下面就來詳細的介紹兩種實現方法。
0.前提
兩種方法不管使用哪一種都需要設定透明主題及Activity中根佈局的background,以實現滑動時,上一個Activity可見。
Activity根佈局背景: android:background="?android:colorBackground" Activity主題: <style name="Translucent" parent="AppTheme"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle">@android:style/Animation</item> </style>
1.使用OnTouchEvent,處理觸控事件實現滑動退出
先來看看具體實現:
/** * @author Steven Duan * @version 1.0 */ public class SlideLayout extends FrameLayout { private static final String T = SlideLayout.class.getName(); private Activity mActivity; private Scroller mScroller; private int mShadowWidth; private Drawable mLeftShadow; private int mLastMoveX; private int mScreenWidth; private int mMinX; public SlideLayout(Activity activity) { this(activity, null); } public SlideLayout(Activity activity, AttributeSet attrs) { this(activity, attrs, 0); } public SlideLayout(Activity activity, AttributeSet attrs, int defStyleAttr) { super(activity, attrs, defStyleAttr); Log.d(T, "F初始化 "); this.mActivity = activity; mScroller = new Scroller(activity); //滑動時漸變的陰影 //noinspection deprecation mLeftShadow = getResources().getDrawable(R.drawable.left_shadow); //陰影的寬度 mShadowWidth = ((int) getResources().getDisplayMetrics().density) * 16; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastMoveX = (int) event.getX(); mScreenWidth = getWidth(); mMinX = mScreenWidth / 10; break; case MotionEvent.ACTION_MOVE: int eventX = (int) event.getX(); Log.d(T, "eventX: " + eventX); int dx = mLastMoveX - eventX; if (getScrollX() + dx >= 0) { scrollTo(0, 0); } else if (eventX > mMinX) { //手指處於螢幕邊緣時不處理滑動 scrollBy(dx, 0); } mLastMoveX = eventX; break; case MotionEvent.ACTION_UP: if (-getScrollX() < mScreenWidth / 2) { slideBack(); } else { slideFinish(); } break; } return true; } private void slideFinish() { mScroller.startScroll(getScrollX(), 0, -getScrollX() - mScreenWidth, 0, 200); invalidate(); } private void slideBack() { mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0, 200); invalidate(); } @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), 0); postInvalidate(); } else if (-getScrollX() == mScreenWidth) { mActivity.finish(); } } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); //繪製邊緣陰影 canvas.save(); //設定陰影的大小範圍 mLeftShadow.setBounds(0, 0, mShadowWidth, getHeight()); //平移畫布 canvas.translate(-mShadowWidth, 0); //繪製 mLeftShadow.draw(canvas); canvas.restore(); } public void bind() { Log.d(T, "bind: F"); ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView(); View child = decorView.getChildAt(0); decorView.removeView(child); addView(child); decorView.addView(this); Log.d(T, "bind成功"); } }
定義好了容器,那麼在Activity中如何使用呢?只需要在Activity的onCreate方法做如下呼叫即可:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
new SlideLayout(this).bind();
}
程式碼比較簡單,一看便知。只是這種方法在Activity中有滑動或滾動事件會產生衝突,這就涉及事件分發機制,需要自己看情況處理。
2.使用ViewDragHelper拖動實現滑動退出
廢話不多說直接上程式碼:
/**
* @author Steven Duan
* @version 1.0
*/
public class SlideLayout extends FrameLayout {
private View mDragView;
private Activity mActivity;
private ViewDragHelper mViewDragHelper;
private float mSlideWidth;
private int mScreenWidth;
private int mScreenHeight;
private int curSlideX;
public SlideLayout(Context context) {
super(context);
init(context);
}
private void init(Context context) {
mActivity = (Activity) context;
mViewDragHelper = ViewDragHelper.create(this, new DragCallback());
//設定可拖動的邊緣
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
}
/**
* 把DecorView下的子View移除新增到SlideLayout,再將SlideLayout新增到DecorView
*/
public void bind() {
ViewGroup mDecorView = (ViewGroup) mActivity.getWindow().getDecorView();
mDragView = mDecorView.getChildAt(0);
mDecorView.removeView(mDragView);
this.addView(mDragView);
mDecorView.addView(this);
//計算螢幕寬度
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
mScreenWidth = dm.widthPixels;
mScreenHeight = dm.heightPixels;
//觸發Activity滑出的寬度
mSlideWidth = dm.widthPixels * 0.5f;
}
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
return mViewDragHelper.shouldInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
class DragCallback extends ViewDragHelper.Callback {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return false;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
int left = releasedChild.getLeft();
if (left <= mSlideWidth) {
//返回
mViewDragHelper.settleCapturedViewAt(0, 0);
} else {
//滑出
mViewDragHelper.settleCapturedViewAt(mScreenWidth, 0);
}
//需要重繪
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
curSlideX = left;
invalidate();
if (changedView == mDragView && left >= mScreenWidth) {
mActivity.finish();
}
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制左右拖拽的位移
left = left >= 0 ? left : 0;
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
//觸發邊緣時,主動捕捉mDragView
mViewDragHelper.captureChildView(mDragView, pointerId);
}
}
@Override
public void computeScroll() {
//持續滾動期間,不斷重繪
if (mViewDragHelper.continueSettling(true))
invalidate();
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
//進行陰影繪製
canvas.save();
Shader mShader = new LinearGradient(curSlideX - 40, 0, curSlideX, 0,
new int[]{Color.parseColor("#00000000"), Color.parseColor("#50000000")},
null, Shader.TileMode.REPEAT);
//繪製陰影畫筆
Paint mPaint = new Paint();
mPaint.setStrokeWidth(2);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.GRAY);
mPaint.setShader(mShader);
RectF rectF = new RectF(curSlideX - 40, 0, curSlideX, mScreenHeight);
canvas.drawRect(rectF, mPaint);
canvas.restore();
}
}
在Activity的onCreate()中呼叫:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forth);
//一句話實現繫結
new SlideLayout(this).bind();
}