当前位置: 移动技术网 > 移动技术>移动开发>Android > Android中SwipeBack实现右滑返回效果

Android中SwipeBack实现右滑返回效果

2019年07月24日  | 移动技术网移动技术  | 我要评论

现在有很多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();
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网