Android侧滑效果简单实现代码
程序员文章站
2024-02-28 13:56:28
先看看效果:
首先,导入包:compile files('libs/nineoldandroids-2.4.0.jar')
r然后在main中创建一个wi...
先看看效果:
首先,导入包: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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。