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

Android侧滑效果简单实现代码

程序员文章站 2024-02-28 13:56:28
先看看效果: 首先,导入包:compile files('libs/nineoldandroids-2.4.0.jar') r然后在main中创建一个wi...

先看看效果:

Android侧滑效果简单实现代码

首先,导入包:compile files('libs/nineoldandroids-2.4.0.jar')

r然后在main中创建一个widget包。
c创建viewdraghelper类

public class viewdraghelper {
 private static final string tag = "viewdraghelper";
 public static final int invalid_pointer = -1
 public static final int state_idle = 0;
 public static final int state_dragging = 1;
 public static final int state_settling = 2;
 public static final int edge_left = 1 << 0;
 public static final int edge_right = 1 << 1
 public static final int edge_top = 1 << 2;
 public static final int edge_bottom = 1 << 3
 public static final int edge_all = edge_left | edge_top | edge_right | edge_bottom;
 public static final int direction_horizontal = 1 << 0;
 public static final int direction_vertical = 1 << 1;
 public static final int direction_all = direction_horizontal | direction_vertical;
 private static final int edge_size = 20; // dp
 private static final int base_settle_duration = 256; // ms
 private static final int max_settle_duration = 600; // ms
 // current drag state; idle, dragging or settling
 private int mdragstate;

 // distance to travel before a drag may begin
 private int mtouchslop;

 // last known position/pointer tracking
 private int mactivepointerid = invalid_pointer;
 private float[] minitialmotionx;
 private float[] minitialmotiony;
 private float[] mlastmotionx;
 private float[] mlastmotiony;
 private int[] minitialedgestouched;
 private int[] medgedragsinprogress;
 private int[] medgedragslocked;
 private int mpointersdown;

 private velocitytracker mvelocitytracker;
 private final float mmaxvelocity;
 private float mminvelocity;

 private final int medgesize;
 private int mtrackingedges;

 private final scrollercompat mscroller;

 private final callback mcallback;

 private view mcapturedview;
 private boolean mreleaseinprogress;

 private final viewgroup mparentview;


 private static final interpolator sinterpolator = new interpolator() {
  public float getinterpolation(float t) {
   t -= 1.0f;
   return t * t * t * t * t + 1.0f;
  }
 };

 private final runnable msetidlerunnable = new runnable() {
  public void run() {
   setdragstate(state_idle);
  }
 };

 private viewdraghelper(context context, viewgroup forparent, callback cb) {
  if (forparent == null) {
   throw new illegalargumentexception("parent view may not be null");
  }
  if (cb == null) {
   throw new illegalargumentexception("callback may not be null");
  }

  mparentview = forparent;
  mcallback = cb;

  final viewconfiguration vc = viewconfiguration.get(context);
  final float density = context.getresources().getdisplaymetrics().density;
  medgesize = (int) (edge_size * density + 0.5f);

  mtouchslop = vc.getscaledtouchslop();
  mmaxvelocity = vc.getscaledmaximumflingvelocity();
  mminvelocity = vc.getscaledminimumflingvelocity();
  mscroller = scrollercompat.create(context, sinterpolator);
 }

 public static abstract class callback {

  public void onviewdragstatechanged(int state) {}

  public void onviewpositionchanged(view changedview, int left, int top, int dx, int dy) {}


  public void onviewcaptured(view capturedchild, int activepointerid) {}


  public void onviewreleased(view releasedchild, float xvel, float yvel) {}

  public void onedgetouched(int edgeflags, int pointerid) {}

  public boolean onedgelock(int edgeflags) {
   return false;
  }

  public void onedgedragstarted(int edgeflags, int pointerid) {}


  public int getorderedchildindex(int index) {
   return index;
  }

  public int getviewhorizontaldragrange(view child) {
   return 0;
  }


  public int getviewverticaldragrange(view child) {
   return 0;
  }

  public abstract boolean trycaptureview(view child, int pointerid);


  public int clampviewpositionhorizontal(view child, int left, int dx) {
   return 0;
  }

  public int clampviewpositionvertical(view child, int top, int dy) {
   return 0;
  }
 }


 public static viewdraghelper create(viewgroup forparent, callback cb) {
  return new viewdraghelper(forparent.getcontext(), forparent, cb);
 }

 public static viewdraghelper create(viewgroup forparent, float sensitivity, callback cb) {
  final viewdraghelper helper = create(forparent, cb);
  helper.mtouchslop = (int) (helper.mtouchslop * (1 / sensitivity));
  return helper;
 }

 public void setminvelocity(float minvel) {
  mminvelocity = minvel;
 }


 public float getminvelocity() {
  return mminvelocity;
 }


 public int getviewdragstate() {
  return mdragstate;
 }

 public void setedgetrackingenabled(int edgeflags) {
  mtrackingedges = edgeflags;
 }


 public int getedgesize() {
  return medgesize;
 }

 public void capturechildview(view childview, int activepointerid) {
  if (childview.getparent() != mparentview) {
   throw new illegalargumentexception("capturechildview: parameter must be a descendant " +
     "of the viewdraghelper's tracked parent view (" + mparentview + ")");
  }

  mcapturedview = childview;
  mactivepointerid = activepointerid;
  mcallback.onviewcaptured(childview, activepointerid);
  setdragstate(state_dragging);
 }

 public view getcapturedview() {
  return mcapturedview;
 }

 public int getactivepointerid() {
  return mactivepointerid;
 }

 public int gettouchslop() {
  return mtouchslop;
 }

 public void cancel() {
  mactivepointerid = invalid_pointer;
  clearmotionhistory();

  if (mvelocitytracker != null) {
   mvelocitytracker.recycle();
   mvelocitytracker = null;
  }
 }

