效果圖
act2是Main2Activity,act3是Main3Activity
原理
滾動
首先我們知道每個Activity展示的內(nèi)容一般都是DecorView去承載的,不知道的看下圖恕汇,其中狀態(tài)欄背景也包括在內(nèi):
所以我們第一步,只需要滾動DecorView內(nèi)容或者平移DecorView就行了。
使上一個Activity可見
上面的Activity不可見其實是因為被當前Activity給擋住了布讹。那問題來了。
Q:為什么我把布局顏色設置成透明背景训堆,可還是看不到上面的Activity呢描验?
A:看上面的DecorView那張圖,我們Activity布局只是填充content里面的內(nèi)容坑鱼,也就是說我們是被ContentFrameLayout包裹住的膘流,Activity布局文件的根元素并不是Activity的根元素,由層級可知鲁沥。我們的Activity被上層的Activity擋住呼股,其實是因為DecorView具有背景顏色,我們只需要把它的背景色去掉就行了画恰。
實現(xiàn)
第一步設置透明主題
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="CustomTheme" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
<activity android:name=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Main3Activity"
android:theme="@style/CustomTheme" />
我們把Main3Activity的DecorView背景色去掉了彭谁。
滾動DecorView內(nèi)容
這里我們使用滾動DecorView內(nèi)容而不是滾動整個DecorView。
首先大家需要搞懂一個View的ScrollBy
和ScrollTo
是什么回事允扇,參考Android scrollTo和scrollBy方法使用說明
Main3Activity.java
public class Main3Activity extends AppCompatActivity {
/**
* DecorView左邊滑出間距占屏幕寬度PRESENT_TO_FINISH時表示用戶需要退出當前Activity
*/
private static final float PRESENT_TO_FINISH = 0.3f;
/**
* 用戶距離左邊MIN_EDGE_DISTANCE內(nèi)拖動有效
*/
private static final int MIN_EDGE_DISTANCE = 100;
/**
* 屏幕寬度
*/
private static float mScreenW = -1;
/**
* 用戶計算用戶在屏幕滑動的距離
*/
private float mStartX = 0;
/**
* 當前是否允許拖動
*/
private boolean mIsScrollEnable = false;
/**
* 當前Activity的DecorView
*/
private View mDecorView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
// 初始化
mDecorView = getWindow().getDecorView();
if (mScreenW == -1) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
mScreenW = metrics.widthPixels;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mStartX = event.getX();
if (mStartX < MIN_EDGE_DISTANCE) {
// 距離左邊距離足夠小缠局,設置為可拖動狀態(tài)
mIsScrollEnable = true;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE && mIsScrollEnable) {
// 滾動DecorView內(nèi)容
float dX = event.getX() - mStartX;
mStartX = event.getX();
mDecorView.scrollBy((int) -dX, 0);
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
// 觸摸操作取消则奥,重置
mIsScrollEnable = false;
// 根據(jù)當前滑動狀態(tài)判斷最終是滑到左邊還是滑到右邊(結(jié)束Activity)
final int targetX = -mDecorView.getScrollX() / mScreenW > PRESENT_TO_FINISH ? (int) -mScreenW : 0;
ValueAnimator animator = ValueAnimator.ofInt(mDecorView.getScrollX(), targetX);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDecorView.scrollTo((Integer) animation.getAnimatedValue(), 0);
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (targetX == -mScreenW) {
finish();
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.start();
}
return super.onTouchEvent(event);
}
}
寫在最后
這是最簡單最簡單的做法,無任何封裝與擴展甩鳄,包括一些可能存在的滾動沖突也沒有去處理逞度。大家可以封裝一個比較完善并且容易使用的庫,加入ListView之類的滑動沖突處理以及背景色透明漸變之類的妙啃,然后里面的xml代碼轉(zhuǎn)換成對應deJava代碼寫法档泽。一句話使Activity實現(xiàn)該功能也是可以做到的。