软件编程
位置:首页>> 软件编程>> Android编程>> Android侧滑效果简单实现代码

Android侧滑效果简单实现代码

作者:三棵面包树  发布时间:2023-02-25 09:50:00 

标签:Android,侧滑

先看看效果:

Android侧滑效果简单实现代码

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

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


public class ViewDragHelper {
private static final String TAG = "ViewDragHelper";
public static final int INVALID_POINTER = -1
public static final int STATE_IDLE = 0;
public static final int STATE_DRAGGING = 1;
public static final int STATE_SETTLING = 2;
public static final int EDGE_LEFT = 1 << 0;
public static final int EDGE_RIGHT = 1 << 1
public static final int EDGE_TOP = 1 << 2;
public static final int EDGE_BOTTOM = 1 << 3
public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;
public static final int DIRECTION_HORIZONTAL = 1 << 0;
public static final int DIRECTION_VERTICAL = 1 << 1;
public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
private static final int EDGE_SIZE = 20; // dp
private static final int BASE_SETTLE_DURATION = 256; // ms
private static final int MAX_SETTLE_DURATION = 600; // ms
// Current drag state; idle, dragging or settling
private int mDragState;

// Distance to travel before a drag may begin
private int mTouchSlop;

// Last known position/pointer tracking
private int mActivePointerId = INVALID_POINTER;
private float[] mInitialMotionX;
private float[] mInitialMotionY;
private float[] mLastMotionX;
private float[] mLastMotionY;
private int[] mInitialEdgesTouched;
private int[] mEdgeDragsInProgress;
private int[] mEdgeDragsLocked;
private int mPointersDown;

private VelocityTracker mVelocityTracker;
private final float mMaxVelocity;
private float mMinVelocity;

private final int mEdgeSize;
private int mTrackingEdges;

private final ScrollerCompat mScroller;

private final Callback mCallback;

private View mCapturedView;
private boolean mReleaseInProgress;

private final ViewGroup mParentView;

private static final Interpolator sInterpolator = new Interpolator() {
 public float getInterpolation(float t) {
  t -= 1.0f;
  return t * t * t * t * t + 1.0f;
 }
};

private final Runnable mSetIdleRunnable = new Runnable() {
 public void run() {
  setDragState(STATE_IDLE);
 }
};

private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {
 if (forParent == null) {
  throw new IllegalArgumentException("Parent view may not be null");
 }
 if (cb == null) {
  throw new IllegalArgumentException("Callback may not be null");
 }

mParentView = forParent;
 mCallback = cb;

final ViewConfiguration vc = ViewConfiguration.get(context);
 final float density = context.getResources().getDisplayMetrics().density;
 mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);

mTouchSlop = vc.getScaledTouchSlop();
 mMaxVelocity = vc.getScaledMaximumFlingVelocity();
 mMinVelocity = vc.getScaledMinimumFlingVelocity();
 mScroller = ScrollerCompat.create(context, sInterpolator);
}

public static abstract class Callback {

public void onViewDragStateChanged(int state) {}

public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {}

public void onViewCaptured(View capturedChild, int activePointerId) {}

public void onViewReleased(View releasedChild, float xvel, float yvel) {}

public void onEdgeTouched(int edgeFlags, int pointerId) {}

public boolean onEdgeLock(int edgeFlags) {
  return false;
 }

public void onEdgeDragStarted(int edgeFlags, int pointerId) {}

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

public int getViewHorizontalDragRange(View child) {
  return 0;
 }

public int getViewVerticalDragRange(View child) {
  return 0;
 }

public abstract boolean tryCaptureView(View child, int pointerId);

public int clampViewPositionHorizontal(View child, int left, int dx) {
  return 0;
 }

public int clampViewPositionVertical(View child, int top, int dy) {
  return 0;
 }
}

public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
 return new ViewDragHelper(forParent.getContext(), forParent, cb);
}

public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
 final ViewDragHelper helper = create(forParent, cb);
 helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
 return helper;
}

public void setMinVelocity(float minVel) {
 mMinVelocity = minVel;
}

public float getMinVelocity() {
 return mMinVelocity;
}

public int getViewDragState() {
 return mDragState;
}

public void setEdgeTrackingEnabled(int edgeFlags) {
 mTrackingEdges = edgeFlags;
}

public int getEdgeSize() {
 return mEdgeSize;
}