 public void abort() {
  cancel();
  if (mdragstate == state_settling) {
   final int oldx = mscroller.getcurrx();
   final int oldy = mscroller.getcurry();
   mscroller.abortanimation();
   final int newx = mscroller.getcurrx();
   final int newy = mscroller.getcurry();
   mcallback.onviewpositionchanged(mcapturedview, newx, newy, newx - oldx, newy - oldy);
  }
  setdragstate(state_idle);
 }


 public boolean smoothslideviewto(view child, int finalleft, int finaltop) {
  mcapturedview = child;
  mactivepointerid = invalid_pointer;

  boolean continuesliding = forcesettlecapturedviewat(finalleft, finaltop, 0, 0);
  if (!continuesliding && mdragstate == state_idle && mcapturedview != null) {
   // if we're in an idle state to begin with and aren't moving anywhere, we
   // end up having a non-null capturedview with an idle dragstate
   mcapturedview = null;
  }

  return continuesliding;
 }


 public boolean settlecapturedviewat(int finalleft, int finaltop) {
  if (!mreleaseinprogress) {
   throw new illegalstateexception("cannot settlecapturedviewat outside of a call to " +
     "callback#onviewreleased");
  }

  return forcesettlecapturedviewat(finalleft, finaltop,
    (int) velocitytrackercompat.getxvelocity(mvelocitytracker, mactivepointerid),
    (int) velocitytrackercompat.getyvelocity(mvelocitytracker, mactivepointerid));
 }

 private boolean forcesettlecapturedviewat(int finalleft, int finaltop, int xvel, int yvel) {
  final int startleft = mcapturedview.getleft();
  final int starttop = mcapturedview.gettop();
  final int dx = finalleft - startleft;
  final int dy = finaltop - starttop;

  if (dx == 0 && dy == 0) {
   // nothing to do. send callbacks, be done.
   mscroller.abortanimation();
   setdragstate(state_idle);
   return false;
  }

  final int duration = computesettleduration(mcapturedview, dx, dy, xvel, yvel);
  mscroller.startscroll(startleft, starttop, dx, dy, duration);

  setdragstate(state_settling);
  return true;
 }

 private int computesettleduration(view child, int dx, int dy, int xvel, int yvel) {
  xvel = clampmag(xvel, (int) mminvelocity, (int) mmaxvelocity);
  yvel = clampmag(yvel, (int) mminvelocity, (int) mmaxvelocity);
  final int absdx = math.abs(dx);
  final int absdy = math.abs(dy);
  final int absxvel = math.abs(xvel);
  final int absyvel = math.abs(yvel);
  final int addedvel = absxvel + absyvel;
  final int addeddistance = absdx + absdy;

  final float xweight = xvel != 0 ? (float) absxvel / addedvel :
    (float) absdx / addeddistance;
  final float yweight = yvel != 0 ? (float) absyvel / addedvel :
    (float) absdy / addeddistance;

  int xduration = computeaxisduration(dx, xvel, mcallback.getviewhorizontaldragrange(child));
  int yduration = computeaxisduration(dy, yvel, mcallback.getviewverticaldragrange(child));

  return (int) (xduration * xweight + yduration * yweight);
 }

 private int computeaxisduration(int delta, int velocity, int motionrange) {
  if (delta == 0) {
   return 0;
  }

  final int width = mparentview.getwidth();
  final int halfwidth = width / 2;
  final float distanceratio = math.min(1f, (float) math.abs(delta) / width);
  final float distance = halfwidth + halfwidth *
    distanceinfluenceforsnapduration(distanceratio);

  int duration;
  velocity = math.abs(velocity);
  if (velocity > 0) {
   duration = 4 * math.round(1000 * math.abs(distance / velocity));
  } else {
   final float range = (float) math.abs(delta) / motionrange;
   duration = (int) ((range + 1) * base_settle_duration);
  }
  return math.min(duration, max_settle_duration);
 }


 private static int clampmag(int value, int absmin, int absmax) {
  final int absvalue = math.abs(value);
  if (absvalue < absmin) return 0;
  if (absvalue > absmax) return value > 0 ? absmax : -absmax;
  return value;
 }


 private static float clampmag(float value, float absmin, float absmax) {
  final float absvalue = math.abs(value);
  if (absvalue < absmin) return 0;
  if (absvalue > absmax) return value > 0 ? absmax : -absmax;
  return value;
 }

 private static float distanceinfluenceforsnapduration(float f) {
  f -= 0.5f; // center the values about 0.
  f *= 0.3f * math.pi / 2.0f;
  return (float) math.sin(f);
 }


 public void flingcapturedview(int minleft, int mintop, int maxleft, int maxtop) {
  if (!mreleaseinprogress) {
   throw new illegalstateexception("cannot flingcapturedview outside of a call to " +
     "callback#onviewreleased");
  }

  mscroller.fling(mcapturedview.getleft(), mcapturedview.gettop(),
    (int) velocitytrackercompat.getxvelocity(mvelocitytracker, mactivepointerid),
    (int) velocitytrackercompat.getyvelocity(mvelocitytracker, mactivepointerid),
    minleft, maxleft, mintop, maxtop);

  setdragstate(state_settling);
 }


