手机屏幕越来越大,单手操作时,无法点击到左上角的回退按钮。看到很多人都有实现这个功能,但是实现的功能过于强大。所以自己写了一个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);
源码地址
时间: 2024-10-13 15:56:11