public void captureChildView(View childView, int activePointerId) {
 if (childView.getParent() != mParentView) {
  throw new IllegalArgumentException("captureChildView: parameter must be a descendant " +
    "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
 }

mCapturedView = childView;
 mActivePointerId = activePointerId;
 mCallback.onViewCaptured(childView, activePointerId);
 setDragState(STATE_DRAGGING);
}

public View getCapturedView() {
 return mCapturedView;
}

public int getActivePointerId() {
 return mActivePointerId;
}

public int getTouchSlop() {
 return mTouchSlop;
}

public void cancel() {
 mActivePointerId = INVALID_POINTER;
 clearMotionHistory();

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

public void abort() {
 cancel();
 if (mDragState == STATE_SETTLING) {
  final int oldX = mScroller.getCurrX();
  final int oldY = mScroller.getCurrY();
  mScroller.abortAnimation();
  final int newX = mScroller.getCurrX();
  final int newY = mScroller.getCurrY();
  mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY);
 }
 setDragState(STATE_IDLE);
}

public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {
 mCapturedView = child;
 mActivePointerId = INVALID_POINTER;

boolean continueSliding = forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);
 if (!continueSliding && mDragState == STATE_IDLE && mCapturedView != null) {
  // If we're in an IDLE state to begin with and aren't moving anywhere, we
  // end up having a non-null capturedView with an IDLE dragState
  mCapturedView = null;
 }

return continueSliding;
}

public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
 if (!mReleaseInProgress) {
  throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to " +
    "Callback#onViewReleased");
 }

return forceSettleCapturedViewAt(finalLeft, finalTop,
   (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
   (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));
}

private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {
 final int startLeft = mCapturedView.getLeft();
 final int startTop = mCapturedView.getTop();
 final int dx = finalLeft - startLeft;
 final int dy = finalTop - startTop;

if (dx == 0 && dy == 0) {
  // Nothing to do. Send callbacks, be done.
  mScroller.abortAnimation();
  setDragState(STATE_IDLE);
  return false;
 }

final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);
 mScroller.startScroll(startLeft, startTop, dx, dy, duration);

setDragState(STATE_SETTLING);
 return true;
}

private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {
 xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);
 yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);
 final int absDx = Math.abs(dx);
 final int absDy = Math.abs(dy);
 final int absXVel = Math.abs(xvel);
 final int absYVel = Math.abs(yvel);
 final int addedVel = absXVel + absYVel;
 final int addedDistance = absDx + absDy;

final float xweight = xvel != 0 ? (float) absXVel / addedVel :
   (float) absDx / addedDistance;
 final float yweight = yvel != 0 ? (float) absYVel / addedVel :
   (float) absDy / addedDistance;

int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));
 int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));

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

private int computeAxisDuration(int delta, int velocity, int motionRange) {
 if (delta == 0) {
  return 0;
 }

final int width = mParentView.getWidth();
 final int halfWidth = width / 2;
 final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);
 final float distance = halfWidth + halfWidth *
   distanceInfluenceForSnapDuration(distanceRatio);

int duration;
 velocity = Math.abs(velocity);
 if (velocity > 0) {
  duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
 } else {
  final float range = (float) Math.abs(delta) / motionRange;
  duration = (int) ((range + 1) * BASE_SETTLE_DURATION);
 }
 return Math.min(duration, MAX_SETTLE_DURATION);
}

private static int clampMag(int value, int absMin, int absMax) {
 final int absValue = Math.abs(value);
 if (absValue < absMin) return 0;
 if (absValue > absMax) return value > 0 ? absMax : -absMax;
 return value;
}

private static float clampMag(float value, float absMin, float absMax) {
 final float absValue = Math.abs(value);
 if (absValue < absMin) return 0;
 if (absValue > absMax) return value > 0 ? absMax : -absMax;
 return value;
}

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

public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {
 if (!mReleaseInProgress) {
  throw new IllegalStateException("Cannot flingCapturedView outside of a call to " +
    "Callback#onViewReleased");
 }

mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),
   (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
   (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),
   minLeft, maxLeft, minTop, maxTop);

setDragState(STATE_SETTLING);
}

public boolean continueSettling(boolean deferCallbacks) {
 if (mDragState == STATE_SETTLING) {
  boolean keepGoing = mScroller.computeScrollOffset();
  final int x = mScroller.getCurrX();
  final int y = mScroller.getCurrY();
  final int dx = x - mCapturedView.getLeft();
  final int dy = y - mCapturedView.getTop();

if (dx != 0) {
   mCapturedView.offsetLeftAndRight(dx);
  }
  if (dy != 0) {
   mCapturedView.offsetTopAndBottom(dy);
  }

if (dx != 0 || dy != 0) {
   mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);
  }

if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {
   // Close enough. The interpolator/scroller might think we're still moving
   // but the user sure doesn't.
   mScroller.abortAnimation();
   keepGoing = false;
  }

if (!keepGoing) {
   if (deferCallbacks) {
    mParentView.post(mSetIdleRunnable);
   } else {
    setDragState(STATE_IDLE);
   }
  }
 }