 public boolean continuesettling(boolean defercallbacks) {
  if (mdragstate == state_settling) {
   boolean keepgoing = mscroller.computescrolloffset();
   final int x = mscroller.getcurrx();
   final int y = mscroller.getcurry();
   final int dx = x - mcapturedview.getleft();
   final int dy = y - mcapturedview.gettop();

   if (dx != 0) {
    mcapturedview.offsetleftandright(dx);
   }
   if (dy != 0) {
    mcapturedview.offsettopandbottom(dy);
   }

   if (dx != 0 || dy != 0) {
    mcallback.onviewpositionchanged(mcapturedview, x, y, dx, dy);
   }

   if (keepgoing && x == mscroller.getfinalx() && y == mscroller.getfinaly()) {
    // close enough. the interpolator/scroller might think we're still moving
    // but the user sure doesn't.
    mscroller.abortanimation();
    keepgoing = false;
   }

   if (!keepgoing) {
    if (defercallbacks) {
     mparentview.post(msetidlerunnable);
    } else {
     setdragstate(state_idle);
    }
   }
  }

  return mdragstate == state_settling;
 }


 private void dispatchviewreleased(float xvel, float yvel) {
  mreleaseinprogress = true;
  mcallback.onviewreleased(mcapturedview, xvel, yvel);
  mreleaseinprogress = false;

  if (mdragstate == state_dragging) {
   // onviewreleased didn't call a method that would have changed this. go idle.
   setdragstate(state_idle);
  }
 }

 private void clearmotionhistory() {
  if (minitialmotionx == null) {
   return;
  }
  arrays.fill(minitialmotionx, 0);
  arrays.fill(minitialmotiony, 0);
  arrays.fill(mlastmotionx, 0);
  arrays.fill(mlastmotiony, 0);
  arrays.fill(minitialedgestouched, 0);
  arrays.fill(medgedragsinprogress, 0);
  arrays.fill(medgedragslocked, 0);
  mpointersdown = 0;
 }

 private void clearmotionhistory(int pointerid) {
  if (minitialmotionx == null) {
   return;
  }
  minitialmotionx[pointerid] = 0;
  minitialmotiony[pointerid] = 0;
  mlastmotionx[pointerid] = 0;
  mlastmotiony[pointerid] = 0;
  minitialedgestouched[pointerid] = 0;
  medgedragsinprogress[pointerid] = 0;
  medgedragslocked[pointerid] = 0;
  mpointersdown &= ~(1 << pointerid);
 }

 private void ensuremotionhistorysizeforid(int pointerid) {
  if (minitialmotionx == null || minitialmotionx.length <= pointerid) {
   float[] imx = new float[pointerid + 1];
   float[] imy = new float[pointerid + 1];
   float[] lmx = new float[pointerid + 1];
   float[] lmy = new float[pointerid + 1];
   int[] iit = new int[pointerid + 1];
   int[] edip = new int[pointerid + 1];
   int[] edl = new int[pointerid + 1];

   if (minitialmotionx != null) {
    system.arraycopy(minitialmotionx, 0, imx, 0, minitialmotionx.length);
    system.arraycopy(minitialmotiony, 0, imy, 0, minitialmotiony.length);
    system.arraycopy(mlastmotionx, 0, lmx, 0, mlastmotionx.length);
    system.arraycopy(mlastmotiony, 0, lmy, 0, mlastmotiony.length);
    system.arraycopy(minitialedgestouched, 0, iit, 0, minitialedgestouched.length);
    system.arraycopy(medgedragsinprogress, 0, edip, 0, medgedragsinprogress.length);
    system.arraycopy(medgedragslocked, 0, edl, 0, medgedragslocked.length);
   }

   minitialmotionx = imx;
   minitialmotiony = imy;
   mlastmotionx = lmx;
   mlastmotiony = lmy;
   minitialedgestouched = iit;
   medgedragsinprogress = edip;
   medgedragslocked = edl;
  }
 }

 private void saveinitialmotion(float x, float y, int pointerid) {
  ensuremotionhistorysizeforid(pointerid);
  minitialmotionx[pointerid] = mlastmotionx[pointerid] = x;
  minitialmotiony[pointerid] = mlastmotiony[pointerid] = y;
  minitialedgestouched[pointerid] = getedgestouched((int) x, (int) y);
  mpointersdown |= 1 << pointerid;
 }

 private void savelastmotion(motionevent ev) {
  final int pointercount = motioneventcompat.getpointercount(ev);
  for (int i = 0; i < pointercount; i++) {
   final int pointerid = motioneventcompat.getpointerid(ev, i);
   final float x = motioneventcompat.getx(ev, i);
   final float y = motioneventcompat.gety(ev, i);
   mlastmotionx[pointerid] = x;
   mlastmotiony[pointerid] = y;
  }
 }

 public boolean ispointerdown(int pointerid) {
  return (mpointersdown & 1 << pointerid) != 0;
 }

 void setdragstate(int state) {
  mparentview.removecallbacks(msetidlerunnable);
  if (mdragstate != state) {
   mdragstate = state;
   mcallback.onviewdragstatechanged(state);
   if (mdragstate == state_idle) {
    mcapturedview = null;
   }
  }
 }

 boolean trycaptureviewfordrag(view tocapture, int pointerid) {
  if (tocapture == mcapturedview && mactivepointerid == pointerid) {
   // already done!
   return true;
  }
  if (tocapture != null && mcallback.trycaptureview(tocapture, pointerid)) {
   mactivepointerid = pointerid;
   capturechildview(tocapture, pointerid);
   return true;
  }
  return false;
 }


 protected boolean canscroll(view v, boolean checkv, int dx, int dy, int x, int y) {
  if (v instanceof viewgroup) {
   final viewgroup group = (viewgroup) v;
   final int scrollx = v.getscrollx();
   final int scrolly = v.getscrolly();
   final int count = group.getchildcount();
   // count backwards - let topmost views consume scroll distance first.
   for (int i = count - 1; i >= 0; i--) {
    // todo: add versioned support here for transformed views.
    // this will not work for transformed views in honeycomb+
    final view child = group.getchildat(i);
    if (x + scrollx >= child.getleft() && x + scrollx < child.getright() &&
      y + scrolly >= child.gettop() && y + scrolly < child.getbottom() &&
      canscroll(child, true, dx, dy, x + scrollx - child.getleft(),
        y + scrolly - child.gettop())) {
     return true;
    }
   }
  }

  return checkv && (viewcompat.canscrollhorizontally(v, -dx) ||
    viewcompat.canscrollvertically(v, -dy));
 }

