当前位置: 移动技术网 > 移动技术>移动开发>Android > Android侧滑效果简单实现代码

Android侧滑效果简单实现代码

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

先看看效果:

首先,导入包: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>

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

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

相关文章:

验证码:
移动技术网