return mDragState == STATE_SETTLING;
}

private void dispatchViewReleased(float xvel, float yvel) {
 mReleaseInProgress = true;
 mCallback.onViewReleased(mCapturedView, xvel, yvel);
 mReleaseInProgress = false;

if (mDragState == STATE_DRAGGING) {
  // onViewReleased didn't call a method that would have changed this. Go idle.
  setDragState(STATE_IDLE);
 }
}

private void clearMotionHistory() {
 if (mInitialMotionX == null) {
  return;
 }
 Arrays.fill(mInitialMotionX, 0);
 Arrays.fill(mInitialMotionY, 0);
 Arrays.fill(mLastMotionX, 0);
 Arrays.fill(mLastMotionY, 0);
 Arrays.fill(mInitialEdgesTouched, 0);
 Arrays.fill(mEdgeDragsInProgress, 0);
 Arrays.fill(mEdgeDragsLocked, 0);
 mPointersDown = 0;
}

private void clearMotionHistory(int pointerId) {
 if (mInitialMotionX == null) {
  return;
 }
 mInitialMotionX[pointerId] = 0;
 mInitialMotionY[pointerId] = 0;
 mLastMotionX[pointerId] = 0;
 mLastMotionY[pointerId] = 0;
 mInitialEdgesTouched[pointerId] = 0;
 mEdgeDragsInProgress[pointerId] = 0;
 mEdgeDragsLocked[pointerId] = 0;
 mPointersDown &= ~(1 << pointerId);
}

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

if (mInitialMotionX != null) {
   System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length);
   System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length);
   System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length);
   System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length);
   System.arraycopy(mInitialEdgesTouched, 0, iit, 0, mInitialEdgesTouched.length);
   System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length);
   System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length);
  }

mInitialMotionX = imx;
  mInitialMotionY = imy;
  mLastMotionX = lmx;
  mLastMotionY = lmy;
  mInitialEdgesTouched = iit;
  mEdgeDragsInProgress = edip;
  mEdgeDragsLocked = edl;
 }
}

private void saveInitialMotion(float x, float y, int pointerId) {
 ensureMotionHistorySizeForId(pointerId);
 mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x;
 mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y;
 mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y);
 mPointersDown |= 1 << pointerId;
}

private void saveLastMotion(MotionEvent ev) {
 final int pointerCount = MotionEventCompat.getPointerCount(ev);
 for (int i = 0; i < pointerCount; i++) {
  final int pointerId = MotionEventCompat.getPointerId(ev, i);
  final float x = MotionEventCompat.getX(ev, i);
  final float y = MotionEventCompat.getY(ev, i);
  mLastMotionX[pointerId] = x;
  mLastMotionY[pointerId] = y;
 }
}

public boolean isPointerDown(int pointerId) {
 return (mPointersDown & 1 << pointerId) != 0;
}

void setDragState(int state) {
 mParentView.removeCallbacks(mSetIdleRunnable);
 if (mDragState != state) {
  mDragState = state;
  mCallback.onViewDragStateChanged(state);
  if (mDragState == STATE_IDLE) {
   mCapturedView = null;
  }
 }
}

boolean tryCaptureViewForDrag(View toCapture, int pointerId) {
 if (toCapture == mCapturedView && mActivePointerId == pointerId) {
  // Already done!
  return true;
 }
 if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) {
  mActivePointerId = pointerId;
  captureChildView(toCapture, pointerId);
  return true;
 }
 return false;
}

protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) {
 if (v instanceof ViewGroup) {
  final ViewGroup group = (ViewGroup) v;
  final int scrollX = v.getScrollX();
  final int scrollY = v.getScrollY();
  final int count = group.getChildCount();
  // Count backwards - let topmost views consume scroll distance first.
  for (int i = count - 1; i >= 0; i--) {
   // TODO: Add versioned support here for transformed views.
   // This will not work for transformed views in Honeycomb+
   final View child = group.getChildAt(i);
   if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
     y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
     canScroll(child, true, dx, dy, x + scrollX - child.getLeft(),
       y + scrollY - child.getTop())) {
    return true;
   }
  }
 }

return checkV && (ViewCompat.canScrollHorizontally(v, -dx) ||
   ViewCompat.canScrollVertically(v, -dy));
}