 public boolean shouldintercepttouchevent(motionevent ev) {
  final int action = motioneventcompat.getactionmasked(ev);
  final int actionindex = motioneventcompat.getactionindex(ev);

  if (action == motionevent.action_down) {
   // reset things for a new event stream, just in case we didn't get
   // the whole previous stream.
   cancel();
  }

  if (mvelocitytracker == null) {
   mvelocitytracker = velocitytracker.obtain();
  }
  mvelocitytracker.addmovement(ev);

  switch (action) {
   case motionevent.action_down: {
    final float x = ev.getx();
    final float y = ev.gety();
    final int pointerid = motioneventcompat.getpointerid(ev, 0);
    saveinitialmotion(x, y, pointerid);

    final view tocapture = findtopchildunder((int) x, (int) y);

    // catch a settling view if possible.
    if (tocapture == mcapturedview && mdragstate == state_settling) {
     trycaptureviewfordrag(tocapture, pointerid);
    }

    final int edgestouched = minitialedgestouched[pointerid];
    if ((edgestouched & mtrackingedges) != 0) {
     mcallback.onedgetouched(edgestouched & mtrackingedges, pointerid);
    }
    break;
   }

   case motioneventcompat.action_pointer_down: {
    final int pointerid = motioneventcompat.getpointerid(ev, actionindex);
    final float x = motioneventcompat.getx(ev, actionindex);
    final float y = motioneventcompat.gety(ev, actionindex);

    saveinitialmotion(x, y, pointerid);

    // a viewdraghelper can only manipulate one view at a time.
    if (mdragstate == state_idle) {
     final int edgestouched = minitialedgestouched[pointerid];
     if ((edgestouched & mtrackingedges) != 0) {
      mcallback.onedgetouched(edgestouched & mtrackingedges, pointerid);
     }
    } else if (mdragstate == state_settling) {
     // catch a settling view if possible.
     final view tocapture = findtopchildunder((int) x, (int) y);
     if (tocapture == mcapturedview) {
      trycaptureviewfordrag(tocapture, pointerid);
     }
    }
    break;
   }

   case motionevent.action_move: {
    if (minitialmotionx == null || minitialmotiony == null) break;

    // first to cross a touch slop over a draggable view wins. also report edge drags.
    final int pointercount = motioneventcompat.getpointercount(ev);
    for (int i = 0; i < pointercount; i++) {
     final int pointerid = motioneventcompat.getpointerid(ev, i);
     final float x = motioneventcompat.getx(ev, i);
     final float y = motioneventcompat.gety(ev, i);
     final float dx = x - minitialmotionx[pointerid];
     final float dy = y - minitialmotiony[pointerid];

     final view tocapture = findtopchildunder((int) x, (int) y);
     final boolean pastslop = tocapture != null && checktouchslop(tocapture, dx, dy);
     if (pastslop) {
      // check the callback's
      // getview[horizontal|vertical]dragrange methods to know
      // if you can move at all along an axis, then see if it
      // would clamp to the same value. if you can't move at
      // all in every dimension with a nonzero range, bail.
      final int oldleft = tocapture.getleft();
      final int targetleft = oldleft + (int) dx;
      final int newleft = mcallback.clampviewpositionhorizontal(tocapture,
        targetleft, (int) dx);
      final int oldtop = tocapture.gettop();
      final int targettop = oldtop + (int) dy;
      final int newtop = mcallback.clampviewpositionvertical(tocapture, targettop,
        (int) dy);
      final int horizontaldragrange = mcallback.getviewhorizontaldragrange(
        tocapture);
      final int verticaldragrange = mcallback.getviewverticaldragrange(tocapture);
      if ((horizontaldragrange == 0 || horizontaldragrange > 0
        && newleft == oldleft) && (verticaldragrange == 0
        || verticaldragrange > 0 && newtop == oldtop)) {
       break;
      }
     }
     reportnewedgedrags(dx, dy, pointerid);
     if (mdragstate == state_dragging) {
      // callback might have started an edge drag
      break;
     }

     if (pastslop && trycaptureviewfordrag(tocapture, pointerid)) {
      break;
     }
    }
    savelastmotion(ev);
    break;
   }

   case motioneventcompat.action_pointer_up: {
    final int pointerid = motioneventcompat.getpointerid(ev, actionindex);
    clearmotionhistory(pointerid);
    break;
   }

   case motionevent.action_up:
   case motionevent.action_cancel: {
    cancel();
    break;
   }
   default:
    break;
  }

  return mdragstate == state_dragging;
 }

