您好,登錄后才能下訂單哦!
類似于微信的右滑返回,在BaseActivity里利用dispatchTouchEvent()攔截右滑動(dòng)作,利用setTranslationX()實(shí)現(xiàn)動(dòng)畫(huà),在DecorView里添加View作為滑動(dòng)時(shí)的左側(cè)陰影。
漸進(jìn)步驟:
注意:步驟中的代碼為了不關(guān)聯(lián)到后面的步驟,會(huì)與最終的有點(diǎn)不同
背景透明
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item>
activity的跳轉(zhuǎn)動(dòng)畫(huà)
根據(jù)項(xiàng)目需要,重寫用到的startActivity(Intent intent),startActivityForResult(Intent intent, int requestCode),finish()等activity跳轉(zhuǎn)和銷毀方法
@Override public void startActivity(Intent intent) { super.startActivity(intent); overridePendingTransition(R.anim.slide_right_in, 0); } @Override public void startActivityForResult(Intent intent, int requestCode) { super.startActivityForResult(intent, requestCode); overridePendingTransition(R.anim.slide_right_in, 0); } @Override public void finish() { super.finish(); overridePendingTransition(0, R.anim.slide_right_out); } //R.anim.slide_right_in <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="300" android:fromXDelta="100%" android:toXDelta="0" android:fromYDelta="0" android:toYDelta="0"/> </set> //R.anim.slide_right_out <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="300" android:fromXDelta="0" android:toXDelta="100%" android:fromYDelta="0" android:toYDelta="0" /> </set>
攔截右滑動(dòng)作
所有的觸摸事件通過(guò)activity.dispatchTouchEvent(MotionEvent ev)向view分發(fā)。
手指在X軸方向右滑動(dòng)50~100px時(shí),判斷是否為(產(chǎn)品經(jīng)理要)右滑動(dòng)作
private float downX = 0; private float downY = 0; private boolean shouldIntercept = false; private boolean hadJudge = false; @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (shouldIntercept) { return onTouchEvent(ev); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { downX = ev.getRawX(); downY = ev.getRawY(); hadJudge = false; break; } case MotionEvent.ACTION_MOVE: { if (hadJudge) break; if (ev.getRawX() == downX) break; if (ev.getRawX() < downX) { //左滑 hadJudge = true; break; } if (ev.getRawX() - downX >=100){ //超出判斷距離 hadJudge = true; break; } if (ev.getRawX() - downX > 50) { //x軸右滑50~100px float rate = (ev.getRawX() - downX) / (Math.abs(ev.getRawY() - downY)); if ((downX < 50 && rate > 0.5f) || rate > 2) { shouldIntercept = true; } } break; } case MotionEvent.ACTION_UP: { downX =0; downY = 0; shouldIntercept = false; hadJudge=false; break; } } //Activity的默認(rèn)分發(fā) if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return true; }
根布局位移動(dòng)畫(huà)
根據(jù)手指滑動(dòng)距離設(shè)置根布局偏移距離,用滑動(dòng)距離和手指抬起時(shí)的速度判斷是否返回
private View rootView = null; private float lastX = -1; private VelocityTracker velocityTracker = null; private int maxFlingVelocity; @Override public boolean onTouchEvent(MotionEvent event) { if (rootView == null) { ViewGroup rootGroup = (ViewGroup) (getWindow().getDecorView()); rootView = rootGroup.getChildAt(0); } //測(cè)量手指抬起時(shí)的速度 if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity(); } velocityTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { lastX = event.getRawX(); break; } case MotionEvent.ACTION_MOVE: { if (lastX == -1) { lastX = event.getRawX(); break; } //根據(jù)手指滑動(dòng)距離設(shè)置根布局偏移距離 rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX); if (rootView.getTranslationX() < 0) rootView.setTranslationX(0); lastX = event.getRawX(); break; } case MotionEvent.ACTION_UP: { //測(cè)量手指抬起時(shí)的速度 velocityTracker.computeCurrentVelocity(1000, maxFlingVelocity); float velocityX = velocityTracker.getXVelocity(); if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } //判斷是否返回 if (downX < 50 && velocityX > 1000) { //手指在左側(cè)邊落下,返回 onBack(); } else if (velocityX > 3600) { //手指快速滑動(dòng),返回 onBack(); } else if (rootView.getTranslationX() > ConvertUtil.getWidthInPx() * 0.3) { //滑動(dòng)距離超過(guò)30%屏幕寬度,返回 onBack(); } else { //不返回,根布局偏移歸零 rootView.animate().translationX(0).setDuration(200).start(); } lastX = -1; shouldIntercept = false; hadJudge=false; downX = 0; downY = 0; break; } } return super.onTouchEvent(event); }
添加左側(cè)陰影
Activity的最頂層View為DecorView,DecorView是一個(gè)FrameLayout,里面只有一個(gè)Linearlayout,Linearlayout包含著標(biāo)題欄和自定義布局(setContentView)。
上一步跟隨手指滑動(dòng)進(jìn)行偏移的就是Linearlayout,現(xiàn)在要在DecorView里添加一個(gè)View,設(shè)置背景作為陰影,并跟隨Linearlayout進(jìn)行移動(dòng)
private View shadowView = null; @Override public boolean onTouchEvent(MotionEvent event) { if (rootView == null) { //添加陰影 ViewGroup rootGroup = (ViewGroup) (getWindow().getDecorView()); shadowView = new View(this); rootGroup.addView(shadowView, 0); ViewGroup.LayoutParams params = shadowView.getLayoutParams(); //陰影寬度 params.width = (int) ((float) ConvertUtil.getWidthInPx() * 0.05f); params.height = ConvertUtil.getHeightInPx(); shadowView.setLayoutParams(params); shadowView.setBackgroundResource(R.drawable.shadow_grey_h); shadowView.setTranslationX(params.width); rootView = rootGroup.getChildAt(1); } ... switch (event.getAction()) { ... case MotionEvent.ACTION_MOVE: { if (lastX == -1) { lastX = event.getRawX(); break; } //根據(jù)手指滑動(dòng)距離設(shè)置根布局偏移距離 rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX); if (rootView.getTranslationX() < 0) rootView.setTranslationX(0); //陰影跟隨根布局移動(dòng) shadowView.setTranslationX(-shadowView.getWidth()+rootView.getTranslationX()); lastX = event.getRawX(); break; } case MotionEvent.ACTION_UP: { ... } else { //不返回,根布局偏移歸零 rootView.animate().translationX(0).setDuration(200).start(); //陰影偏移歸零 shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start(); } ... } } ... }
關(guān)聯(lián)下層activity滑動(dòng)
獲取下層activity
private static ArrayList<Activity> Activity_Stack = new ArrayList<>(); private BaseSwipeBackActivity lastActivity = null; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity(); if (!Activity_Stack.contains(this)) Activity_Stack.add(this); if (Activity_Stack.size() >= 2) { Activity last = Activity_Stack.get(Activity_Stack.size() - 2); if (last instanceof BaseSwipeBackActivity) { lastActivity = (BaseSwipeBackActivity) last; } } } @Override protected void onDestroy() { super.onDestroy(); Activity_Stack.remove(this); }
下層activity的退出、進(jìn)入動(dòng)畫(huà)
private void lowerActivityExitAnim() { if (rootView == null) return; //只移動(dòng)30% rootView.animate().translationX(-ConvertUtil.getWidthInPx() * 0.3f).setDuration(300).start(); } private void lowerActivityEnterAnim(float upperTranslationX) { if (rootView == null) return; //保證滑動(dòng)退出時(shí),上下層時(shí)間同步 float r = 1-upperTranslationX/ (float) ConvertUtil.getWidthInPx(); rootView.animate().translationX(0).setDuration((long) (300f * r)).start(); }
在跳轉(zhuǎn)時(shí),調(diào)用下層activity的退出、進(jìn)入動(dòng)畫(huà)
@Override public void startActivity(Intent intent) { super.startActivity(intent); overridePendingTransition(R.anim.slide_right_in, 0); lowerActivityExitAnim(); } @Override public void startActivityForResult(Intent intent, int requestCode) { super.startActivityForResult(intent, requestCode); overridePendingTransition(R.anim.slide_right_in, 0); lowerActivityExitAnim(); } @Override public void finish() { super.finish(); overridePendingTransition(0, R.anim.slide_right_out); if (lastActivity != null) lastActivity.lowerActivityEnterAnim(rootView.getTranslationX()); Activity_Stack.remove(this); }
上層activity滑動(dòng)時(shí)關(guān)聯(lián)下層滑動(dòng)
@Override public boolean onTouchEvent(MotionEvent event) { ... switch (event.getAction()) { ... case MotionEvent.ACTION_MOVE: { ... //根據(jù)手指滑動(dòng)距離設(shè)置根布局偏移距離 rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX); if (rootView.getTranslationX() < 0) rootView.setTranslationX(0); //陰影跟隨根布局移動(dòng) shadowView.setTranslationX(-shadowView.getWidth() + rootView.getTranslationX()); //下層activity跟隨移動(dòng) if (lastActivity != null && lastActivity.rootView != null) //-ConvertUtil.getWidthInPx() * 0.3f初始的偏移 lastActivity.rootView.setTranslationX(-ConvertUtil.getWidthInPx() * 0.3f + rootView.getTranslationX() * 0.3f); ... } case MotionEvent.ACTION_UP: { ... } else { //不返回,根布局偏移歸零 rootView.animate().translationX(0).setDuration(200).start(); //陰影偏移歸零 shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start(); //下層activity偏移復(fù)原 if (lastActivity != null) lastActivity.lowerActivityExitAnim(); } ... } } return super.onTouchEvent(event); }
完整的
public abstract class BaseSwipeBackActivity extends AppCompatActivity { private static ArrayList<Activity> Activity_Stack = new ArrayList<>(); private BaseSwipeBackActivity lastActivity = null; private View rootView = null; private View shadowView = null; private float downX = 0; private float downY = 0; private boolean shouldIntercept = false; private boolean hadJudge = false; private float lastX = -1; private VelocityTracker velocityTracker = null; private int maxFlingVelocity; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity(); if (!Activity_Stack.contains(this)) Activity_Stack.add(this); if (Activity_Stack.size() >= 2) { Activity last = Activity_Stack.get(Activity_Stack.size() - 2); if (last instanceof BaseSwipeBackActivity) { lastActivity = (BaseSwipeBackActivity) last; } } } @Override protected void onResume() { initShadow(); super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); Activity_Stack.remove(this); } @Override public void startActivity(Intent intent) { super.startActivity(intent); overridePendingTransition(R.anim.slide_right_in, 0); lowerActivityExitAnim(); } @Override public void startActivityForResult(Intent intent, int requestCode) { super.startActivityForResult(intent, requestCode); overridePendingTransition(R.anim.slide_right_in, 0); lowerActivityExitAnim(); } @Override public void finish() { super.finish(); overridePendingTransition(0, R.anim.slide_right_out); if (lastActivity != null) lastActivity.lowerActivityEnterAnim(rootView.getTranslationX()); Activity_Stack.remove(this); } private void initShadow() { if (shadowView == null) { ViewGroup rootGroup = (ViewGroup) (getWindow().getDecorView()); shadowView = new View(this); rootGroup.addView(shadowView, 0); ViewGroup.LayoutParams params = shadowView.getLayoutParams(); //陰影寬度 params.width = (int) ((float) ConvertUtil.getWidthInPx() * 0.05f); params.height = ConvertUtil.getHeightInPx(); shadowView.setLayoutParams(params); //漸變背景作為陰影 shadowView.setBackgroundResource(R.drawable.shadow_grey_h); shadowView.setTranslationX(-params.width); rootView = rootGroup.getChildAt(1); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (shouldIntercept) { return onTouchEvent(ev); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { downX = ev.getRawX(); downY = ev.getRawY(); hadJudge = false; break; } case MotionEvent.ACTION_MOVE: { if (hadJudge) break; if (ev.getRawX() == downX) break; if (ev.getRawX() < downX) { //左滑 hadJudge = true; break; } if (ev.getRawX() - downX >= 100) { //超出判斷距離 hadJudge = true; break; } if (ev.getRawX() - downX > 50) { //x軸右滑50~100px float rate = (ev.getRawX() - downX) / (Math.abs(ev.getRawY() - downY)); if ((downX < 50 && rate > 0.5f) || rate > 2) { shouldIntercept = true; } } break; } case MotionEvent.ACTION_UP: { downX = 0; downY = 0; shouldIntercept = false; hadJudge = false; break; } } //Activity的默認(rèn)分發(fā) if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return true; } @Override public boolean onTouchEvent(MotionEvent event) { initShadow(); //測(cè)量手指抬起時(shí)的速度 if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity(); } velocityTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { lastX = event.getRawX(); break; } case MotionEvent.ACTION_MOVE: { if (lastX == -1) { lastX = event.getRawX(); break; } //根據(jù)手指滑動(dòng)距離設(shè)置根布局偏移距離 rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX); if (rootView.getTranslationX() < 0) rootView.setTranslationX(0); //陰影跟隨根布局移動(dòng) shadowView.setTranslationX(-shadowView.getWidth() + rootView.getTranslationX()); //下層activity跟隨移動(dòng) if (lastActivity != null && lastActivity.rootView != null) lastActivity.rootView.setTranslationX(-ConvertUtil.getWidthInPx() * 0.3f + rootView.getTranslationX() * 0.3f); lastX = event.getRawX(); break; } case MotionEvent.ACTION_UP: { //測(cè)量手指抬起時(shí)的速度 velocityTracker.computeCurrentVelocity(1000, maxFlingVelocity); float velocityX = velocityTracker.getXVelocity(); if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } //判斷是否返回 if (downX < 50 && velocityX > 1000) { //手指在左側(cè)邊落下,返回 onBack(); } else if (velocityX > 3600) { //手指快速滑動(dòng),返回 onBack(); } else if (rootView.getTranslationX() > ConvertUtil.getWidthInPx() * 0.3) { //滑動(dòng)距離超過(guò)30%屏幕寬度,返回 onBack(); } else { //不返回,根布局偏移歸零 rootView.animate().translationX(0).setDuration(200).start(); //陰影偏移歸零 shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start(); //下層activity偏移復(fù)原 if (lastActivity != null) lastActivity.lowerActivityExitAnim(); } lastX = -1; shouldIntercept = false; hadJudge = false; downX = 0; downY = 0; break; } } return super.onTouchEvent(event); } private void lowerActivityExitAnim() { if (rootView == null) return; rootView.animate().translationX(-ConvertUtil.getWidthInPx() * 0.3f).setDuration(300).start(); } private void lowerActivityEnterAnim(float upperTranslationX) { if (rootView == null) return; float r = 1-upperTranslationX/ (float) ConvertUtil.getWidthInPx(); rootView.animate().translationX(0).setDuration(r == 0.0f ? 10 : (long) (300f * r)).start(); } //退出 abstract public void onBack(); }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。