public ObjectAnimator getDisappearAnimator() {
    if (!mIsInitialized || !mDrawValuesReady) {
      Log.e(TAG, "RadialSelectorView was not ready for animation.");
      return null;
    }

    Keyframe kf0, kf1, kf2;
    float midwayPoint = 0.2f;
    int duration = 500;

    kf0 = Keyframe.ofFloat(0f, 1);
    kf1 = Keyframe.ofFloat(midwayPoint, mTransitionMidRadiusMultiplier);
    kf2 = Keyframe.ofFloat(1f, mTransitionEndRadiusMultiplier);
    PropertyValuesHolder radiusDisappear =
        PropertyValuesHolder.ofKeyframe("animationRadiusMultiplier", kf0, kf1, kf2);

    kf0 = Keyframe.ofFloat(0f, 1f);
    kf1 = Keyframe.ofFloat(1f, 0f);
    PropertyValuesHolder fadeOut = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1);

    ObjectAnimator disappearAnimator =
        ObjectAnimator.ofPropertyValuesHolder(this, radiusDisappear, fadeOut).setDuration(duration);
    disappearAnimator.addUpdateListener(mInvalidateUpdateListener);

    return disappearAnimator;
  }
  public static ObjectAnimator tada(View view, float shakeFactor) {

    PropertyValuesHolder pvhScaleX =
        PropertyValuesHolder.ofKeyframe(
            View.SCALE_X,
            Keyframe.ofFloat(0f, 1f),
            Keyframe.ofFloat(.1f, .9f),
            Keyframe.ofFloat(.2f, .9f),
            Keyframe.ofFloat(.3f, 1.1f),
            Keyframe.ofFloat(.4f, 1.1f),
            Keyframe.ofFloat(.5f, 1.1f),
            Keyframe.ofFloat(.6f, 1.1f),
            Keyframe.ofFloat(.7f, 1.1f),
            Keyframe.ofFloat(.8f, 1.1f),
            Keyframe.ofFloat(.9f, 1.1f),
            Keyframe.ofFloat(1f, 1f));

    PropertyValuesHolder pvhScaleY =
        PropertyValuesHolder.ofKeyframe(
            View.SCALE_Y,
            Keyframe.ofFloat(0f, 1f),
            Keyframe.ofFloat(.1f, .9f),
            Keyframe.ofFloat(.2f, .9f),
            Keyframe.ofFloat(.3f, 1.1f),
            Keyframe.ofFloat(.4f, 1.1f),
            Keyframe.ofFloat(.5f, 1.1f),
            Keyframe.ofFloat(.6f, 1.1f),
            Keyframe.ofFloat(.7f, 1.1f),
            Keyframe.ofFloat(.8f, 1.1f),
            Keyframe.ofFloat(.9f, 1.1f),
            Keyframe.ofFloat(1f, 1f));

    PropertyValuesHolder pvhRotate =
        PropertyValuesHolder.ofKeyframe(
            View.ROTATION,
            Keyframe.ofFloat(0f, 0f),
            Keyframe.ofFloat(.1f, -3f * shakeFactor),
            Keyframe.ofFloat(.2f, -3f * shakeFactor),
            Keyframe.ofFloat(.3f, 3f * shakeFactor),
            Keyframe.ofFloat(.4f, -3f * shakeFactor),
            Keyframe.ofFloat(.5f, 3f * shakeFactor),
            Keyframe.ofFloat(.6f, -3f * shakeFactor),
            Keyframe.ofFloat(.7f, 3f * shakeFactor),
            Keyframe.ofFloat(.8f, -3f * shakeFactor),
            Keyframe.ofFloat(.9f, 3f * shakeFactor),
            Keyframe.ofFloat(1f, 0));

    return ObjectAnimator.ofPropertyValuesHolder(view, pvhScaleX, pvhScaleY, pvhRotate)
        .setDuration(1000);
  }
  /** Render the animations for appearing and disappearing. */
  private void renderAnimations() {
    Keyframe kf0, kf1, kf2, kf3;
    float midwayPoint = 0.2f;
    int duration = 500;

    // Set up animator for disappearing.
    kf0 = Keyframe.ofFloat(0f, 1);
    kf1 = Keyframe.ofFloat(midwayPoint, mTransitionMidRadiusMultiplier);
    kf2 = Keyframe.ofFloat(1f, mTransitionEndRadiusMultiplier);
    PropertyValuesHolder radiusDisappear =
        PropertyValuesHolder.ofKeyframe("animationRadiusMultiplier", kf0, kf1, kf2);

    kf0 = Keyframe.ofFloat(0f, 1f);
    kf1 = Keyframe.ofFloat(1f, 0f);
    PropertyValuesHolder fadeOut = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1);

    mDisappearAnimator =
        ObjectAnimator.ofPropertyValuesHolder(this, radiusDisappear, fadeOut).setDuration(duration);
    mDisappearAnimator.addUpdateListener(mInvalidateUpdateListener);

    // Set up animator for reappearing.
    float delayMultiplier = 0.25f;
    float transitionDurationMultiplier = 1f;
    float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier;
    int totalDuration = (int) (duration * totalDurationMultiplier);
    float delayPoint = (delayMultiplier * duration) / totalDuration;
    midwayPoint = 1 - (midwayPoint * (1 - delayPoint));

    kf0 = Keyframe.ofFloat(0f, mTransitionEndRadiusMultiplier);
    kf1 = Keyframe.ofFloat(delayPoint, mTransitionEndRadiusMultiplier);
    kf2 = Keyframe.ofFloat(midwayPoint, mTransitionMidRadiusMultiplier);
    kf3 = Keyframe.ofFloat(1f, 1);
    PropertyValuesHolder radiusReappear =
        PropertyValuesHolder.ofKeyframe("animationRadiusMultiplier", kf0, kf1, kf2, kf3);

    kf0 = Keyframe.ofFloat(0f, 0f);
    kf1 = Keyframe.ofFloat(delayPoint, 0f);
    kf2 = Keyframe.ofFloat(1f, 1f);
    PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2);

    mReappearAnimator =
        ObjectAnimator.ofPropertyValuesHolder(this, radiusReappear, fadeIn)
            .setDuration(totalDuration);
    mReappearAnimator.addUpdateListener(mInvalidateUpdateListener);
  }
  public ObjectAnimator getReappearAnimator() {
    if (!mIsInitialized || !mDrawValuesReady) {
      Log.e(TAG, "RadialSelectorView was not ready for animation.");
      return null;
    }

    Keyframe kf0, kf1, kf2, kf3;
    float midwayPoint = 0.2f;
    int duration = 500;

    // The time points are half of what they would normally be, because this animation is
    // staggered against the disappear so they happen seamlessly. The reappear starts
    // halfway into the disappear.
    float delayMultiplier = 0.25f;
    float transitionDurationMultiplier = 1f;
    float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier;
    int totalDuration = (int) (duration * totalDurationMultiplier);
    float delayPoint = (delayMultiplier * duration) / totalDuration;
    midwayPoint = 1 - (midwayPoint * (1 - delayPoint));

    kf0 = Keyframe.ofFloat(0f, mTransitionEndRadiusMultiplier);
    kf1 = Keyframe.ofFloat(delayPoint, mTransitionEndRadiusMultiplier);
    kf2 = Keyframe.ofFloat(midwayPoint, mTransitionMidRadiusMultiplier);
    kf3 = Keyframe.ofFloat(1f, 1);
    PropertyValuesHolder radiusReappear =
        PropertyValuesHolder.ofKeyframe("animationRadiusMultiplier", kf0, kf1, kf2, kf3);

    kf0 = Keyframe.ofFloat(0f, 0f);
    kf1 = Keyframe.ofFloat(delayPoint, 0f);
    kf2 = Keyframe.ofFloat(1f, 1f);
    PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2);

    ObjectAnimator reappearAnimator =
        ObjectAnimator.ofPropertyValuesHolder(this, radiusReappear, fadeIn)
            .setDuration(totalDuration);
    reappearAnimator.addUpdateListener(mInvalidateUpdateListener);
    return reappearAnimator;
  }
  public static ObjectAnimator nope(View view) {

    int delta = view.getResources().getDimensionPixelOffset(R.dimen.spacing_medium);

    PropertyValuesHolder pvhTranslateX =
        PropertyValuesHolder.ofKeyframe(
            View.TRANSLATION_X,
            Keyframe.ofFloat(0f, 0),
            Keyframe.ofFloat(.10f, -delta),
            Keyframe.ofFloat(.26f, delta),
            Keyframe.ofFloat(.42f, -delta),
            Keyframe.ofFloat(.58f, delta),
            Keyframe.ofFloat(.74f, -delta),
            Keyframe.ofFloat(.90f, delta),
            Keyframe.ofFloat(1f, 0f));

    return ObjectAnimator.ofPropertyValuesHolder(view, pvhTranslateX).setDuration(500);
  }
  private void createCustomAnimations(LayoutTransition transition) {
    // Changing while Adding
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
    PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
    PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);
    PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);
    PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
    PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
    customChangingAppearingAnim =
        ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX, pvhScaleY)
            .setDuration(transition.getDuration(LayoutTransition.CHANGE_APPEARING));
    customChangingAppearingAnim.addListener(
        new AnimatorListenerAdapter() {
          public void onAnimationEnd(Animator anim) {
            View view = (View) ((ObjectAnimator) anim).getTarget();
            view.setScaleX(1f);
            view.setScaleY(1f);
          }
        });

    // Changing while Removing
    Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
    Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f);
    Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
    PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
    customChangingDisappearingAnim =
        ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhRotation)
            .setDuration(transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
    customChangingDisappearingAnim.addListener(
        new AnimatorListenerAdapter() {
          public void onAnimationEnd(Animator anim) {
            View view = (View) ((ObjectAnimator) anim).getTarget();
            view.setRotation(0f);
          }
        });

    // Adding
    customAppearingAnim =
        ObjectAnimator.ofFloat(null, "rotationY", 90f, 0f)
            .setDuration(transition.getDuration(LayoutTransition.APPEARING));
    customAppearingAnim.addListener(
        new AnimatorListenerAdapter() {
          public void onAnimationEnd(Animator anim) {
            View view = (View) ((ObjectAnimator) anim).getTarget();
            view.setRotationY(0f);
          }
        });

    // Removing
    customDisappearingAnim =
        ObjectAnimator.ofFloat(null, "rotationX", 0f, 90f)
            .setDuration(transition.getDuration(LayoutTransition.DISAPPEARING));
    customDisappearingAnim.addListener(
        new AnimatorListenerAdapter() {
          public void onAnimationEnd(Animator anim) {
            View view = (View) ((ObjectAnimator) anim).getTarget();
            view.setRotationX(0f);
          }
        });
  }