Skip to content

Commit

Permalink
Updated add to Pocket anim to use proper RecyclerView plumbing.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickbutcher committed Nov 24, 2015
1 parent 83e6c74 commit 13b113a
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 85 deletions.
90 changes: 5 additions & 85 deletions app/src/main/java/io/plaidapp/ui/FeedAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.ActivityOptions;
Expand All @@ -35,7 +33,6 @@
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.transition.ArcMotion;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.util.Pair;
Expand Down Expand Up @@ -80,11 +77,12 @@
*/
public class FeedAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

public static final float DUPE_WEIGHT_BOOST = 0.4f;

private static final int TYPE_DESIGNER_NEWS_STORY = 0;
private static final int TYPE_DRIBBBLE_SHOT = 1;
private static final int TYPE_PRODUCT_HUNT_POST = 2;
private static final int TYPE_LOADING_MORE = -1;
public static final float DUPE_WEIGHT_BOOST = 0.4f;

// we need to hold on to an activity ref for the shared element transitions :/
private final Activity host;
Expand Down Expand Up @@ -189,89 +187,11 @@ public void onClick(View commentsView) {
holder.pocket.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
final ImageButton pocketButton = (ImageButton) view;
// actually add to pocket
PocketUtils.addToPocket(host,
((Story) getItem(holder.getAdapterPosition())).url);

// setup for anim
holder.itemView.setHasTransientState(true);
((ViewGroup) pocketButton.getParent().getParent()).setClipChildren(false);
final int initialLeft = pocketButton.getLeft();
final int initialTop = pocketButton.getTop();
final int translatedLeft =
(holder.itemView.getWidth() - pocketButton.getWidth()) / 2;
final int translatedTop =
initialTop - ((holder.itemView.getHeight() - pocketButton.getHeight()) / 2);
final ArcMotion arc = new ArcMotion();

// animate the title & pocket icon up, scale the pocket icon up
PropertyValuesHolder pvhTitleUp = PropertyValuesHolder.ofFloat(View
.TRANSLATION_Y, -(holder.itemView.getHeight() / 5));
PropertyValuesHolder pvhTitleFade = PropertyValuesHolder.ofFloat(View.ALPHA,
0.54f);
Animator titleMoveFadeOut = ObjectAnimator.ofPropertyValuesHolder(holder.title,
pvhTitleUp, pvhTitleFade);

Animator pocketMoveUp = ObjectAnimator.ofFloat(pocketButton, View
.TRANSLATION_X, View.TRANSLATION_Y,
arc.getPath(initialLeft, initialTop, translatedLeft, translatedTop));
PropertyValuesHolder pvhPocketScaleUpX = PropertyValuesHolder.ofFloat(View
.SCALE_X, 3f);
PropertyValuesHolder pvhPocketScaleUpY = PropertyValuesHolder.ofFloat(View
.SCALE_Y, 3f);
Animator pocketScaleUp = ObjectAnimator.ofPropertyValuesHolder(pocketButton,
pvhPocketScaleUpX, pvhPocketScaleUpY);
ObjectAnimator pocketFadeUp = ObjectAnimator.ofInt(pocketButton,
ViewUtils.IMAGE_ALPHA, 255);

AnimatorSet up = new AnimatorSet();
up.playTogether(titleMoveFadeOut, pocketMoveUp, pocketScaleUp, pocketFadeUp);
up.setDuration(300);
up.setInterpolator(AnimationUtils.loadInterpolator(host, android.R
.interpolator.fast_out_slow_in));

// animate everything back into place
PropertyValuesHolder pvhTitleMoveUp = PropertyValuesHolder.ofFloat(View
.TRANSLATION_Y, 0f);
PropertyValuesHolder pvhTitleFadeUp = PropertyValuesHolder.ofFloat(View
.ALPHA, 1f);
Animator titleMoveFadeIn = ObjectAnimator.ofPropertyValuesHolder(holder.title,
pvhTitleMoveUp, pvhTitleFadeUp);
Animator pocketMoveDown = ObjectAnimator.ofFloat(pocketButton, View
.TRANSLATION_X, View.TRANSLATION_Y,
arc.getPath(translatedLeft, translatedTop, 0, 0));
PropertyValuesHolder pvhPocketScaleDownX = PropertyValuesHolder.ofFloat(View
.SCALE_X, 1f);
PropertyValuesHolder pvhPocketScaleDownY = PropertyValuesHolder.ofFloat(View
.SCALE_Y, 1f);
Animator pvhPocketScaleDown = ObjectAnimator.ofPropertyValuesHolder
(pocketButton, pvhPocketScaleDownX, pvhPocketScaleDownY);
ObjectAnimator pocketFadeDown = ObjectAnimator.ofInt(pocketButton,
ViewUtils.IMAGE_ALPHA, 138);

AnimatorSet down = new AnimatorSet();
down.playTogether(titleMoveFadeIn, pocketMoveDown, pvhPocketScaleDown,
pocketFadeDown);
down.setDuration(300);
down.setInterpolator(AnimationUtils.loadInterpolator(host, android.R
.interpolator.fast_out_slow_in));
down.setStartDelay(500);

// play it
AnimatorSet upDown = new AnimatorSet();
upDown.playSequentially(up, down);

// clean up
upDown.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
((ViewGroup) pocketButton.getParent().getParent()).setClipChildren
(true);
holder.itemView.setHasTransientState(false);
}
});
upDown.start();
// notify changed with a payload asking RV to run the anim
notifyItemChanged(holder.getAdapterPosition(),
HomeGridItemAnimator.ANIMATE_ADD_POCKET);
}
});
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/io/plaidapp/ui/HomeActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ public void onLoadMore() {
grid.setHasFixedSize(true);
grid.addItemDecoration(new GridItemDividerDecoration(adapter.getDividedViewHolderClasses(),
this, R.dimen.divider_height, R.color.divider));
grid.setItemAnimator(new HomeGridItemAnimator());

// drawer layout treats fitsSystemWindows specially so we have to handle insets ourselves
drawer.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
Expand Down
151 changes: 151 additions & 0 deletions app/src/main/java/io/plaidapp/ui/HomeGridItemAnimator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* 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;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.support.annotation.NonNull;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.transition.ArcMotion;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;

import java.util.List;

import io.plaidapp.util.ViewUtils;

/**
* An extension to {@link DefaultItemAnimator} for running animations specific to our home grid.
*/
public class HomeGridItemAnimator extends DefaultItemAnimator {

public static final int ANIMATE_ADD_POCKET = 7;

@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}

@NonNull
@Override
public ItemHolderInfo recordPreLayoutInformation(RecyclerView.State state,
RecyclerView.ViewHolder viewHolder,
int changeFlags,
List<Object> payloads) {
ItemHolderInfo info = super.recordPreLayoutInformation(state, viewHolder, changeFlags,
payloads);
if (payloads.contains(ANIMATE_ADD_POCKET)) {
DesignerNewsItemHolderInfo dnInfo = (DesignerNewsItemHolderInfo) info;
dnInfo.animateAddToPocket = true;
return dnInfo;
}
return info;
}

@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder,
RecyclerView.ViewHolder newHolder,
ItemHolderInfo preInfo,
ItemHolderInfo postInfo) {
if (preInfo instanceof DesignerNewsItemHolderInfo
&& ((DesignerNewsItemHolderInfo) preInfo).animateAddToPocket) {
final FeedAdapter.DesignerNewsStoryHolder holder =
(FeedAdapter.DesignerNewsStoryHolder) newHolder;

// setup for anim
holder.itemView.setHasTransientState(true);
((ViewGroup) holder.pocket.getParent().getParent()).setClipChildren(false);
final int initialLeft = holder.pocket.getLeft();
final int initialTop = holder.pocket.getTop();
final int translatedLeft =
(holder.itemView.getWidth() - holder.pocket.getWidth()) / 2;
final int translatedTop =
initialTop - ((holder.itemView.getHeight() - holder.pocket.getHeight()) / 2);
final ArcMotion arc = new ArcMotion();

// animate the title & pocket icon up, scale the pocket icon up
Animator titleMoveFadeOut = ObjectAnimator.ofPropertyValuesHolder(holder.title,
PropertyValuesHolder.ofFloat(View .TRANSLATION_Y,
-(holder.itemView.getHeight() / 5)),
PropertyValuesHolder.ofFloat(View.ALPHA, 0.54f));

Animator pocketMoveUp = ObjectAnimator.ofFloat(holder.pocket,
View.TRANSLATION_X, View.TRANSLATION_Y,
arc.getPath(initialLeft, initialTop, translatedLeft, translatedTop));
Animator pocketScaleUp = ObjectAnimator.ofPropertyValuesHolder(holder.pocket,
PropertyValuesHolder.ofFloat(View.SCALE_X, 3f),
PropertyValuesHolder.ofFloat(View.SCALE_Y, 3f));
ObjectAnimator pocketFadeUp = ObjectAnimator.ofInt(holder.pocket,
ViewUtils.IMAGE_ALPHA, 255);

AnimatorSet up = new AnimatorSet();
up.playTogether(titleMoveFadeOut, pocketMoveUp, pocketScaleUp, pocketFadeUp);
up.setDuration(300);
up.setInterpolator(AnimationUtils.loadInterpolator(holder.itemView.getContext(),
android.R.interpolator.fast_out_slow_in));

// animate everything back into place
Animator titleMoveFadeIn = ObjectAnimator.ofPropertyValuesHolder(holder.title,
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0f),
PropertyValuesHolder.ofFloat(View.ALPHA, 1f));
Animator pocketMoveDown = ObjectAnimator.ofFloat(holder.pocket,
View.TRANSLATION_X, View.TRANSLATION_Y,
arc.getPath(translatedLeft, translatedTop, 0, 0));
Animator pvhPocketScaleDown = ObjectAnimator.ofPropertyValuesHolder(holder.pocket,
PropertyValuesHolder.ofFloat(View.SCALE_X, 1f),
PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f));
ObjectAnimator pocketFadeDown = ObjectAnimator.ofInt(holder.pocket,
ViewUtils.IMAGE_ALPHA, 138);

AnimatorSet down = new AnimatorSet();
down.playTogether(titleMoveFadeIn, pocketMoveDown, pvhPocketScaleDown, pocketFadeDown);
down.setDuration(300);
down.setInterpolator(AnimationUtils.loadInterpolator(holder.itemView.getContext(),
android.R.interpolator.fast_out_slow_in));
down.setStartDelay(500);

// play it
AnimatorSet upDown = new AnimatorSet();
upDown.playSequentially(up, down);

// clean up
upDown.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
((ViewGroup) holder.pocket.getParent().getParent()).setClipChildren(true);
holder.itemView.setHasTransientState(false);
}
});
upDown.start();
}
return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
}

@Override
public ItemHolderInfo obtainHolderInfo() {
return new DesignerNewsItemHolderInfo();
}

/* package */ class DesignerNewsItemHolderInfo extends ItemHolderInfo {
boolean animateAddToPocket;
}
}

0 comments on commit 13b113a

Please sign in to comment.