 public void processtouchevent(motionevent ev) {
  final int action = motioneventcompat.getactionmasked(ev);
  final int actionindex = motioneventcompat.getactionindex(ev);

  if (action == motionevent.action_down) {
   // reset things for a new event stream, just in case we didn't get
   // the whole previous stream.
   cancel();
  }

  if (mvelocitytracker == null) {
   mvelocitytracker = velocitytracker.obtain();
  }
  mvelocitytracker.addmovement(ev);

  switch (action) {
   case motionevent.action_down: {
    final float x = ev.getx();
    final float y = ev.gety();
    final int pointerid = motioneventcompat.getpointerid(ev, 0);
    final view tocapture = findtopchildunder((int) x, (int) y);

    saveinitialmotion(x, y, pointerid);

    // since the parent is already directly processing this touch event,
    // there is no reason to delay for a slop before dragging.
    // start immediately if possible.
    trycaptureviewfordrag(tocapture, pointerid);

    final int edgestouched = minitialedgestouched[pointerid];
    if ((edgestouched & mtrackingedges) != 0) {
     mcallback.onedgetouched(edgestouched & mtrackingedges, pointerid);
    }
    break;
   }

   case motioneventcompat.action_pointer_down: {
    final int pointerid = motioneventcompat.getpointerid(ev, actionindex);
    final float x = motioneventcompat.getx(ev, actionindex);
    final float y = motioneventcompat.gety(ev, actionindex);

    saveinitialmotion(x, y, pointerid);

    // a viewdraghelper can only manipulate one view at a time.
    if (mdragstate == state_idle) {
     // if we're idle we can do anything! treat it like a normal down event.

     final view tocapture = findtopchildunder((int) x, (int) y);
     trycaptureviewfordrag(tocapture, pointerid);

     final int edgestouched = minitialedgestouched[pointerid];
     if ((edgestouched & mtrackingedges) != 0) {
      mcallback.onedgetouched(edgestouched & mtrackingedges, pointerid);
     }
    } else if (iscapturedviewunder((int) x, (int) y)) {
     // we're still tracking a captured view. if the same view is under this
     // point, we'll swap to controlling it with this pointer instead.
     // (this will still work if we're "catching" a settling view.)

     trycaptureviewfordrag(mcapturedview, pointerid);
    }
    break;
   }

   case motionevent.action_move: {
    if (mdragstate == state_dragging) {
     final int index = motioneventcompat.findpointerindex(ev, mactivepointerid);
     final float x = motioneventcompat.getx(ev, index);
     final float y = motioneventcompat.gety(ev, index);
     final int idx = (int) (x - mlastmotionx[mactivepointerid]);
     final int idy = (int) (y - mlastmotiony[mactivepointerid]);

     dragto(mcapturedview.getleft() + idx, mcapturedview.gettop() + idy, idx, idy);

     savelastmotion(ev);
    } else {
     // check to see if any pointer is now over a draggable view.
     final int pointercount = motioneventcompat.getpointercount(ev);
     for (int i = 0; i < pointercount; i++) {
      final int pointerid = motioneventcompat.getpointerid(ev, i);
      final float x = motioneventcompat.getx(ev, i);
      final float y = motioneventcompat.gety(ev, i);
      final float dx = x - minitialmotionx[pointerid];
      final float dy = y - minitialmotiony[pointerid];

      reportnewedgedrags(dx, dy, pointerid);
      if (mdragstate == state_dragging) {
       // callback might have started an edge drag.
       break;
      }

      final view tocapture = findtopchildunder((int) x, (int) y);
      if (checktouchslop(tocapture, dx, dy) &&
        trycaptureviewfordrag(tocapture, pointerid)) {
       break;
      }
     }
     savelastmotion(ev);
    }
    break;
   }

   case motioneventcompat.action_pointer_up: {
    final int pointerid = motioneventcompat.getpointerid(ev, actionindex);
    if (mdragstate == state_dragging && pointerid == mactivepointerid) {
     // try to find another pointer that's still holding on to the captured view.
     int newactivepointer = invalid_pointer;
     final int pointercount = motioneventcompat.getpointercount(ev);
     for (int i = 0; i < pointercount; i++) {
      final int id = motioneventcompat.getpointerid(ev, i);
      if (id == mactivepointerid) {
       // this one's going away, skip.
       continue;
      }

      final float x = motioneventcompat.getx(ev, i);
      final float y = motioneventcompat.gety(ev, i);
      if (findtopchildunder((int) x, (int) y) == mcapturedview &&
        trycaptureviewfordrag(mcapturedview, id)) {
       newactivepointer = mactivepointerid;
       break;
      }
     }

     if (newactivepointer == invalid_pointer) {
      // we didn't find another pointer still touching the view, release it.
      releaseviewforpointerup();
     }
    }
    clearmotionhistory(pointerid);
    break;
   }

   case motionevent.action_up: {
    if (mdragstate == state_dragging) {
     releaseviewforpointerup();
    }
    cancel();
    break;
   }

   case motionevent.action_cancel: {
    if (mdragstate == state_dragging) {
     dispatchviewreleased(0, 0);
    }
    cancel();
    break;
   }
   default:
    break;

  }
 }

 private void reportnewedgedrags(float dx, float dy, int pointerid) {
  int dragsstarted = 0;
  if (checknewedgedrag(dx, dy, pointerid, edge_left)) {
   dragsstarted |= edge_left;
  }
  if (checknewedgedrag(dy, dx, pointerid, edge_top)) {
   dragsstarted |= edge_top;
  }
  if (checknewedgedrag(dx, dy, pointerid, edge_right)) {
   dragsstarted |= edge_right;
  }
  if (checknewedgedrag(dy, dx, pointerid, edge_bottom)) {
   dragsstarted |= edge_bottom;
  }

  if (dragsstarted != 0) {
   medgedragsinprogress[pointerid] |= dragsstarted;
   mcallback.onedgedragstarted(dragsstarted, pointerid);
  }
 }

 private boolean checknewedgedrag(float delta, float odelta, int pointerid, int edge) {
  final float absdelta = math.abs(delta);
  final float absodelta = math.abs(odelta);

  if ((minitialedgestouched[pointerid] & edge) != edge || (mtrackingedges & edge) == 0 ||
    (medgedragslocked[pointerid] & edge) == edge ||
    (medgedragsinprogress[pointerid] & edge) == edge ||
    (absdelta <= mtouchslop && absodelta <= mtouchslop)) {
   return false;
  }
  if (absdelta < absodelta * 0.5f && mcallback.onedgelock(edge)) {
   medgedragslocked[pointerid] |= edge;
   return false;
  }
  return (medgedragsinprogress[pointerid] & edge) == 0 && absdelta > mtouchslop;
 }


