欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中SwipeBack实现右滑返回效果

程序员文章站 2024-02-22 08:41:52
现在有很多app支持右滑返回,比如知乎,效果比较赞。 于是自己对activity和fragment进行了继承,派生出swipebackactivity和swipeba...

现在有很多app支持右滑返回,比如知乎,效果比较赞。

Android中SwipeBack实现右滑返回效果

于是自己对activity和fragment进行了继承,派生出swipebackactivity和swipebackfragment,用于对这种效果的实现,也就是只要继承这两个类就可以了。

效果如下

  • activity

Android中SwipeBack实现右滑返回效果

fragment

frgament的效果实现比activity稍微简单,因为activity要考虑到dectorview。

支持滑动的控件swipelayout,核心思路就是把原有的控件添加到支持滑动的控件中,swipelayout要注意计算手势速度,源码如下:

Android中SwipeBack实现右滑返回效果

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();
  }
}

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