/*
* Copyright (C) 2016 Andrey Kulikov (andkulikov@gmail.com)
*
* 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.transitionseverywhere.extra;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.transitionseverywhere.R;
import com.transitionseverywhere.Transition;
import com.transitionseverywhere.TransitionUtils;
import com.transitionseverywhere.TransitionValues;
import com.transitionseverywhere.Visibility;
/**
* This transition tracks changes to the visibility of target views in the
* start and end scenes and scales views up or down. Visibility is determined by both the
* {@link View#setVisibility(int)} state of the view as well as whether it
* is parented in the current view hierarchy. Disappearing Views are
* limited as described in {@link Visibility#onDisappear(android.view.ViewGroup,
* TransitionValues, int, TransitionValues, int)}.
* <p/>
* Created by Andrey Kulikov on 13/03/16.
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class Scale extends Visibility {
static final String PROPNAME_SCALE_X = "scale:scaleX";
static final String PROPNAME_SCALE_Y = "scale:scaleY";
private float mDisappearedScale = 0f;
public Scale() {
}
/**
* @param disappearedScale Value of scale on start of appearing or in finish of disappearing.
* Default value is 0. Can be useful for mixing some Visibility
* transitions, for example Scale and Fade
*/
public Scale(float disappearedScale) {
setDisappearedScale(disappearedScale);
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
super.captureStartValues(transitionValues);
if (transitionValues.view != null) {
transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
transitionValues.values.put(PROPNAME_SCALE_Y, transitionValues.view.getScaleY());
}
}
/**
* @param disappearedScale Value of scale on start of appearing or in finish of disappearing.
* Default value is 0. Can be useful for mixing some Visibility
* transitions, for example Scale and Fade
* @return This Scale object.
*/
public Scale setDisappearedScale(float disappearedScale) {
if (disappearedScale < 0f) {
throw new IllegalArgumentException("disappearedScale cannot be negative!");
}
mDisappearedScale = disappearedScale;
return this;
}
public Scale(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Scale);
setDisappearedScale(a.getFloat(R.styleable.Scale_disappearedScale, mDisappearedScale));
a.recycle();
}
@Nullable
private Animator createAnimation(final View view, float startScale, float endScale, TransitionValues values) {
final float initialScaleX = view.getScaleX();
final float initialScaleY = view.getScaleY();
float startScaleX = initialScaleX * startScale;
float endScaleX = initialScaleX * endScale;
float startScaleY = initialScaleY * startScale;
float endScaleY = initialScaleY * endScale;
if (values != null) {
Float savedScaleX = (Float) values.values.get(PROPNAME_SCALE_X);
Float savedScaleY = (Float) values.values.get(PROPNAME_SCALE_Y);
// if saved value is not equal initial value it means that previous
// transition was interrupted and in the onTransitionEnd
// we've applied endScale. we should apply proper value to
// continue animation from the interrupted state
if (savedScaleX != null && savedScaleX != initialScaleX) {
startScaleX = savedScaleX;
}
if (savedScaleY != null && savedScaleY != initialScaleY) {
startScaleY = savedScaleY;
}
}
view.setScaleX(startScaleX);
view.setScaleY(startScaleY);
Animator animator = TransitionUtils.mergeAnimators(
ObjectAnimator.ofFloat(view, View.SCALE_X, startScaleX, endScaleX),
ObjectAnimator.ofFloat(view, View.SCALE_Y, startScaleY, endScaleY));
addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
view.setScaleX(initialScaleX);
view.setScaleY(initialScaleY);
}
});
return animator;
}
@Override
public Animator onAppear(ViewGroup sceneRoot, final View view, TransitionValues startValues,
TransitionValues endValues) {
return createAnimation(view, mDisappearedScale, 1f, startValues);
}
@Override
public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,
TransitionValues endValues) {
return createAnimation(view, 1f, mDisappearedScale, startValues);
}
}