 private boolean checktouchslop(view child, float dx, float dy) {
  if (child == null) {
   return false;
  }
  final boolean checkhorizontal = mcallback.getviewhorizontaldragrange(child) > 0;
  final boolean checkvertical = mcallback.getviewverticaldragrange(child) > 0;

  if (checkhorizontal && checkvertical) {
   return dx * dx + dy * dy > mtouchslop * mtouchslop;
  } else if (checkhorizontal) {
   return math.abs(dx) > mtouchslop;
  } else if (checkvertical) {
   return math.abs(dy) > mtouchslop;
  }
  return false;
 }

 public boolean checktouchslop(int directions) {
  final int count = minitialmotionx.length;
  for (int i = 0; i < count; i++) {
   if (checktouchslop(directions, i)) {
    return true;
   }
  }
  return false;
 }


 public boolean checktouchslop(int directions, int pointerid) {
  if (!ispointerdown(pointerid)) {
   return false;
  }

  final boolean checkhorizontal = (directions & direction_horizontal) == direction_horizontal;
  final boolean checkvertical = (directions & direction_vertical) == direction_vertical;

  final float dx = mlastmotionx[pointerid] - minitialmotionx[pointerid];
  final float dy = mlastmotiony[pointerid] - minitialmotiony[pointerid];

  if (checkhorizontal && checkvertical) {
   return dx * dx + dy * dy > mtouchslop * mtouchslop;
  } else if (checkhorizontal) {
   return math.abs(dx) > mtouchslop;
  } else if (checkvertical) {
   return math.abs(dy) > mtouchslop;
  }
  return false;
 }

 public boolean isedgetouched(int edges) {
  final int count = minitialedgestouched.length;
  for (int i = 0; i < count; i++) {
   if (isedgetouched(edges, i)) {
    return true;
   }
  }
  return false;
 }


 public boolean isedgetouched(int edges, int pointerid) {
  return ispointerdown(pointerid) && (minitialedgestouched[pointerid] & edges) != 0;
 }

 private void releaseviewforpointerup() {
  mvelocitytracker.computecurrentvelocity(1000, mmaxvelocity);
  final float xvel = clampmag(
    velocitytrackercompat.getxvelocity(mvelocitytracker, mactivepointerid),
    mminvelocity, mmaxvelocity);
  final float yvel = clampmag(
    velocitytrackercompat.getyvelocity(mvelocitytracker, mactivepointerid),
    mminvelocity, mmaxvelocity);
  dispatchviewreleased(xvel, yvel);
 }

 private void dragto(int left, int top, int dx, int dy) {
  int clampedx = left;
  int clampedy = top;
  final int oldleft = mcapturedview.getleft();
  final int oldtop = mcapturedview.gettop();
  if (dx != 0) {
   clampedx = mcallback.clampviewpositionhorizontal(mcapturedview, left, dx);
   mcapturedview.offsetleftandright(clampedx - oldleft);
  }
  if (dy != 0) {
   clampedy = mcallback.clampviewpositionvertical(mcapturedview, top, dy);
   mcapturedview.offsettopandbottom(clampedy - oldtop);
  }

  if (dx != 0 || dy != 0) {
   final int clampeddx = clampedx - oldleft;
   final int clampeddy = clampedy - oldtop;
   mcallback.onviewpositionchanged(mcapturedview, clampedx, clampedy,
     clampeddx, clampeddy);
  }
 }


 public boolean iscapturedviewunder(int x, int y) {
  return isviewunder(mcapturedview, x, y);
 }

 public boolean isviewunder(view view, int x, int y) {
  if (view == null) {
   return false;
  }
  return x >= view.getleft() &&
    x < view.getright() &&
    y >= view.gettop() &&
    y < view.getbottom();
 }

 public view findtopchildunder(int x, int y) {
  final int childcount = mparentview.getchildcount();
  for (int i = childcount - 1; i >= 0; i--) {
   final view child = mparentview.getchildat(mcallback.getorderedchildindex(i));
   if (x >= child.getleft() && x < child.getright() &&
     y >= child.gettop() && y < child.getbottom()) {
    return child;
   }
  }
  return null;
 }

 private int getedgestouched(int x, int y) {
  int result = 0;

  if (x < mparentview.getleft() + medgesize) result |= edge_left;
  if (y < mparentview.gettop() + medgesize) result |= edge_top;
  if (x > mparentview.getright() - medgesize) result |= edge_right;
  if (y > mparentview.getbottom() - medgesize) result |= edge_bottom;

  return result;
 }
}

draglayout布局继承framelayout:

public class draglayout extends framelayout {

 private static final boolean is_show_shadow = true;
 //手势处理类
 private gesturedetectorcompat gesturedetector;
 //视图拖拽移动帮助类
 private viewdraghelper draghelper;
 //滑动监听器
 private draglistener draglistener;
 //水平拖拽的距离
 private int range;
 //宽度
 private int width;
 //高度
 private int height;
 //main视图距离在viewgroup距离左边的距离
 private int mainleft;
 private context context;
 private imageview ivshadow;
 //左侧布局
 private relativelayout vgleft;
 //右侧(主界面布局)
 private customrelativelayout vgmain;
 //页面状态 默认为关闭
 private status status = status.close;