public boolean shouldInterceptTouchEvent(MotionEvent ev) {
 final int action = MotionEventCompat.getActionMasked(ev);
 final int actionIndex = MotionEventCompat.getActionIndex(ev);

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

if (mVelocityTracker == null) {
  mVelocityTracker = VelocityTracker.obtain();
 }
 mVelocityTracker.addMovement(ev);

switch (action) {
  case MotionEvent.ACTION_DOWN: {
   final float x = ev.getX();
   final float y = ev.getY();
   final int pointerId = MotionEventCompat.getPointerId(ev, 0);
   saveInitialMotion(x, y, pointerId);

final View toCapture = findTopChildUnder((int) x, (int) y);

// Catch a settling view if possible.
   if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {
    tryCaptureViewForDrag(toCapture, pointerId);
   }

final int edgesTouched = mInitialEdgesTouched[pointerId];
   if ((edgesTouched & mTrackingEdges) != 0) {
    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
   }
   break;
  }

case MotionEventCompat.ACTION_POINTER_DOWN: {
   final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
   final float x = MotionEventCompat.getX(ev, actionIndex);
   final float y = MotionEventCompat.getY(ev, actionIndex);

saveInitialMotion(x, y, pointerId);

// A ViewDragHelper can only manipulate one view at a time.
   if (mDragState == STATE_IDLE) {
    final int edgesTouched = mInitialEdgesTouched[pointerId];
    if ((edgesTouched & mTrackingEdges) != 0) {
     mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
    }
   } else if (mDragState == STATE_SETTLING) {
    // Catch a settling view if possible.
    final View toCapture = findTopChildUnder((int) x, (int) y);
    if (toCapture == mCapturedView) {
     tryCaptureViewForDrag(toCapture, pointerId);
    }
   }
   break;
  }

case MotionEvent.ACTION_MOVE: {
   if (mInitialMotionX == null || mInitialMotionY == null) break;

// First to cross a touch slop over a draggable view wins. Also report edge drags.
   final int pointerCount = MotionEventCompat.getPointerCount(ev);
   for (int i = 0; i < pointerCount; i++) {
    final int pointerId = MotionEventCompat.getPointerId(ev, i);
    final float x = MotionEventCompat.getX(ev, i);
    final float y = MotionEventCompat.getY(ev, i);
    final float dx = x - mInitialMotionX[pointerId];
    final float dy = y - mInitialMotionY[pointerId];

final View toCapture = findTopChildUnder((int) x, (int) y);
    final boolean pastSlop = toCapture != null && checkTouchSlop(toCapture, dx, dy);
    if (pastSlop) {
     // check the callback's
     // getView[Horizontal|Vertical]DragRange methods to know
     // if you can move at all along an axis, then see if it
     // would clamp to the same value. If you can't move at
     // all in every dimension with a nonzero range, bail.
     final int oldLeft = toCapture.getLeft();
     final int targetLeft = oldLeft + (int) dx;
     final int newLeft = mCallback.clampViewPositionHorizontal(toCapture,
       targetLeft, (int) dx);
     final int oldTop = toCapture.getTop();
     final int targetTop = oldTop + (int) dy;
     final int newTop = mCallback.clampViewPositionVertical(toCapture, targetTop,
       (int) dy);
     final int horizontalDragRange = mCallback.getViewHorizontalDragRange(
       toCapture);
     final int verticalDragRange = mCallback.getViewVerticalDragRange(toCapture);
     if ((horizontalDragRange == 0 || horizontalDragRange > 0
       && newLeft == oldLeft) && (verticalDragRange == 0
       || verticalDragRange > 0 && newTop == oldTop)) {
      break;
     }
    }
    reportNewEdgeDrags(dx, dy, pointerId);
    if (mDragState == STATE_DRAGGING) {
     // Callback might have started an edge drag
     break;
    }

if (pastSlop && tryCaptureViewForDrag(toCapture, pointerId)) {
     break;
    }
   }
   saveLastMotion(ev);
   break;
  }

case MotionEventCompat.ACTION_POINTER_UP: {
   final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
   clearMotionHistory(pointerId);
   break;
  }

case MotionEvent.ACTION_UP:
  case MotionEvent.ACTION_CANCEL: {
   cancel();
   break;
  }
  default:
   break;
 }

return mDragState == STATE_DRAGGING;
}

