android 右滑返回的示例代码
类似于微信的右滑返回,在baseactivity里利用dispatchtouchevent()拦截右滑动作,利用settranslationx()实现动画,在decorview里添加view作为滑动时的左侧阴影。
渐进步骤:
- 设置activity背景透明
- 重写finish()等方法设置activity的跳转动画
- 重写dispatchtouchevent()拦截 所需要 右滑动作
- 重写ontouchevent()给根布局设置偏移量
- 添加滑动时上层activity的左侧阴影
- 滑动时关联下层activity滑动
注意:步骤中的代码为了不关联到后面的步骤,会与最终的有点不同
背景透明
<item name="android:windowbackground">@android:color/transparent</item> <item name="android:windowistranslucent">true</item>
activity的跳转动画
根据项目需要,重写用到的startactivity(intent intent),startactivityforresult(intent intent, int requestcode),finish()等activity跳转和销毁方法
@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>
拦截右滑动作
所有的触摸事件通过activity.dispatchtouchevent(motionevent ev)向view分发。
手指在x轴方向右滑动50~100px时,判断是否为(产品经理要)右滑动作
- 手指落点为全屏幕,x方向滑动距离要比y方向的大一些;
- 手指落点为左侧边,x方向滑动距离有一些就行
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的默认分发 if (ev.getaction() == motionevent.action_down) { onuserinteraction(); } if (getwindow().superdispatchtouchevent(ev)) { return true; } return true; }
根布局位移动画
根据手指滑动距离设置根布局偏移距离,用滑动距离和手指抬起时的速度判断是否返回
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); } //测量手指抬起时的速度 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; } //根据手指滑动距离设置根布局偏移距离 rootview.settranslationx(rootview.gettranslationx() + event.getrawx() - lastx); if (rootview.gettranslationx() < 0) rootview.settranslationx(0); lastx = event.getrawx(); break; } case motionevent.action_up: { //测量手指抬起时的速度 velocitytracker.computecurrentvelocity(1000, maxflingvelocity); float velocityx = velocitytracker.getxvelocity(); if (velocitytracker != null) { velocitytracker.recycle(); velocitytracker = null; } //判断是否返回 if (downx < 50 && velocityx > 1000) { //手指在左侧边落下,返回 onback(); } else if (velocityx > 3600) { //手指快速滑动,返回 onback(); } else if (rootview.gettranslationx() > convertutil.getwidthinpx() * 0.3) { //滑动距离超过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); }
添加左侧阴影
activity的最顶层view为decorview,decorview是一个framelayout,里面只有一个linearlayout,linearlayout包含着标题栏和自定义布局(setcontentview)。
上一步跟随手指滑动进行偏移的就是linearlayout,现在要在decorview里添加一个view,设置背景作为阴影,并跟随linearlayout进行移动
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; } //根据手指滑动距离设置根布局偏移距离 rootview.settranslationx(rootview.gettranslationx() + event.getrawx() - lastx); if (rootview.gettranslationx() < 0) rootview.settranslationx(0); //阴影跟随根布局移动 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(); } ... } } ... }
关联下层activity滑动
- 保存所有的activity以获取下层activity
- 给下层activity添加退出和进入的动画
- 在上层activity滑动时调用下层滑动
获取下层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的退出、进入动画
private void loweractivityexitanim() { if (rootview == null) return; //只移动30% 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((long) (300f * r)).start(); }
在跳转时,调用下层activity的退出、进入动画
@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滑动时关联下层滑动
@override public boolean ontouchevent(motionevent event) { ... switch (event.getaction()) { ... case motionevent.action_move: { ... //根据手指滑动距离设置根布局偏移距离 rootview.settranslationx(rootview.gettranslationx() + event.getrawx() - lastx); if (rootview.gettranslationx() < 0) rootview.settranslationx(0); //阴影跟随根布局移动 shadowview.settranslationx(-shadowview.getwidth() + rootview.gettranslationx()); //下层activity跟随移动 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偏移复原 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的默认分发 if (ev.getaction() == motionevent.action_down) { onuserinteraction(); } if (getwindow().superdispatchtouchevent(ev)) { return true; } return true; } @override public boolean ontouchevent(motionevent event) { initshadow(); //测量手指抬起时的速度 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; } //根据手指滑动距离设置根布局偏移距离 rootview.settranslationx(rootview.gettranslationx() + event.getrawx() - lastx); if (rootview.gettranslationx() < 0) rootview.settranslationx(0); //阴影跟随根布局移动 shadowview.settranslationx(-shadowview.getwidth() + rootview.gettranslationx()); //下层activity跟随移动 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: { //测量手指抬起时的速度 velocitytracker.computecurrentvelocity(1000, maxflingvelocity); float velocityx = velocitytracker.getxvelocity(); if (velocitytracker != null) { velocitytracker.recycle(); velocitytracker = null; } //判断是否返回 if (downx < 50 && velocityx > 1000) { //手指在左侧边落下,返回 onback(); } else if (velocityx > 3600) { //手指快速滑动,返回 onback(); } else if (rootview.gettranslationx() > convertutil.getwidthinpx() * 0.3) { //滑动距离超过30%屏幕宽度,返回 onback(); } else { //不返回,根布局偏移归零 rootview.animate().translationx(0).setduration(200).start(); //阴影偏移归零 shadowview.animate().translationx(-shadowview.getwidth()).setduration(200).start(); //下层activity偏移复原 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(); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。