 private final viewdraghelper.callback draghelpercallback = new viewdraghelper.callback() {

  @override
  public int clampviewpositionhorizontal(view child, int left, int dx) {
   if (mainleft + dx < 0) {
    return 0;
   } else if (mainleft + dx > range) {
    return range;
   } else {
    return left;
   }
  }

  @override
  public boolean trycaptureview(view child, int pointerid) {
   return true;
  }

  @override
  public int getviewhorizontaldragrange(view child) {
   return width;
  }


  @override
  public void onviewreleased(view releasedchild, float xvel, float yvel) {
   super.onviewreleased(releasedchild, xvel, yvel);
   if (xvel > 0) {
    open();
   } else if (xvel < 0) {
    close();
   } else if (releasedchild == vgmain && mainleft > range * 0.3) {
    open();
   } else if (releasedchild == vgleft && mainleft > range * 0.7) {
    open();
   } else {
    close();
   }
  }

  @override
  public void onviewpositionchanged(view changedview, int left, int top,
           int dx, int dy) {
   if (changedview == vgmain) {
    mainleft = left;
   } else {
    mainleft = mainleft + left;
   }
   if (mainleft < 0) {
    mainleft = 0;
   } else if (mainleft > range) {
    mainleft = range;
   }

   if (is_show_shadow) {
    ivshadow.layout(mainleft, 0, mainleft + width, height);
   }
   if (changedview == vgleft) {
    vgleft.layout(0, 0, width, height);
    vgmain.layout(mainleft, 0, mainleft + width, height);
   }

   dispatchdragevent(mainleft);
  }
 };

 public draglayout(context context) {
  this(context, null);
 }

 public draglayout(context context, attributeset attrs) {
  this(context, attrs, 0);
  this.context = context;
 }

 public draglayout(context context, attributeset attrs, int defstyle) {
  super(context, attrs, defstyle);
  gesturedetector = new gesturedetectorcompat(context, new yscrolldetector());
  draghelper = viewdraghelper.create(this, draghelpercallback);
 }

 class yscrolldetector extends gesturedetector.simpleongesturelistener {
  @override
  public boolean onscroll(motionevent e1, motionevent e2, float dx, float dy) {
   return math.abs(dy) <= math.abs(dx);
  }
 }

 /**
  * 滑动相关回调接口
  */
 public interface draglistener {
  //界面打开
  public void onopen();
  //界面关闭
  public void onclose();
  //界面滑动过程中
  public void ondrag(float percent);
 }
 public void setdraglistener(draglistener draglistener) {
  this.draglistener = draglistener;
 }

 /**
  * 布局加载完成回调
  * 做一些初始化的操作
  */
 @override
 protected void onfinishinflate() {
  super.onfinishinflate();
  if (is_show_shadow) {
   ivshadow = new imageview(context);
   ivshadow.setimageresource(r.mipmap.shadow);
   layoutparams lp = new layoutparams(layoutparams.match_parent, layoutparams.match_parent);
   addview(ivshadow, 1, lp);
  }
  //左侧界面
  vgleft = (relativelayout) getchildat(0);
  //右侧(主)界面
  vgmain = (customrelativelayout) getchildat(is_show_shadow ? 2 : 1);
  vgmain.setdraglayout(this);
  vgleft.setclickable(true);
  vgmain.setclickable(true);
 }

 public viewgroup getvgmain() {
  return vgmain;
 }

 public viewgroup getvgleft() {
  return vgleft;
 }

 @override
 protected void onsizechanged(int w, int h, int oldw, int oldh) {
  super.onsizechanged(w, h, oldw, oldh);
  width = vgleft.getmeasuredwidth();
  height = vgleft.getmeasuredheight();
  //可以水平拖拽滑动的距离 一共为屏幕宽度的80%
  range = (int) (width * 0.8f);
 }


 @override
 protected void onlayout(boolean changed, int left, int top, int right, int bottom) {
  vgleft.layout(0, 0, width, height);
  vgmain.layout(mainleft, 0, mainleft + width, height);
 }

 /**
  * 拦截触摸事件
  * @param ev
  * @return
  */
 @override
 public boolean onintercepttouchevent(motionevent ev) {
  return draghelper.shouldintercepttouchevent(ev) && gesturedetector.ontouchevent(ev);
 }

 /**
  * 将拦截的到事件给viewdraghelper进行处理
  * @param e
  * @return
  */
 @override
 public boolean ontouchevent(motionevent e) {
  try {
   draghelper.processtouchevent(e);
  } catch (exception ex) {
   ex.printstacktrace();
  }
  return false;
 }

 /**
  * 进行处理拖拽事件
  * @param mainleft
  */
 private void dispatchdragevent(int mainleft) {
  if (draglistener == null) {
   return;
  }
  float percent = mainleft / (float) range;
  //滑动动画效果
  animateview(percent);
  //进行回调滑动的百分比
  draglistener.ondrag(percent);
  status laststatus = status;
  if (laststatus != getstatus() && status == status.close) {
   draglistener.onclose();
  } else if (laststatus != getstatus() && status == status.open) {
   draglistener.onopen();
  }
 }

 /**
  * 根据滑动的距离的比例,进行平移动画
  * @param percent
  */
 private void animateview(float percent) {
  float f1 = 1 - percent * 0.5f;

  viewhelper.settranslationx(vgleft, -vgleft.getwidth() / 2.5f + vgleft.getwidth() / 2.5f * percent);
  if (is_show_shadow) {
   //阴影效果视图大小进行缩放
   viewhelper.setscalex(ivshadow, f1 * 1.2f * (1 - percent * 0.10f));
   viewhelper.setscaley(ivshadow, f1 * 1.85f * (1 - percent * 0.10f));
  }
 }
 /**
  * 有加速度,当我们停止滑动的时候,该不会立即停止动画效果
  */
 @override
 public void computescroll() {
  if (draghelper.continuesettling(true)) {
   viewcompat.postinvalidateonanimation(this);
  }
 }