public void processTouchEvent(MotionEvent ev) {
 final int action = MotionEventCompat.getActionMasked(ev);
 final int actionIndex = MotionEventCompat.getActionIndex(ev);

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

if (mVelocityTracker == null) {
  mVelocityTracker = VelocityTracker.obtain();
 }
 mVelocityTracker.addMovement(ev);

switch (action) {
  case MotionEvent.ACTION_DOWN: {
   final float x = ev.getX();
   final float y = ev.getY();
   final int pointerId = MotionEventCompat.getPointerId(ev, 0);
   final View toCapture = findTopChildUnder((int) x, (int) y);

saveInitialMotion(x, y, pointerId);

// Since the parent is already directly processing this touch event,
   // there is no reason to delay for a slop before dragging.
   // Start immediately if possible.
   tryCaptureViewForDrag(toCapture, pointerId);

final int edgesTouched = mInitialEdgesTouched[pointerId];
   if ((edgesTouched & mTrackingEdges) != 0) {
    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
   }
   break;
  }

case MotionEventCompat.ACTION_POINTER_DOWN: {
   final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
   final float x = MotionEventCompat.getX(ev, actionIndex);
   final float y = MotionEventCompat.getY(ev, actionIndex);

saveInitialMotion(x, y, pointerId);

// A ViewDragHelper can only manipulate one view at a time.
   if (mDragState == STATE_IDLE) {
    // If we're idle we can do anything! Treat it like a normal down event.

final View toCapture = findTopChildUnder((int) x, (int) y);
    tryCaptureViewForDrag(toCapture, pointerId);

final int edgesTouched = mInitialEdgesTouched[pointerId];
    if ((edgesTouched & mTrackingEdges) != 0) {
     mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
    }
   } else if (isCapturedViewUnder((int) x, (int) y)) {
    // We're still tracking a captured view. If the same view is under this
    // point, we'll swap to controlling it with this pointer instead.
    // (This will still work if we're "catching" a settling view.)

tryCaptureViewForDrag(mCapturedView, pointerId);
   }
   break;
  }

case MotionEvent.ACTION_MOVE: {
   if (mDragState == STATE_DRAGGING) {
    final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
    final float x = MotionEventCompat.getX(ev, index);
    final float y = MotionEventCompat.getY(ev, index);
    final int idx = (int) (x - mLastMotionX[mActivePointerId]);
    final int idy = (int) (y - mLastMotionY[mActivePointerId]);

dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);

saveLastMotion(ev);
   } else {
    // Check to see if any pointer is now over a draggable view.
    final int pointerCount = MotionEventCompat.getPointerCount(ev);
    for (int i = 0; i < pointerCount; i++) {
     final int pointerId = MotionEventCompat.getPointerId(ev, i);
     final float x = MotionEventCompat.getX(ev, i);
     final float y = MotionEventCompat.getY(ev, i);
     final float dx = x - mInitialMotionX[pointerId];
     final float dy = y - mInitialMotionY[pointerId];

reportNewEdgeDrags(dx, dy, pointerId);
     if (mDragState == STATE_DRAGGING) {
      // Callback might have started an edge drag.
      break;
     }

final View toCapture = findTopChildUnder((int) x, (int) y);
     if (checkTouchSlop(toCapture, dx, dy) &&
       tryCaptureViewForDrag(toCapture, pointerId)) {
      break;
     }
    }
    saveLastMotion(ev);
   }
   break;
  }

case MotionEventCompat.ACTION_POINTER_UP: {
   final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
   if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
    // Try to find another pointer that's still holding on to the captured view.
    int newActivePointer = INVALID_POINTER;
    final int pointerCount = MotionEventCompat.getPointerCount(ev);
    for (int i = 0; i < pointerCount; i++) {
     final int id = MotionEventCompat.getPointerId(ev, i);
     if (id == mActivePointerId) {
      // This one's going away, skip.
      continue;
     }

final float x = MotionEventCompat.getX(ev, i);
     final float y = MotionEventCompat.getY(ev, i);
     if (findTopChildUnder((int) x, (int) y) == mCapturedView &&
       tryCaptureViewForDrag(mCapturedView, id)) {
      newActivePointer = mActivePointerId;
      break;
     }
    }

if (newActivePointer == INVALID_POINTER) {
     // We didn't find another pointer still touching the view, release it.
     releaseViewForPointerUp();
    }
   }
   clearMotionHistory(pointerId);
   break;
  }

case MotionEvent.ACTION_UP: {
   if (mDragState == STATE_DRAGGING) {
    releaseViewForPointerUp();
   }
   cancel();
   break;
  }

case MotionEvent.ACTION_CANCEL: {
   if (mDragState == STATE_DRAGGING) {
    dispatchViewReleased(0, 0);
   }
   cancel();
   break;
  }
  default:
   break;

}
}

