先看看效果:
首先,导入包: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 dx) { return 0; } public int clampVIEwpositionVertical(VIEw child,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); 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,(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,duration); setDragState(STATE_SETTliNG); return true; } private int computeSettleDuration(VIEw child,int dy,int yvel) { xvel = clampMag(xvel,(int) mMinVeLocity,(int) mMaxVeLocity); yvel = clampMag(yvel,(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,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(),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,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,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,imx,mInitialMotionX.length); System.arraycopy(mInitialMotionY,imy,mInitialMotionY.length); System.arraycopy(mLastMotionX,lmx,mLastMotionX.length); System.arraycopy(mLastMotionY,lmy,mLastMotionY.length); System.arraycopy(mInitialEdgestouched,iit,mInitialEdgestouched.length); System.arraycopy(mEdgeDragsInProgress,edip,mEdgeDragsInProgress.length); System.arraycopy(mEdgeDragsLocked,edl,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 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,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,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,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,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,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,0); final VIEw toCapture = findtopChildUnder((int) x,(int) y); saveInitialMotion(x,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); // 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,pointerID); if (mDragState == STATE_DRAGGING) { // Callback might have started an edge drag. break; } final VIEw toCapture = findtopChildUnder((int) x,(int) y); if (checktouchSlop(toCapture,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); 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,pointerID,EDGE_left)) { dragsstarted |= EDGE_left; } if (checkNewEdgeDrag(dy,EDGE_top)) { dragsstarted |= EDGE_top; } if (checkNewEdgeDrag(dx,EDGE_RIGHT)) { dragsstarted |= EDGE_RIGHT; } if (checkNewEdgeDrag(dy,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,mMinVeLocity,mMaxVeLocity); final float yvel = clampMag( VeLocityTrackerCompat.getYVeLocity(mVeLocityTracker,mMaxVeLocity); dispatchVIEwReleased(xvel,yvel); } private voID dragTo(int left,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,y); } public boolean isVIEwUnder(VIEw vIEw,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 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 yvel) { super.onVIEwReleased(releasedChild,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 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,mainleft + wIDth,height); } if (changedVIEw == vgleft) { vgleft.layout(0,wIDth,height); vgMain.layout(mainleft,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,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 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 right,int bottom) { vgleft.layout(0,height); vgMain.layout(mainleft,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,range * 2,height); dispatchDragEvent(range); } } public voID close() { close(true); } public voID close(boolean animate) { if (animate) { //继续滑动 if (dragHelper.smoothSlIDeVIEwTo(vgMain,0)) { VIEwCompat.postInvalIDateOnAnimation(this); } } else { vgMain.layout(0,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,int defStyleAttr) { super(context,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" androID:layout_wIDth="fill_parent" androID:layout_height="fill_parent"/> </FrameLayout> </linearLayout> </com.包名.myapplication.Widget.CustomrelativeLayout></com.包名.myapplication.Widget.DragLayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的Android侧滑效果简单实现代码全部内容,希望文章能够帮你解决Android侧滑效果简单实现代码所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)