 /**
  * 页面状态(滑动,打开,关闭)
  */
 public enum status {
  drag, open, close
 }

 /**
  * 页面状态设置
  * @return
  */
 public status getstatus() {
  if (mainleft == 0) {
   status = status.close;
  } else if (mainleft == range) {
   status = status.open;
  } else {
   status = status.drag;
  }
  return status;
 }

 public void open() {
  open(true);
 }

 public void open(boolean animate) {
  if (animate) {
   //继续滑动
   if (draghelper.smoothslideviewto(vgmain, range, 0)) {
    viewcompat.postinvalidateonanimation(this);
   }
  } else {
   vgmain.layout(range, 0, range * 2, height);
   dispatchdragevent(range);
  }
 }

 public void close() {
  close(true);
 }

 public void close(boolean animate) {
  if (animate) {
   //继续滑动
   if (draghelper.smoothslideviewto(vgmain, 0, 0)) {
    viewcompat.postinvalidateonanimation(this);
   }
  } else {
   vgmain.layout(0, 0, width, height);
   dispatchdragevent(0);
  }
 }
}

customrelativelayout:

public class customrelativelayout extends relativelayout {
 private draglayout dl;
 public customrelativelayout(context context) {
  super(context);
 }

 public customrelativelayout(context context, attributeset attrs) {
  super(context, attrs);
 }

 public customrelativelayout(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
 }

 public void setdraglayout(draglayout dl) {
  this.dl = dl;
 }

 @override
 public boolean onintercepttouchevent(motionevent event) {
  if (dl.getstatus() != draglayout.status.close) {
   return true;
  }
  return super.onintercepttouchevent(event);
 }

 @override
 public boolean ontouchevent(motionevent event) {
  if (dl.getstatus() != draglayout.status.close) {
   if (event.getaction() == motionevent.action_up) {
    dl.close();
   }
   return true;
  }
  return super.ontouchevent(event);
 }

}

c沉浸式状态栏:baseactivity:

public class baseactivity extends fragmentactivity {
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  this.requestwindowfeature(window.feature_no_title);
  if (build.version.sdk_int >= build.version_codes.kitkat) {
   //透明状态栏
   getwindow().addflags(windowmanager.layoutparams.flag_translucent_status);
   //透明导航栏
   getwindow().addflags(windowmanager.layoutparams.flag_translucent_navigation);
  }
 }
 /**
  * 设置沉浸式状态栏
  */
 protected void setstatusbar() {
  if (build.version.sdk_int >= build.version_codes.kitkat) {
   final viewgroup linear_bar = (viewgroup) findviewbyid(r.id.rl_title);
   final int statusheight = getstatusbarheight();
   linear_bar.post(new runnable() {
    @override
    public void run() {
     int titleheight = linear_bar.getheight();
     android.widget.linearlayout.layoutparams params = (android.widget.linearlayout.layoutparams) linear_bar.getlayoutparams();
     params.height = statusheight + titleheight;
     linear_bar.setlayoutparams(params);
    }
   });
  }
 }
 /**
  * 获取状态栏的高度
  * @return
  */
 protected int getstatusbarheight(){
  try
  {
   class<?> c=class.forname("com.android.internal.r$dimen");
   object obj=c.newinstance();
   field field=c.getfield("status_bar_height");
   int x=integer.parseint(field.get(obj).tostring());
   return getresources().getdimensionpixelsize(x);
  }catch(exception e){
   e.printstacktrace();
  }
  return 0;
 }

}

mainactivity:

public class mainactivity extends baseactivity {
 private draglayout dl;
 private linearlayout linearlayout;
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  initdraglayout();
 }
 private void initdraglayout() {
  dl = (draglayout) findviewbyid(r.id.dl);
  linearlayout =(linearlayout) findviewbyid(r.id.aaa);
  dl.setdraglistener(new draglayout.draglistener() {
   //界面打开的时候
   @override
   public void onopen() {
   }
   //界面关闭的时候
   @override
   public void onclose() {
   }

   //界面滑动的时候
   @override
   public void ondrag(float percent) {
   }
  });
 }
}

onefragment:

public class onefragment extends fragment {
 private view mview;
 @override
 public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) {
  if(mview==null){
   mview=inflater.inflate(r.layout.one_frag_layout,container,false);
  }
  return mview;
 }
}

b布局文件:
one_frag_layout.xml
linearlayout布局

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center"
 android:id="@+id/aaa"

 >

 <textview
  android:text="界面"
  android:layout_gravity="center"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />
</linearlayout>

one_frag_layout1.xml:
relativelayout布局

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center"
 >

 <textview
  android:text="主界面"
  android:layout_gravity="center"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />
</relativelayout>

activity.main.xml:

<com.包名.myapplication.widget.draglayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/dl"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@android:color/transparent"
 >
 <!--下层 左边的布局 这个布局不能省去-->
 <include layout="@layout/one_frag_layout1"/>
 <!--上层 右边的主布局-->
 <com.包名.myapplication.widget.customrelativelayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#ffffff"
  >
  <linearlayout
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical"
   >
  <relativelayout
   android:id="@+id/rl_title"
   android:layout_width="match_parent"
   android:layout_height="49dp"
   android:gravity="bottom"
   android:background="#2aaced"
    >
   <include layout="@layout/one_frag_layout"/>
  </relativelayout>
  <!--中间内容后面放入fragment-->
  <framelayout
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <fragment
    android:id="@+id/main_info_fragment"
    class="com.mieasy.myapplication.onefragment"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
  </framelayout>
  </linearlayout>
 </com.包名.myapplication.widget.customrelativelayout>
</com.包名.myapplication.widget.draglayout>

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