private void reportNewEdgeDrags(float dx, float dy, int pointerId) {
 int dragsStarted = 0;
 if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) {
  dragsStarted |= EDGE_LEFT;
 }
 if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) {
  dragsStarted |= EDGE_TOP;
 }
 if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) {
  dragsStarted |= EDGE_RIGHT;
 }
 if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) {
  dragsStarted |= EDGE_BOTTOM;
 }

if (dragsStarted != 0) {
  mEdgeDragsInProgress[pointerId] |= dragsStarted;
  mCallback.onEdgeDragStarted(dragsStarted, pointerId);
 }
}

private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) {
 final float absDelta = Math.abs(delta);
 final float absODelta = Math.abs(odelta);

if ((mInitialEdgesTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0 ||
   (mEdgeDragsLocked[pointerId] & edge) == edge ||
   (mEdgeDragsInProgress[pointerId] & edge) == edge ||
   (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) {
  return false;
 }
 if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) {
  mEdgeDragsLocked[pointerId] |= edge;
  return false;
 }
 return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop;
}

private boolean checkTouchSlop(View child, float dx, float dy) {
 if (child == null) {
  return false;
 }
 final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0;
 final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0;

if (checkHorizontal && checkVertical) {
  return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
 } else if (checkHorizontal) {
  return Math.abs(dx) > mTouchSlop;
 } else if (checkVertical) {
  return Math.abs(dy) > mTouchSlop;
 }
 return false;
}

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

public boolean checkTouchSlop(int directions, int pointerId) {
 if (!isPointerDown(pointerId)) {
  return false;
 }

final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL;
 final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL;

final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId];
 final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId];

if (checkHorizontal && checkVertical) {
  return dx * dx + dy * dy > mTouchSlop * mTouchSlop;
 } else if (checkHorizontal) {
  return Math.abs(dx) > mTouchSlop;
 } else if (checkVertical) {
  return Math.abs(dy) > mTouchSlop;
 }
 return false;
}

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

public boolean isEdgeTouched(int edges, int pointerId) {
 return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0;
}

private void releaseViewForPointerUp() {
 mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
 final float xvel = clampMag(
   VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
   mMinVelocity, mMaxVelocity);
 final float yvel = clampMag(
   VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),
   mMinVelocity, mMaxVelocity);
 dispatchViewReleased(xvel, yvel);
}

private void dragTo(int left, int top, int dx, int dy) {
 int clampedX = left;
 int clampedY = top;
 final int oldLeft = mCapturedView.getLeft();
 final int oldTop = mCapturedView.getTop();
 if (dx != 0) {
  clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);
  mCapturedView.offsetLeftAndRight(clampedX - oldLeft);
 }
 if (dy != 0) {
  clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);
  mCapturedView.offsetTopAndBottom(clampedY - oldTop);
 }

if (dx != 0 || dy != 0) {
  final int clampedDx = clampedX - oldLeft;
  final int clampedDy = clampedY - oldTop;
  mCallback.onViewPositionChanged(mCapturedView, clampedX, clampedY,
    clampedDx, clampedDy);
 }
}

public boolean isCapturedViewUnder(int x, int y) {
 return isViewUnder(mCapturedView, x, y);
}

public boolean isViewUnder(View view, int x, int y) {
 if (view == null) {
  return false;
 }
 return x >= view.getLeft() &&
   x < view.getRight() &&
   y >= view.getTop() &&
   y < view.getBottom();
}

public View findTopChildUnder(int x, int y) {
 final int childCount = mParentView.getChildCount();
 for (int i = childCount - 1; i >= 0; i--) {
  final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));
  if (x >= child.getLeft() && x < child.getRight() &&
    y >= child.getTop() && y < child.getBottom()) {
   return child;
  }
 }
 return null;
}

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

if (x < mParentView.getLeft() + mEdgeSize) result |= EDGE_LEFT;
 if (y < mParentView.getTop() + mEdgeSize) result |= EDGE_TOP;
 if (x > mParentView.getRight() - mEdgeSize) result |= EDGE_RIGHT;
 if (y > mParentView.getBottom() - mEdgeSize) result |= EDGE_BOTTOM;

return result;
}
}

DragLayout布局继承FrameLayout:


public class DragLayout extends FrameLayout {

private static final boolean IS_SHOW_SHADOW = true;
//手势处理类
private GestureDetectorCompat gestureDetector;
//视图拖拽移动帮助类
private ViewDragHelper dragHelper;
//滑动 *
private DragListener dragListener;
//水平拖拽的距离
private int range;
//宽度
private int width;
//高度
private int height;
//main视图距离在ViewGroup距离左边的距离
private int mainLeft;
private Context context;
private ImageView ivShadow;
//左侧布局
private RelativeLayout vgLeft;
//右侧(主界面布局)
private CustomRelativeLayout vgMain;
//页面状态 默认为关闭
private Status status = Status.CLOSE;

private final ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

@Override
 public int clampViewPositionHorizontal(View child, int left, int dx) {
  if (mainLeft + dx < 0) {
   return 0;
  } else if (mainLeft + dx > range) {
   return range;
  } else {
   return left;
  }
 }

@Override
 public boolean tryCaptureView(View child, int pointerId) {
  return true;
 }

@Override
 public int getViewHorizontalDragRange(View child) {
  return width;
 }

@Override
 public void onViewReleased(View releasedChild, float xvel, float yvel) {
  super.onViewReleased(releasedChild, xvel, yvel);
  if (xvel > 0) {
   open();
  } else if (xvel < 0) {
   close();
  } else if (releasedChild == vgMain && mainLeft > range * 0.3) {
   open();
  } else if (releasedChild == vgLeft && mainLeft > range * 0.7) {
   open();
  } else {
   close();
  }
 }

@Override
 public void onViewPositionChanged(View changedView, int left, int top,
          int dx, int dy) {
  if (changedView == vgMain) {
   mainLeft = left;
  } else {
   mainLeft = mainLeft + left;
  }
  if (mainLeft < 0) {
   mainLeft = 0;
  } else if (mainLeft > range) {
   mainLeft = range;
  }

if (IS_SHOW_SHADOW) {
   ivShadow.layout(mainLeft, 0, mainLeft + width, height);
  }
  if (changedView == vgLeft) {
   vgLeft.layout(0, 0, width, height);
   vgMain.layout(mainLeft, 0, mainLeft + width, height);
  }

dispatchDragEvent(mainLeft);
 }
};

public DragLayout(Context context) {
 this(context, null);
}

public DragLayout(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 this.context = context;
}

public DragLayout(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 gestureDetector = new GestureDetectorCompat(context, new YScrollDetector());
 dragHelper = ViewDragHelper.create(this, dragHelperCallback);
}

class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
 @Override
 public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) {
  return Math.abs(dy) <= Math.abs(dx);
 }
}

/**
 * 滑动相关回调接口
 */
public interface DragListener {
 //界面打开
 public void onOpen();
 //界面关闭
 public void onClose();
 //界面滑动过程中
 public void onDrag(float percent);
}
public void setDragListener(DragListener dragListener) {
 this.dragListener = dragListener;
}

/**
 * 布局加载完成回调
 * 做一些初始化的操作
 */
@Override
protected void onFinishInflate() {
 super.onFinishInflate();
 if (IS_SHOW_SHADOW) {
  ivShadow = new ImageView(context);
  ivShadow.setImageResource(R.mipmap.shadow);
  LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
  addView(ivShadow, 1, lp);
 }
 //左侧界面
 vgLeft = (RelativeLayout) getChildAt(0);
 //右侧(主)界面
 vgMain = (CustomRelativeLayout) getChildAt(IS_SHOW_SHADOW ? 2 : 1);
 vgMain.setDragLayout(this);
 vgLeft.setClickable(true);
 vgMain.setClickable(true);
}

public ViewGroup getVgMain() {
 return vgMain;
}

public ViewGroup getVgLeft() {
 return vgLeft;
}

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

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
 vgLeft.layout(0, 0, width, height);
 vgMain.layout(mainLeft, 0, mainLeft + width, height);
}

/**
 * 拦截触摸事件
 * @param ev
 * @return
 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
 return dragHelper.shouldInterceptTouchEvent(ev) && gestureDetector.onTouchEvent(ev);
}

/**
 * 将拦截的到事件给ViewDragHelper进行处理
 * @param e
 * @return
 */
@Override
public boolean onTouchEvent(MotionEvent e) {
 try {
  dragHelper.processTouchEvent(e);
 } catch (Exception ex) {
  ex.printStackTrace();
 }
 return false;
}

/**
 * 进行处理拖拽事件
 * @param mainLeft
 */
private void dispatchDragEvent(int mainLeft) {
 if (dragListener == null) {
  return;
 }
 float percent = mainLeft / (float) range;
 //滑动动画效果
 animateView(percent);
 //进行回调滑动的百分比
 dragListener.onDrag(percent);
 Status lastStatus = status;
 if (lastStatus != getStatus() && status == Status.CLOSE) {
  dragListener.onClose();
 } else if (lastStatus != getStatus() && status == Status.OPEN) {
  dragListener.onOpen();
 }
}

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

