/** Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}. */
  public static float mapCoordInSelfToDescendent(View descendant, View root, int[] coord) {
    ArrayList<View> ancestorChain = new ArrayList<View>();

    float[] pt = {coord[0], coord[1]};

    View v = descendant;
    while (v != root) {
      ancestorChain.add(v);
      v = (View) v.getParent();
    }
    ancestorChain.add(root);

    float scale = 1.0f;
    Matrix inverse = new Matrix();
    int count = ancestorChain.size();
    for (int i = count - 1; i >= 0; i--) {
      View ancestor = ancestorChain.get(i);
      View next = i > 0 ? ancestorChain.get(i - 1) : null;

      pt[0] += ancestor.getScrollX();
      pt[1] += ancestor.getScrollY();

      if (next != null) {
        pt[0] -= next.getLeft();
        pt[1] -= next.getTop();
        next.getMatrix().invert(inverse);
        inverse.mapPoints(pt);
        scale *= next.getScaleX();
      }
    }

    coord[0] = (int) Math.round(pt[0]);
    coord[1] = (int) Math.round(pt[1]);
    return scale;
  }
  /**
   * Given a coordinate relative to the descendant, find the coordinate in a parent view's
   * coordinates.
   *
   * @param descendant The descendant to which the passed coordinate is relative.
   * @param root The root view to make the coordinates relative to.
   * @param coord The coordinate that we want mapped.
   * @param includeRootScroll Whether or not to account for the scroll of the descendant: sometimes
   *     this is relevant as in a child's coordinates within the descendant.
   * @return The factor by which this descendant is scaled relative to this DragLayer. Caution this
   *     scale factor is assumed to be equal in X and Y, and so if at any point this assumption
   *     fails, we will need to return a pair of scale factors.
   */
  public static float getDescendantCoordRelativeToParent(
      View descendant, View root, int[] coord, boolean includeRootScroll) {
    ArrayList<View> ancestorChain = new ArrayList<View>();

    float[] pt = {coord[0], coord[1]};

    View v = descendant;
    while (v != root && v != null) {
      ancestorChain.add(v);
      v = (View) v.getParent();
    }
    ancestorChain.add(root);

    float scale = 1.0f;
    int count = ancestorChain.size();
    for (int i = 0; i < count; i++) {
      View v0 = ancestorChain.get(i);
      // For TextViews, scroll has a meaning which relates to the text position
      // which is very strange... ignore the scroll.
      if (v0 != descendant || includeRootScroll) {
        pt[0] -= v0.getScrollX();
        pt[1] -= v0.getScrollY();
      }

      v0.getMatrix().mapPoints(pt);
      pt[0] += v0.getLeft();
      pt[1] += v0.getTop();
      scale *= v0.getScaleX();
    }

    coord[0] = (int) Math.round(pt[0]);
    coord[1] = (int) Math.round(pt[1]);
    return scale;
  }
Example #3
0
 // invalidate a rectangle relative to the view's coordinate system all the way up the view
 // hierarchy
 @SuppressLint("NewApi")
 public static void invalidateGlobalRegion(View view, RectF childBounds) {
   // childBounds.offset(view.getTranslationX(), view.getTranslationY());
   if (DEBUG_INVALIDATE) if (DebugLog.DEBUG) DebugLog.d(TAG, "-------------");
   while (view.getParent() != null && view.getParent() instanceof View) {
     view = (View) view.getParent();
     view.getMatrix().mapRect(childBounds);
     view.invalidate(
         (int) Math.floor(childBounds.left),
         (int) Math.floor(childBounds.top),
         (int) Math.ceil(childBounds.right),
         (int) Math.ceil(childBounds.bottom));
     if (DebugLog.DEBUG) {
       DebugLog.v(
           TAG,
           "INVALIDATE("
               + (int) Math.floor(childBounds.left)
               + ","
               + (int) Math.floor(childBounds.top)
               + ","
               + (int) Math.ceil(childBounds.right)
               + ","
               + (int) Math.ceil(childBounds.bottom));
     }
   }
 }
 private static void a(View paramView, RectF paramRectF)
 {
   while ((paramView.getParent() instanceof View))
   {
     paramView = (View)paramView.getParent();
     paramView.getMatrix().mapRect(paramRectF);
     paramView.invalidate((int)Math.floor(left), (int)Math.floor(top), (int)Math.ceil(right), (int)Math.ceil(bottom));
   }
 }
