滑动返回
手机屏幕越来越大,单手操作时,无法点击到左上角的回退按钮。看到很多人都有实现这个功能,但是实现的功能过于强大。所以自己写了一个Layout来实现这个功能。整个Layout实现滑动返回只有180行代码。
实现思想
现在有一个ViewGroup和一个View,在这个ViewGroup和View之间加上一个层Overlay,实现滑动时,Overlay和view像→滑动,ViewGroup不动。
比如,Activity的decorView就是ViewGroup,view就是ActionBarOverlayLayout(decorView.getChildAtIndex(0));
将activty的windowbackground职位null,并将windowbackroundcolor置为透明色即可。
源码
public class SlideOverlayLayout extends FrameLayout {
private onSlideListener mOnSlideListener;
private int mTouchSlop;
private Scroller mScroller;
private float mLastPositionX;
private float mLastPositonY;
private boolean mIsSliding;
private boolean mIsFinish;
private View mSlidView;
public SlideOverlayLayout(Context context) {
super(context);
init(context);
}
public SlideOverlayLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SlideOverlayLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mScroller = new Scroller(context);
}
public void setOnSlideListener(onSlideListener onSlideListener) {
mOnSlideListener = onSlideListener;
}
public void slide() {
if (mOnSlideListener == null) {
mSlidView = null;
return;
}
mOnSlideListener.insertSlideOverlayLayout(this);
if (getChildCount() == 0) {
throw new IllegalArgumentException(
"slide view at least have one child, which is the slid view.");
}
mSlidView = getChildAt(getChildCount() - 1);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mOnSlideListener == null) {
return super.onInterceptTouchEvent(event);
}
if (!mOnSlideListener.canSlide(this, event.getRawX(), event.getRawY())) {
return super.onInterceptTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mIsSliding = true;
mLastPositionX = event.getRawX();
mLastPositonY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float positionX = event.getRawX();
float positionY = event.getRawY();
float deltaX = positionX - mLastPositionX;
float deltaY = positionY - mLastPositonY;
if (Math.abs(deltaY) < mTouchSlop && deltaX > 0) {
mLastPositionX = positionX;
mLastPositonY = positionY;
return mIsSliding = true;
} else {
mIsSliding = false;
}
break;
default:
break;
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mOnSlideListener == null || !mIsSliding) {
return super.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float positionX = event.getRawX();
float positionY = event.getRawY();
float deltaX = positionX - mLastPositionX;
mLastPositionX = positionX;
mLastPositonY = positionY;
if (mSlidView.getScrollX() - deltaX > 0) {
deltaX = mSlidView.getScrollX();
}
mSlidView.scrollBy((int) -deltaX, 0);
mOnSlideListener.onSlide(this, deltaX - mSlidView.getScrollX());
break;
case MotionEvent.ACTION_UP:
mIsSliding = false;
int dx;
if (mIsFinish = mOnSlideListener.canFinish(this,
-mSlidView.getScrollX())) {
dx = -(getWidth() + mSlidView.getScrollX()) + 1;
} else {
dx = -mSlidView.getScrollX();
}
mScroller.startScroll(mSlidView.getScrollX(), 0, dx, 0,
Math.abs(dx));
postInvalidate();
break;
}
return true;
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mSlidView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
mOnSlideListener.onSlide(this, - mScroller.getCurrX());
postInvalidate();
} else if (mIsFinish) {
mOnSlideListener.onFinish(this);
}
}
public interface onSlideListener {
// Insert the slide layout between the container and slid view.
// Also you can add other views into the layout to let the slid look
// better.
// But be sure that the slid view will be the last child to be added in.
void insertSlideOverlayLayout(SlideOverlayLayout layout);
// When touching the screen, this will be called with the position where
// your finger touches.
boolean canSlide(SlideOverlayLayout layout, float positionX,
float positionY);
// This will be called when ever your finger moves with the offset.
void onSlide(SlideOverlayLayout layout, float offset);
// When leaving your finger from the screen, this method will be called
// with the final offset, and return the boolean value which can finish
// the slid action.
boolean canFinish(SlideOverlayLayout layout, float offset);
// when return true by canFinish() method, this will be immediately
// called when the slide animation overs.
void onFinish(SlideOverlayLayout layout);
}
}
如何使用
1.将activity的window置为透明(查看values下的style文件)
<style name="AppTheme.Translucent">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<!-- Note that we use the base animation style here (that is no
animations) because we really have no idea how this kind of
activity will be used. -->
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
2.将其应用到AndroidManifest文件的制定Activity上
<activity
android:name="com.demo.slide.activity.SlideActivity"
android:theme="@style/AppTheme.Translucent" />
3.在activity中使用SlideOverlayLayout
public class SlideActivity extends Activity implements onSlideListener {
// private View vSlideAlphaView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_slide);
SlideOverlayLayout slideView = new SlideOverlayLayout(this);
slideView.setOnSlideListener(this);
slideView.slide();
}
@Override
public void insertSlideOverlayLayout(SlideOverlayLayout layout) {
ViewGroup root = (ViewGroup) getWindow().getDecorView();
View contentView = root.getChildAt(0);
root.removeView(contentView);
// vSlideAlphaView = new View(this);
// vSlideAlphaView.setBackgroundColor(Color.BLACK);
// vSlideAlphaView.getBackground().setAlpha(255 / 2);
// layout.addView(vSlideAlphaView);
layout.addView(contentView);
root.addView(layout);
}
@Override
public void onSlide(SlideOverlayLayout layout, float offset) {
// float alpha = 0.5f - offset / vSlideAlphaView.getWidth();
//
// if (alpha < 0) {
// alpha = 0;
// }
//
// vSlideAlphaView.getBackground().setAlpha((int) (255 * alpha));
}
@Override
public boolean canFinish(SlideOverlayLayout layout, float offset) {
return offset > layout.getWidth() / 3.0f;
}
@Override
public void onFinish(SlideOverlayLayout layout) {
finish();
}
@Override
public boolean canSlide(SlideOverlayLayout layout, float positionX,
float positonY) {
return true;
}
}
注:对这个listener方法的说明
// Insert the slide layout between the container and slid view.
// Also you can add other views into the layout to let the slid look
// better.
// But be sure that the slid view will be the last child to be added in.
void insertSlideOverlayLayout(SlideOverlayLayout layout);
// When touching the screen, this will be called with the position where
// your finger touches.
boolean canSlide(SlideOverlayLayout layout, float positionX,
float positionY);
// This will be called when ever your finger moves with the offset.
void onSlide(SlideOverlayLayout layout, float offset);
// When leaving your finger from the screen, this method will be called
// with the final offset, and return the boolean value which can finish
// the slid action.
boolean canFinish(SlideOverlayLayout layout, float offset);
// when return true by canFinish() method, this will be immediately
// called when the slide animation overs.
void onFinish(SlideOverlayLayout layout);
源码地址