ViewHelper.setTranslationX(vgLeft, -vgLeft.getWidth() / 2.5f + vgLeft.getWidth() / 2.5f * percent);
 if (IS_SHOW_SHADOW) {
  //阴影效果视图大小进行缩放
  ViewHelper.setScaleX(ivShadow, f1 * 1.2f * (1 - percent * 0.10f));
  ViewHelper.setScaleY(ivShadow, f1 * 1.85f * (1 - percent * 0.10f));
 }
}
/**
 * 有加速度,当我们停止滑动的时候,该不会立即停止动画效果
 */
@Override
public void computeScroll() {
 if (dragHelper.continueSettling(true)) {
  ViewCompat.postInvalidateOnAnimation(this);
 }
}

/**
 * 页面状态(滑动,打开,关闭)
 */
public enum Status {
 DRAG, OPEN, CLOSE
}

/**
 * 页面状态设置
 * @return
 */
public Status getStatus() {
 if (mainLeft == 0) {
  status = Status.CLOSE;
 } else if (mainLeft == range) {
  status = Status.OPEN;
 } else {
  status = Status.DRAG;
 }
 return status;
}

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

public void open(boolean animate) {
 if (animate) {
  //继续滑动
  if (dragHelper.smoothSlideViewTo(vgMain, range, 0)) {
   ViewCompat.postInvalidateOnAnimation(this);
  }
 } else {
  vgMain.layout(range, 0, range * 2, height);
  dispatchDragEvent(range);
 }
}

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

public void close(boolean animate) {
 if (animate) {
  //继续滑动
  if (dragHelper.smoothSlideViewTo(vgMain, 0, 0)) {
   ViewCompat.postInvalidateOnAnimation(this);
  }
 } else {
  vgMain.layout(0, 0, width, height);
  dispatchDragEvent(0);
 }
}
}

CustomRelativeLayout:


public class CustomRelativeLayout extends RelativeLayout {
private DragLayout dl;
public CustomRelativeLayout(Context context) {
 super(context);
}

public CustomRelativeLayout(Context context, AttributeSet attrs) {
 super(context, attrs);
}

public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
}

public void setDragLayout(DragLayout dl) {
 this.dl = dl;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
 if (dl.getStatus() != DragLayout.Status.CLOSE) {
  return true;
 }
 return super.onInterceptTouchEvent(event);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
 if (dl.getStatus() != DragLayout.Status.CLOSE) {
  if (event.getAction() == MotionEvent.ACTION_UP) {
   dl.close();
  }
  return true;
 }
 return super.onTouchEvent(event);
}

}

c沉浸式状态栏:BaseActivity:


public class BaseActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 this.requestWindowFeature(Window.FEATURE_NO_TITLE);
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  //透明状态栏
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  //透明导航栏
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
 }
}
/**
 * 设置沉浸式状态栏
 */
protected void setStatusBar() {
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  final ViewGroup linear_bar = (ViewGroup) findViewById(R.id.rl_title);
  final int statusHeight = getStatusBarHeight();
  linear_bar.post(new Runnable() {
   @Override
   public void run() {
    int titleHeight = linear_bar.getHeight();
    android.widget.LinearLayout.LayoutParams params = (android.widget.LinearLayout.LayoutParams) linear_bar.getLayoutParams();
    params.height = statusHeight + titleHeight;
    linear_bar.setLayoutParams(params);
   }
  });
 }
}
/**
 * 获取状态栏的高度
 * @return
 */
protected int getStatusBarHeight(){
 try
 {
  Class<?> c=Class.forName("com.android.internal.R$dimen");
  Object obj=c.newInstance();
  Field field=c.getField("status_bar_height");
  int x=Integer.parseInt(field.get(obj).toString());
  return getResources().getDimensionPixelSize(x);
 }catch(Exception e){
  e.printStackTrace();
 }
 return 0;
}

}

MainActivity:


public class MainActivity extends BaseActivity {
private DragLayout dl;
private LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 initDragLayout();
}
private void initDragLayout() {
 dl = (DragLayout) findViewById(R.id.dl);
 linearLayout =(LinearLayout) findViewById(R.id.aaa);
 dl.setDragListener(new DragLayout.DragListener() {
  //界面打开的时候
  @Override
  public void onOpen() {
  }
  //界面关闭的时候
  @Override
  public void onClose() {
  }

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

OneFragment:


public class OneFragment extends Fragment {
private View mView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 if(mView==null){
  mView=inflater.inflate(R.layout.one_frag_layout,container,false);
 }
 return mView;
}
}

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


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

>

<TextView
 android:text="界面"
 android:layout_gravity="center"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" />
</LinearLayout>

one_frag_layout1.xml:
RelativeLayout布局


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

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

activity.main.xml:


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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com