@Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      Log.d("Fling", "Fling with " + velocityX + ", " + velocityY);
      final View topCard = mTopCard;
      float dx = e2.getX() - e1.getX();
      if (Math.abs(dx) > mTouchSlop
          && Math.abs(velocityX) > Math.abs(velocityY)
          && Math.abs(velocityX) > mFlingSlop * 3) {
        float targetX = topCard.getX();
        float targetY = topCard.getY();
        long duration = 0;

        boundsRect.set(
            0 - topCard.getWidth() - 100,
            0 - topCard.getHeight() - 100,
            getWidth() + 100,
            getHeight() + 100);

        while (boundsRect.contains((int) targetX, (int) targetY)) {
          targetX += velocityX / 10;
          targetY += velocityY / 10;
          duration += 100;
        }

        duration = Math.min(500, duration);

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

        if (mTopCard != null) mTopCard.setLayerType(LAYER_TYPE_HARDWARE, null);

        if (cardModel.getOnCardDismissedListener() != null) {
          if (targetX > 0) {
            cardModel.getOnCardDismissedListener().onLike();
          } else {
            cardModel.getOnCardDismissedListener().onDislike();
          }
        }

        topCard
            .animate()
            .setDuration(duration)
            .alpha(.75f)
            .setInterpolator(new LinearInterpolator())
            .x(targetX)
            .y(targetY)
            .rotation(Math.copySign(45, velocityX))
            .setListener(
                new AnimatorListenerAdapter() {
                  @Override
                  public void onAnimationEnd(Animator animation) {
                    removeViewInLayout(topCard);
                    ensureFull();
                  }

                  @Override
                  public void onAnimationCancel(Animator animation) {
                    onAnimationEnd(animation);
                  }
                });
        return true;
      } else return false;
    }
  @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;
  }