blob: 1135c215660e2f2c1f60dab9da619e67895d5ee6 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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 com.android.documentsui.dirlist;
import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.v4.util.ArrayMap;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import com.android.documentsui.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Performs change animations on Items in DirectoryFragment's RecyclerView. This class overrides
* the way selection animations are normally performed - instead of cross fading the old Item with a
* new Item, this class manually animates a background color change. This enables selected Items to
* correctly maintain focus.
*/
class DirectoryItemAnimator extends DefaultItemAnimator {
private final List<ColorAnimation> mPendingAnimations = new ArrayList<>();
private final Map<RecyclerView.ViewHolder, ColorAnimation> mRunningAnimations =
new ArrayMap<>();
private final Integer mDefaultColor;
private final Integer mSelectedColor;
public DirectoryItemAnimator(Context context) {
mDefaultColor = context.getResources().getColor(R.color.item_doc_background);
mSelectedColor = context.getResources().getColor(R.color.item_doc_background_selected);
}
@Override
public void runPendingAnimations() {
super.runPendingAnimations();
for (ColorAnimation anim: mPendingAnimations) {
anim.start();
mRunningAnimations.put(anim.viewHolder, anim);
}
mPendingAnimations.clear();
}
@Override
public void endAnimation(RecyclerView.ViewHolder vh) {
super.endAnimation(vh);
for (int i = mPendingAnimations.size() - 1; i >= 0; --i) {
ColorAnimation anim = mPendingAnimations.get(i);
if (anim.viewHolder == vh) {
mPendingAnimations.remove(i);
anim.end();
}
}
ColorAnimation anim = mRunningAnimations.get(vh);
if (anim != null) {
anim.cancel();
}
}
@Override
public ItemHolderInfo recordPreLayoutInformation(
RecyclerView.State state,
RecyclerView.ViewHolder viewHolder,
@AdapterChanges int changeFlags,
List<Object> payloads) {
ItemInfo info = (ItemInfo) super.recordPreLayoutInformation(state,
viewHolder, changeFlags, payloads);
info.isActivated = viewHolder.itemView.isActivated();
return info;
}
@Override
public ItemHolderInfo recordPostLayoutInformation(
RecyclerView.State state, RecyclerView.ViewHolder viewHolder) {
ItemInfo info = (ItemInfo) super.recordPostLayoutInformation(state,
viewHolder);
info.isActivated = viewHolder.itemView.isActivated();
return info;
}
@Override
public boolean animateChange(final RecyclerView.ViewHolder oldHolder,
RecyclerView.ViewHolder newHolder, ItemHolderInfo preInfo,
ItemHolderInfo postInfo) {
if (oldHolder != newHolder) {
return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
}
ItemInfo pre = (ItemInfo)preInfo;
ItemInfo post = (ItemInfo)postInfo;
if (pre.isActivated == post.isActivated) {
dispatchAnimationFinished(oldHolder);
return false;
} else {
Integer startColor = pre.isActivated ? mSelectedColor : mDefaultColor;
Integer endColor = post.isActivated ? mSelectedColor : mDefaultColor;
oldHolder.itemView.setBackgroundColor(startColor);
mPendingAnimations.add(new ColorAnimation(oldHolder, startColor, endColor));
}
return true;
}
@Override
public ItemHolderInfo obtainHolderInfo() {
return new ItemInfo();
}
@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder vh) {
return true;
}
class ItemInfo extends DefaultItemAnimator.ItemHolderInfo {
boolean isActivated;
};
/**
* Animates changes in background color.
*/
class ColorAnimation
implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
ValueAnimator mValueAnimator;
final RecyclerView.ViewHolder viewHolder;
int mEndColor;
public ColorAnimation(RecyclerView.ViewHolder vh, int startColor, int endColor)
{
viewHolder = vh;
mValueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), startColor, endColor);
mValueAnimator.addUpdateListener(this);
mValueAnimator.addListener(this);
mEndColor = endColor;
}
public void start() {
mValueAnimator.start();
}
public void cancel() {
mValueAnimator.cancel();
}
public void end() {
mValueAnimator.end();
}
@Override
public void onAnimationUpdate(ValueAnimator animator) {
viewHolder.itemView.setBackgroundColor((Integer)animator.getAnimatedValue());
}
@Override
public void onAnimationEnd(Animator animator) {
viewHolder.itemView.setBackgroundColor(mEndColor);
mRunningAnimations.remove(viewHolder);
dispatchAnimationFinished(viewHolder);
}
@Override
public void onAnimationStart(Animator animation) {
dispatchAnimationStarted(viewHolder);
}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
};
};