/* * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.plaidapp.ui.transitions; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.transition.ChangeBounds; import android.transition.TransitionValues; import android.view.View; import android.view.ViewGroup; import io.plaidapp.ui.drawable.MorphDrawable; import io.plaidapp.util.AnimUtils; /** * An extension to {@link ChangeBounds} that also morphs the views background (color & corner * radius). */ public class MorphTransform extends ChangeBounds { private static final String EXTRA_SHARED_ELEMENT_START_COLOR = "EXTRA_SHARED_ELEMENT_START_COLOR"; private static final String EXTRA_SHARED_ELEMENT_START_CORNER_RADIUS = "EXTRA_SHARED_ELEMENT_START_CORNER_RADIUS"; private static final long DEFAULT_DURATION = 300L; private final int startColor; private final int endColor; private final int startCornerRadius; private final int endCornerRadius; public MorphTransform(@ColorInt int startColor, @ColorInt int endColor, int startCornerRadius, int endCornerRadius) { this.startColor = startColor; this.endColor = endColor; this.startCornerRadius = startCornerRadius; this.endCornerRadius = endCornerRadius; setDuration(DEFAULT_DURATION); setPathMotion(new GravityArcMotion()); } /** * Configure {@code intent} with the extras needed to initialize this transition. */ public static void addExtras(@NonNull Intent intent, @ColorInt int startColor, int startCornerRadius) { intent.putExtra(EXTRA_SHARED_ELEMENT_START_COLOR, startColor); intent.putExtra(EXTRA_SHARED_ELEMENT_START_CORNER_RADIUS, startCornerRadius); } /** * Configure {@link MorphTransform}s & set as {@code activity}'s shared element enter and return * transitions. */ public static void setup(@NonNull Activity activity, @Nullable View target, @ColorInt int endColor, int endCornerRadius) { final Intent intent = activity.getIntent(); if (intent == null || !intent.hasExtra(EXTRA_SHARED_ELEMENT_START_COLOR) || !intent.hasExtra(EXTRA_SHARED_ELEMENT_START_CORNER_RADIUS)) return; final int startColor = activity.getIntent(). getIntExtra(EXTRA_SHARED_ELEMENT_START_COLOR, Color.TRANSPARENT); final int startCornerRadius = intent.getIntExtra(EXTRA_SHARED_ELEMENT_START_CORNER_RADIUS, 0); final MorphTransform sharedEnter = new MorphTransform(startColor, endColor, startCornerRadius, endCornerRadius); // Reverse the start/end params for the return transition final MorphTransform sharedReturn = new MorphTransform(endColor, startColor, endCornerRadius, startCornerRadius); if (target != null) { sharedEnter.addTarget(target); sharedReturn.addTarget(target); } activity.getWindow().setSharedElementEnterTransition(sharedEnter); activity.getWindow().setSharedElementReturnTransition(sharedReturn); } @Override public Animator createAnimator(final ViewGroup sceneRoot, final TransitionValues startValues, final TransitionValues endValues) { final Animator changeBounds = super.createAnimator(sceneRoot, startValues, endValues); if (changeBounds == null) return null; TimeInterpolator interpolator = getInterpolator(); if (interpolator == null) { interpolator = AnimUtils.getFastOutSlowInInterpolator(sceneRoot.getContext()); } final MorphDrawable background = new MorphDrawable(startColor, startCornerRadius); endValues.view.setBackground(background); final Animator color = ObjectAnimator.ofArgb(background, MorphDrawable.COLOR, endColor); final Animator corners = ObjectAnimator.ofFloat(background, MorphDrawable.CORNER_RADIUS, endCornerRadius); // ease in the dialog's child views (fade in & staggered slide up) if (endValues.view instanceof ViewGroup) { final ViewGroup vg = (ViewGroup) endValues.view; final long duration = getDuration() / 2; float offset = vg.getHeight() / 3; for (int i = 0; i < vg.getChildCount(); i++) { View v = vg.getChildAt(i); v.setTranslationY(offset); v.setAlpha(0f); v.animate() .alpha(1f) .translationY(0f) .setDuration(duration) .setStartDelay(duration) .setInterpolator(interpolator); offset *= 1.8f; } } final AnimatorSet transition = new AnimatorSet(); transition.playTogether(changeBounds, corners, color); transition.setDuration(getDuration()); transition.setInterpolator(interpolator); return transition; } }