Android中SwipeBack实现右滑返回效果
程序员文章站
2024-02-22 08:41:52
现在有很多app支持右滑返回,比如知乎,效果比较赞。
于是自己对activity和fragment进行了继承,派生出swipebackactivity和swipeba...
现在有很多app支持右滑返回,比如知乎,效果比较赞。
于是自己对activity和fragment进行了继承,派生出swipebackactivity和swipebackfragment,用于对这种效果的实现,也就是只要继承这两个类就可以了。
效果如下
- activity
fragment
frgament的效果实现比activity稍微简单,因为activity要考虑到dectorview。
支持滑动的控件swipelayout,核心思路就是把原有的控件添加到支持滑动的控件中,swipelayout要注意计算手势速度,源码如下:
package com.ui.jerry.swipebackdemo; import android.content.context; import android.util.attributeset; import android.util.log; import android.view.layoutinflater; import android.view.motionevent; import android.view.velocitytracker; import android.view.view; import android.view.viewconfiguration; import android.view.viewgroup; import android.widget.linearlayout; import android.widget.scroller; import android.widget.toast; public class swipelayout extends linearlayout { public static final string tag = "swipelayout"; private view memptyview; private view mcontentview; private int mleftedge; private int mwidth; private int mmaxscrollx; private scroller mscroller; private velocitytracker mvelocitytracker = null; private int mmaxflingvelocity; private int mlastx; viewgroup.layoutparams childparams = new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.match_parent); private context mcontext; public static final int duration = 1500; //满屏滑动时间 public static final int open_anim_duration = 1000; public static int snap_velocity = 600; //最小的滑动速率 private onfinishlistener monfinishlistener; public swipelayout(context context) { this(context, null); } public swipelayout(context context, attributeset attrs) { super(context, attrs); mcontext = context; init(); } public void setonfinishlistener(onfinishlistener monfinishlistener) { this.monfinishlistener = monfinishlistener; } void init() { mscroller = new scroller(mcontext); mmaxflingvelocity = viewconfiguration.get(mcontext).getscaledmaximumflingvelocity(); mwidth = displayutils.getscreenwidth(mcontext) * 2; mmaxscrollx = mwidth / 2; mleftedge = mmaxscrollx - mmaxscrollx / 3; setorientation(linearlayout.horizontal); childparams.width = displayutils.getscreenwidth(mcontext); memptyview = layoutinflater.from(mcontext).inflate(r.layout.view_translate, null); addview(memptyview, childparams); } public void setcontentview(view contentview) { if (mcontentview != null) { removeview(mcontentview); } mcontentview = contentview; addview(contentview, childparams); postdelayed(new runnable() { @override public void run() { openactivityanimation(); } }, 200); } /** * 获取速度追踪器 * * @return */ private velocitytracker getvelocitytracker() { if (mvelocitytracker == null) { mvelocitytracker = velocitytracker.obtain(); } return mvelocitytracker; } /** * 回收速度追踪器 */ private void recyclevelocitytracker() { if (mvelocitytracker != null) { mvelocitytracker.clear(); mvelocitytracker.recycle(); mvelocitytracker = null; } } @override public boolean ontouchevent(motionevent ev) { //1.获取速度追踪器 getvelocitytracker(); //2.将当前事件纳入到追踪器中 mvelocitytracker.addmovement(ev); int pointid = -1; switch (ev.getaction()) { case motionevent.action_down: //如果屏幕的动画还没结束,你就按下了,我们就结束上一次动画,即开始这次新action_down的动画 // clearscrollhis(); mlastx = (int) ev.getx(); pointid = ev.getpointerid(0); break; case motionevent.action_move: int nextscrollx = (int) (mlastx - ev.getx() + getscrollx()); if (scrollto(nextscrollx)) { mlastx = (int) ev.getx(); } break; case motionevent.action_cancel: case motionevent.action_up: //3.计算当前速度 mvelocitytracker.computecurrentvelocity(1000, mmaxflingvelocity); //获取x y方向上的速度 float vx = mvelocitytracker.getxvelocity(pointid); log.i(tag, "mvelocityx:" + vx); //大于某个速率 直接滑动 if (vx > snap_velocity) { scrolltoleft(); } else if (vx < -snap_velocity) { scrolltoright(); } else { snaptodestation(); } //4.回收速度追踪器 recyclevelocitytracker(); break; } return true; } private void openactivityanimation() { clearscrollhis(); mscroller.startscroll(getscrollx(), 0, mmaxscrollx - getscrollx(), 0, open_anim_duration); invalidate();//这里必须调用invalidate()才能保证computescroll()会被调用,否则不一定会刷新界面,看不到滚动效果 } public void closeactivityanimation() { clearscrollhis(); mscroller.startscroll(getscrollx(), 0, -getscrollx(), 0, open_anim_duration); invalidate();//这里必须调用invalidate()才能保证computescroll()会被调用,否则不一定会刷新界面,看不到滚动效果 } private void clearscrollhis() { if (mscroller != null) { if (!mscroller.isfinished()) { mscroller.abortanimation(); } } } /** * 根据现在的滚动位置判断 */ private void snaptodestation() { int scrollx = getscrollx(); if (scrollx > 0 && scrollx <= mleftedge) { smoothscrollto(0); } else if (scrollx > mleftedge) { smoothscrollto(mmaxscrollx); } } /** * 直接滚动 * * @param x * @return */ public boolean scrollto(int x) { if (x < 0) { scrollto(0, 0); } else if (x > mmaxscrollx) { scrollto(mmaxscrollx, 0); } else { scrollto(x, 0); } return true; } public void scrolltoright() { smoothscrollto(mmaxscrollx); } public void scrolltoleft() { smoothscrollto(0); } @override protected void onscrollchanged(int l, int t, int oldl, int oldt) { super.onscrollchanged(l, t, oldl, oldt); log.d(tag, "left:" + l); if (l == 0) { log.d(tag, "onfinish"); toast.maketext(mcontext, "finished", toast.length_short).show(); if(monfinishlistener!=null){ monfinishlistener.onfinish(); } } } public void smoothscrollto(int fx) { if (fx < 0) { smoothscrollto(0, 0); } else if (fx > mmaxscrollx) { smoothscrollto(mmaxscrollx, 0); } else { smoothscrollto(fx, 0); } } // //调用此方法滚动到目标位置 public void smoothscrollto(int fx, int fy) { int dx = fx - getscrollx(); int dy = fy - getscrolly(); smoothscrollby(dx, dy); } //调用此方法设置滚动的相对偏移 public void smoothscrollby(int dx, int dy) { //设置mscroller的滚动偏移量 mscroller.startscroll(getscrollx(), 0, dx, dy, math.abs(dx * duration / mmaxscrollx)); invalidate();//这里必须调用invalidate()才能保证computescroll()会被调用,否则不一定会刷新界面,看不到滚动效果 } @override public void computescroll() { //先判断mscroller滚动是否完成 if (mscroller.computescrolloffset()) { //这里调用view的scrollto()完成实际的滚动 scrollto(mscroller.getcurrx(), mscroller.getcurry()); //必须调用该方法,否则不一定能看到滚动效果 postinvalidate(); } super.computescroll(); } /** * fragment或者activity 结束的接口 */ public interface onfinishlistener{ void onfinish(); } }
以上就是本文的全部内容,希望对大家的学习有所帮助。