package org.qii.weiciyuan.support.lib;
import org.qii.weiciyuan.R;
import org.qii.weiciyuan.support.utils.AnimationUtility;
import org.qii.weiciyuan.support.utils.ThemeUtility;
import org.qii.weiciyuan.support.utils.Utility;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.OverScroller;
/**
* User: qii
* Date: 13-10-15
*/
public class SwipeFrameLayout extends FrameLayout {
private Activity activity;
private boolean isDragging = false;
private float[] initPointLocation = new float[2];
private View topView;
private static final int OFFSET = 5;
private int max_motion_event_down_x_position;
private GestureDetector gestureDetector;
private OverScroller scroller;
private Handler uiHandler = new Handler();
public SwipeFrameLayout(Context context) {
this(context, null);
}
public SwipeFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public SwipeFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
scroller = new OverScroller(getContext(), new DecelerateInterpolator());
setBackground(ThemeUtility.getDrawable(android.R.attr.windowBackground));
this.activity = (Activity) getContext();
this.topView = ((View) (activity.findViewById(android.R.id.content).getParent()));
this.max_motion_event_down_x_position = Utility.dip2px(25);
this.gestureDetector = new GestureDetector(getContext(),
new SwipeRightToCloseOnGestureListener());
this.setId(R.id.swipe_framelayout);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (scroller.computeScrollOffset()) {
scroller.abortAnimation();
}
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
initPointLocation[0] = ev.getRawX();
initPointLocation[1] = ev.getRawY();
return false;
case MotionEvent.ACTION_MOVE:
if (isDragging) {
gestureDetector.onTouchEvent(ev);
return true;
}
float xx = ev.getRawX();
if ((xx > initPointLocation[0] + Utility.dip2px(OFFSET))
&& initPointLocation[0] <= max_motion_event_down_x_position) {
isDragging = true;
gestureDetector.onTouchEvent(ev);
return true;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isDragging = false;
if (initPointLocation[0] <= max_motion_event_down_x_position) {
int x = (int) (ev.getRawX() - initPointLocation[0]);
initPointLocation[0] = 0f;
initPointLocation[1] = 0f;
if (x > (Utility.getScreenWidth() / 2)) {
closeActivity();
return true;
} else {
restoreActivity();
}
}
break;
}
return super.onTouchEvent(ev);
}
private boolean translucent;
private Runnable forceConvertActivityFromTranslucentRunnable;
private void forceConvertActivityFromTranslucent() {
if (forceConvertActivityFromTranslucentRunnable != null) {
uiHandler.removeCallbacks(forceConvertActivityFromTranslucentRunnable);
}
Runnable runnable = new Runnable() {
@Override
public void run() {
if (activity.isFinishing()) {
return;
}
AnimationUtility.forceConvertActivityFromTranslucent(activity);
forceConvertActivityFromTranslucentRunnable = null;
}
};
forceConvertActivityFromTranslucentRunnable = runnable;
uiHandler.postDelayed(forceConvertActivityFromTranslucentRunnable, 3000);
}
private void forceConvertActivityToTranslucent() {
if (forceConvertActivityFromTranslucentRunnable != null) {
uiHandler.removeCallbacks(forceConvertActivityFromTranslucentRunnable);
} else {
AnimationUtility.forceConvertActivityToTranslucent(activity);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!translucent && isDownEventInsideSwipeRegion(ev)) {
forceConvertActivityToTranslucent();
translucent = true;
}
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
initPointLocation[0] = ev.getRawX();
initPointLocation[1] = ev.getRawY();
this.gestureDetector.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (!isDragging && translucent) {
forceConvertActivityFromTranslucent();
translucent = false;
}
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isDragging) {
return true;
}
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
if (canSwipe(ev)) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
private boolean isDownEventInsideSwipeRegion(MotionEvent ev) {
float x = ev.getRawX();
return x <= max_motion_event_down_x_position;
}
private boolean canSwipe(MotionEvent ev) {
float x = ev.getRawX();
return x > initPointLocation[0]
&& initPointLocation[0] <= max_motion_event_down_x_position;
}
private void closeActivity() {
if (translucent) {
forceConvertActivityFromTranslucent();
translucent = false;
}
activity.finish();
activity.overridePendingTransition(R.anim.stay, R.anim.swipe_right_to_close);
}
private void restoreActivity() {
if (lastScrollRunnable != null) {
removeCallbacks(lastScrollRunnable);
}
scroller.startScroll(topView.getScrollX(), 0, -topView.getScrollX(), 0);
lastScrollRunnable = new ScrollRunnable();
post(lastScrollRunnable);
}
private ScrollRunnable lastScrollRunnable;
private class ScrollRunnable implements Runnable {
@Override
public void run() {
if (scroller.computeScrollOffset()) {
int currentValue = scroller.getCurrX();
topView.scrollTo(currentValue, 0);
topView.invalidate();
post(this);
} else if (translucent && !isDragging) {
forceConvertActivityFromTranslucent();
translucent = false;
if (lastScrollRunnable == this) {
lastScrollRunnable = null;
}
}
}
}
private class SwipeRightToCloseOnGestureListener
extends GestureDetector.SimpleOnGestureListener {
protected MotionEvent mLastOnDownEvent = null;
private float[] initPointLocation = new float[2];
@Override
public boolean onDown(MotionEvent e) {
mLastOnDownEvent = e;
initPointLocation[0] = e.getRawX();
initPointLocation[1] = e.getRawY();
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (e2.getRawX() < initPointLocation[0]) {
float y = topView.getScrollX();
if (y != 0f) {
restoreActivity();
return super.onScroll(e1, e2, distanceX, distanceY);
} else {
return false;
}
}
final int MAX_MOTION_EVENT_DOWN__X_POSITION = Utility.dip2px(25);
float s = e2.getRawX() - initPointLocation[0];
if (initPointLocation[0] <= MAX_MOTION_EVENT_DOWN__X_POSITION) {
topView.scrollTo((int) -s, 0);
topView.invalidate();
return true;
} else {
return false;
}
}
}
}