Example #5
0
 /**
  * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
  * coordinates.
  *
  * @param descendant The descendant to which the passed coordinate is relative.
  * @param coord The coordinate that we want mapped.
  * @return The factor by which this descendant is scaled relative to this DragLayer. Caution this
  *     scale factor is assumed to be equal in X and Y, and so if at any point this assumption
  *     fails, we will need to return a pair of scale factors.
  */
 public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
   float scale = 1.0f;
   float[] pt = {coord[0], coord[1]};
   descendant.getMatrix().mapPoints(pt);
   scale *= descendant.getScaleX();
   pt[0] += descendant.getLeft();
   pt[1] += descendant.getTop();
   ViewParent viewParent = descendant.getParent();
   while (viewParent instanceof View && viewParent != this) {
     final View view = (View) viewParent;
     view.getMatrix().mapPoints(pt);
     scale *= view.getScaleX();
     pt[0] += view.getLeft() - view.getScrollX();
     pt[1] += view.getTop() - view.getScrollY();
     viewParent = view.getParent();
   }
   coord[0] = (int) Math.round(pt[0]);
   coord[1] = (int) Math.round(pt[1]);
   return scale;
 }
  @Override
  public boolean onInterceptTouchEvent(MotionEvent event) {
    if (mTopCard == null) {
      return false;
    }
    if (mGestureDetector.onTouchEvent(event)) {
      return true;
    }
    final int pointerIndex;
    final float x, y;
    final float dx, dy;
    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
        mTopCard.getHitRect(childRect);

        CardModel cardModel = (CardModel) getAdapter().getItem(getChildCount() - 1);

        if (cardModel.getOnClickListener() != null) {
          cardModel.getOnClickListener().OnClickListener();
        }
        pointerIndex = event.getActionIndex();
        x = event.getX(pointerIndex);
        y = event.getY(pointerIndex);

        if (!childRect.contains((int) x, (int) y)) {
          return false;
        }

        mLastTouchX = x;
        mLastTouchY = y;
        mActivePointerId = event.getPointerId(pointerIndex);
        break;
      case MotionEvent.ACTION_MOVE:
        pointerIndex = event.findPointerIndex(mActivePointerId);
        x = event.getX(pointerIndex);
        y = event.getY(pointerIndex);
        if (Math.abs(x - mLastTouchX) > mTouchSlop || Math.abs(y - mLastTouchY) > mTouchSlop) {
          float[] points = new float[] {x - mTopCard.getLeft(), y - mTopCard.getTop()};
          mTopCard.getMatrix().invert(mMatrix);
          mMatrix.mapPoints(points);
          mTopCard.setPivotX(points[0]);
          mTopCard.setPivotY(points[1]);
          return true;
        }
    }

    return false;
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (mTopCard == null) {
      return false;
    }
    if (mGestureDetector.onTouchEvent(event)) {
      return true;
    }
    // Log.d("Touch Event", MotionEvent.actionToString(event.getActionMasked()) + " ");
    final int pointerIndex;
    final float x, y;
    final float dx, dy;
    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
        mTopCard.getHitRect(childRect);

        pointerIndex = event.getActionIndex();
        x = event.getX(pointerIndex);
        y = event.getY(pointerIndex);

        if (!childRect.contains((int) x, (int) y)) {
          return false;
        }
        mLastTouchX = x;
        mLastTouchY = y;
        mActivePointerId = event.getPointerId(pointerIndex);

        float[] points = new float[] {x - mTopCard.getLeft(), y - mTopCard.getTop()};
        mTopCard.getMatrix().invert(mMatrix);
        mMatrix.mapPoints(points);
        mTopCard.setPivotX(points[0]);
        mTopCard.setPivotY(points[1]);

        break;
      case MotionEvent.ACTION_MOVE:
        pointerIndex = event.findPointerIndex(mActivePointerId);
        x = event.getX(pointerIndex);
        y = event.getY(pointerIndex);

        dx = x - mLastTouchX;
        dy = y - mLastTouchY;

        if (Math.abs(dx) > mTouchSlop || Math.abs(dy) > mTouchSlop) {
          mDragging = true;
        }

        if (!mDragging) {
          return true;
        }

        mTopCard.setTranslationX(mTopCard.getTranslationX() + dx);
        mTopCard.setTranslationY(mTopCard.getTranslationY() + dy);

        mTopCard.setRotation(40 * mTopCard.getTranslationX() / (getWidth() / 2.f));

        mLastTouchX = x;
        mLastTouchY = y;
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        if (!mDragging) {
          return true;
        }
        mDragging = false;
        mActivePointerId = INVALID_POINTER_ID;
        ValueAnimator animator =
            ObjectAnimator.ofPropertyValuesHolder(
                    mTopCard,
                    PropertyValuesHolder.ofFloat("translationX", 0),
                    PropertyValuesHolder.ofFloat("translationY", 0),
                    PropertyValuesHolder.ofFloat(
                        "rotation",
                        (float)
                            Math.toDegrees(
                                mRandom.nextGaussian() * DISORDERED_MAX_ROTATION_RADIANS)),
                    PropertyValuesHolder.ofFloat("pivotX", mTopCard.getWidth() / 2.f),
                    PropertyValuesHolder.ofFloat("pivotY", mTopCard.getHeight() / 2.f))
                .setDuration(250);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
        break;
      case MotionEvent.ACTION_POINTER_UP:
        pointerIndex = event.getActionIndex();
        final int pointerId = event.getPointerId(pointerIndex);

        if (pointerId == mActivePointerId) {
          final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
          mLastTouchX = event.getX(newPointerIndex);
          mLastTouchY = event.getY(newPointerIndex);

          mActivePointerId = event.getPointerId(newPointerIndex);
        }
        break;
    }

    return true;
  }