mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 1255162 - Replace NineOldAndroids with system API. r=liuche
NineOldAndroids is a backport of the animation API that was introduced with Honeycomb. Since we stopped supporting Gingerbread we do not need this library anymore and can just use the system API. MozReview-Commit-ID: Fv6ALlIktt5 --HG-- extra : rebase_source : 1b0b40303edb985361a23536921de38d5295604a
This commit is contained in:
parent
58887c9d97
commit
d785077dda
@ -143,8 +143,8 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.ViewFlipper;
|
||||
import com.keepsafe.switchboard.AsyncConfigLoader;
|
||||
import com.keepsafe.switchboard.SwitchBoard;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
package org.mozilla.gecko.animation;
|
||||
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import android.animation.Animator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -11,9 +11,9 @@ import android.util.AttributeSet;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorListenerAdapter;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
|
@ -13,10 +13,9 @@ import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorSet;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.nineoldandroids.view.ViewHelper;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
||||
import org.mozilla.gecko.Restrictions;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
@ -122,8 +121,8 @@ public class FirstrunPager extends ViewPager {
|
||||
}
|
||||
|
||||
private void animateLoad() {
|
||||
ViewHelper.setTranslationY(this, 500);
|
||||
ViewHelper.setAlpha(this, 0);
|
||||
setTranslationY(500);
|
||||
setAlpha(0);
|
||||
|
||||
final Animator translateAnimator = ObjectAnimator.ofFloat(this, "translationY", 0);
|
||||
translateAnimator.setDuration(400);
|
||||
|
@ -23,11 +23,10 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorListenerAdapter;
|
||||
import com.nineoldandroids.animation.AnimatorSet;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.nineoldandroids.view.ViewHelper;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
||||
public class TabQueuePrompt extends Locales.LocaleAwareActivity {
|
||||
public static final String LOGTAG = "Gecko" + TabQueuePrompt.class.getSimpleName();
|
||||
@ -96,8 +95,8 @@ public class TabQueuePrompt extends Locales.LocaleAwareActivity {
|
||||
buttonContainer = findViewById(R.id.button_container);
|
||||
enabledConfirmation = findViewById(R.id.enabled_confirmation);
|
||||
|
||||
ViewHelper.setTranslationY(containerView, 500);
|
||||
ViewHelper.setAlpha(containerView, 0);
|
||||
containerView.setTranslationY(500);
|
||||
containerView.setAlpha(0);
|
||||
|
||||
final Animator translateAnimator = ObjectAnimator.ofFloat(containerView, "translationY", 0);
|
||||
translateAnimator.setDuration(400);
|
||||
@ -124,7 +123,7 @@ public class TabQueuePrompt extends Locales.LocaleAwareActivity {
|
||||
|
||||
private void onConfirmButtonPressed() {
|
||||
enabledConfirmation.setVisibility(View.VISIBLE);
|
||||
ViewHelper.setAlpha(enabledConfirmation, 0);
|
||||
enabledConfirmation.setAlpha(0);
|
||||
|
||||
final Animator buttonsAlphaAnimator = ObjectAnimator.ofFloat(buttonContainer, "alpha", 0);
|
||||
buttonsAlphaAnimator.setDuration(300);
|
||||
|
@ -18,10 +18,10 @@ import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver.OnPreDrawListener;
|
||||
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.Animator.AnimatorListener;
|
||||
import com.nineoldandroids.animation.AnimatorSet;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import android.animation.Animator;
|
||||
import android.animation.Animator.AnimatorListener;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -34,12 +34,11 @@ import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.GridView;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorSet;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.nineoldandroids.animation.PropertyValuesHolder;
|
||||
import com.nineoldandroids.animation.ValueAnimator;
|
||||
import com.nineoldandroids.view.ViewHelper;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -316,9 +315,9 @@ class TabsGridLayout extends GridView
|
||||
}
|
||||
|
||||
private void resetTransforms(View view) {
|
||||
ViewHelper.setAlpha(view, 1);
|
||||
ViewHelper.setTranslationX(view, 0);
|
||||
ViewHelper.setTranslationY(view, 0);
|
||||
view.setAlpha(1);
|
||||
view.setTranslationX(0);
|
||||
view.setTranslationY(0);
|
||||
|
||||
((TabsLayoutItemView) view).setCloseVisible(true);
|
||||
}
|
||||
@ -591,7 +590,7 @@ class TabsGridLayout extends GridView
|
||||
|
||||
boolean dismiss = false;
|
||||
|
||||
float deltaX = ViewHelper.getTranslationX(mSwipeView);
|
||||
float deltaX = mSwipeView.getTranslationX();
|
||||
|
||||
if (Math.abs(deltaX) > mTabWidth / 2) {
|
||||
dismiss = true;
|
||||
@ -645,10 +644,9 @@ class TabsGridLayout extends GridView
|
||||
}
|
||||
|
||||
if (mSwiping) {
|
||||
ViewHelper.setTranslationX(mSwipeView, delta);
|
||||
mSwipeView.setTranslationX(delta);
|
||||
|
||||
ViewHelper.setAlpha(mSwipeView, Math.min(1f,
|
||||
1f - 2f * Math.abs(delta) / mTabWidth));
|
||||
mSwipeView.setAlpha(Math.min(1f, 1f - 2f * Math.abs(delta) / mTabWidth));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -15,11 +15,10 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorListenerAdapter;
|
||||
import com.nineoldandroids.animation.AnimatorSet;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.nineoldandroids.view.ViewHelper;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
||||
public class TrackingProtectionPrompt extends Locales.LocaleAwareActivity {
|
||||
public static final String LOGTAG = "Gecko" + TrackingProtectionPrompt.class.getSimpleName();
|
||||
@ -63,8 +62,8 @@ public class TrackingProtectionPrompt extends Locales.LocaleAwareActivity {
|
||||
|
||||
containerView = findViewById(R.id.tracking_protection_inner_container);
|
||||
|
||||
ViewHelper.setTranslationY(containerView, 500);
|
||||
ViewHelper.setAlpha(containerView, 0);
|
||||
containerView.setTranslationY(500);
|
||||
containerView.setAlpha(0);
|
||||
|
||||
final Animator translateAnimator = ObjectAnimator.ofFloat(containerView, "translationY", 0);
|
||||
translateAnimator.setDuration(400);
|
||||
|
@ -12,7 +12,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.nineoldandroids.view.ViewHelper;
|
||||
import org.mozilla.gecko.widget.themed.ThemedImageView;
|
||||
|
||||
/**
|
||||
@ -54,8 +53,8 @@ public abstract class CropImageView extends ThemedImageView {
|
||||
// Setting the pivots means that the image will be drawn from the top left hand corner. There are
|
||||
// issues in Android 4.1 (16) which mean setting these values to 0 may not work.
|
||||
// http://stackoverflow.com/questions/26658124/setpivotx-doesnt-work-on-android-4-1-1-nineoldandroids
|
||||
ViewHelper.setPivotX(this, 1);
|
||||
ViewHelper.setPivotY(this, 1);
|
||||
setPivotX(1);
|
||||
setPivotY(1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,11 +26,10 @@ import android.widget.AbsListView;
|
||||
import android.widget.AbsListView.RecyclerListener;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorListenerAdapter;
|
||||
import com.nineoldandroids.animation.ValueAnimator;
|
||||
import com.nineoldandroids.view.ViewHelper;
|
||||
import com.nineoldandroids.view.ViewPropertyAnimator;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
@ -173,8 +172,8 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
|
||||
// To reset the view to the correct height after its animation, the view's height
|
||||
// is stored in its tag. Reset the view here.
|
||||
if (tag instanceof Integer) {
|
||||
ViewHelper.setAlpha(view, 1f);
|
||||
ViewHelper.setTranslationX(view, 0);
|
||||
view.setAlpha(1f);
|
||||
view.setTranslationX(0);
|
||||
final ViewGroup.LayoutParams lp = view.getLayoutParams();
|
||||
lp.height = (int) tag;
|
||||
view.setLayoutParams(lp);
|
||||
@ -255,7 +254,7 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
|
||||
mDismissing = true;
|
||||
final View downView = mDownView; // mDownView gets null'd before animation ends
|
||||
final int downPosition = mDownPosition;
|
||||
ViewPropertyAnimator.animate(mDownView)
|
||||
mDownView.animate()
|
||||
.translationX(dismissRight ? mViewWidth : -mViewWidth)
|
||||
.alpha(0)
|
||||
.setDuration(mAnimationTime)
|
||||
@ -267,7 +266,7 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
|
||||
});
|
||||
} else {
|
||||
// cancel
|
||||
ViewPropertyAnimator.animate(mDownView)
|
||||
mDownView.animate()
|
||||
.translationX(0)
|
||||
.alpha(1)
|
||||
.setDuration(mAnimationTime)
|
||||
@ -307,9 +306,8 @@ public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
|
||||
}
|
||||
|
||||
if (mSwiping) {
|
||||
ViewHelper.setTranslationX(mDownView, deltaX);
|
||||
ViewHelper.setAlpha(mDownView, Math.max(0f, Math.min(1f,
|
||||
1f - 2f * Math.abs(deltaX) / mViewWidth)));
|
||||
mDownView.setTranslationX(deltaX);
|
||||
mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth)));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -799,34 +799,6 @@ gtjar.sources += [ thirdparty_source_dir + f for f in [
|
||||
'com/keepsafe/switchboard/Preferences.java',
|
||||
'com/keepsafe/switchboard/Switch.java',
|
||||
'com/keepsafe/switchboard/SwitchBoard.java',
|
||||
'com/nineoldandroids/animation/Animator.java',
|
||||
'com/nineoldandroids/animation/AnimatorInflater.java',
|
||||
'com/nineoldandroids/animation/AnimatorListenerAdapter.java',
|
||||
'com/nineoldandroids/animation/AnimatorSet.java',
|
||||
'com/nineoldandroids/animation/ArgbEvaluator.java',
|
||||
'com/nineoldandroids/animation/FloatEvaluator.java',
|
||||
'com/nineoldandroids/animation/FloatKeyframeSet.java',
|
||||
'com/nineoldandroids/animation/IntEvaluator.java',
|
||||
'com/nineoldandroids/animation/IntKeyframeSet.java',
|
||||
'com/nineoldandroids/animation/Keyframe.java',
|
||||
'com/nineoldandroids/animation/KeyframeSet.java',
|
||||
'com/nineoldandroids/animation/ObjectAnimator.java',
|
||||
'com/nineoldandroids/animation/PreHoneycombCompat.java',
|
||||
'com/nineoldandroids/animation/PropertyValuesHolder.java',
|
||||
'com/nineoldandroids/animation/TimeAnimator.java',
|
||||
'com/nineoldandroids/animation/TypeEvaluator.java',
|
||||
'com/nineoldandroids/animation/ValueAnimator.java',
|
||||
'com/nineoldandroids/util/FloatProperty.java',
|
||||
'com/nineoldandroids/util/IntProperty.java',
|
||||
'com/nineoldandroids/util/NoSuchPropertyException.java',
|
||||
'com/nineoldandroids/util/Property.java',
|
||||
'com/nineoldandroids/util/ReflectiveProperty.java',
|
||||
'com/nineoldandroids/view/animation/AnimatorProxy.java',
|
||||
'com/nineoldandroids/view/ViewHelper.java',
|
||||
'com/nineoldandroids/view/ViewPropertyAnimator.java',
|
||||
'com/nineoldandroids/view/ViewPropertyAnimatorHC.java',
|
||||
'com/nineoldandroids/view/ViewPropertyAnimatorICS.java',
|
||||
'com/nineoldandroids/view/ViewPropertyAnimatorPreHC.java',
|
||||
'com/squareup/leakcanary/LeakCanary.java',
|
||||
'com/squareup/leakcanary/RefWatcher.java',
|
||||
'com/squareup/picasso/Action.java',
|
||||
|
@ -29,9 +29,9 @@ import android.view.View;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.AnimatorSet;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
||||
/**
|
||||
* The main entrance for the Android search intent.
|
||||
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This is the superclass for classes which provide basic support for animations which can be
|
||||
* started, ended, and have <code>AnimatorListeners</code> added to them.
|
||||
*/
|
||||
public abstract class Animator implements Cloneable {
|
||||
|
||||
|
||||
/**
|
||||
* The set of listeners to be sent events through the life of an animation.
|
||||
*/
|
||||
ArrayList<AnimatorListener> mListeners = null;
|
||||
|
||||
/**
|
||||
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
||||
* running after that delay elapses. A non-delayed animation will have its initial
|
||||
* value(s) set immediately, followed by calls to
|
||||
* {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
|
||||
*
|
||||
* <p>The animation started by calling this method will be run on the thread that called
|
||||
* this method. This thread should have a Looper on it (a runtime exception will be thrown if
|
||||
* this is not the case). Also, if the animation will animate
|
||||
* properties of objects in the view hierarchy, then the calling thread should be the UI
|
||||
* thread for that view hierarchy.</p>
|
||||
*
|
||||
*/
|
||||
public void start() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
|
||||
* stop in its tracks, sending an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
|
||||
* its listeners, followed by an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the animation. This causes the animation to assign the end value of the property being
|
||||
* animated, then calling the
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
|
||||
* its listeners.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
*
|
||||
* @return the number of milliseconds to delay running the animation
|
||||
*/
|
||||
public abstract long getStartDelay();
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
|
||||
* @param startDelay The amount of the delay, in milliseconds
|
||||
*/
|
||||
public abstract void setStartDelay(long startDelay);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the length of the animation.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract Animator setDuration(long duration);
|
||||
|
||||
/**
|
||||
* Gets the length of the animation.
|
||||
*
|
||||
* @return The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract long getDuration();
|
||||
|
||||
/**
|
||||
* The time interpolator used in calculating the elapsed fraction of this animation. The
|
||||
* interpolator determines whether the animation runs with linear or non-linear motion,
|
||||
* such as acceleration and deceleration. The default value is
|
||||
* {@link android.view.animation.AccelerateDecelerateInterpolator}
|
||||
*
|
||||
* @param value the interpolator to be used by this animation
|
||||
*/
|
||||
public abstract void setInterpolator(/*Time*/Interpolator value);
|
||||
|
||||
/**
|
||||
* Returns whether this Animator is currently running (having been started and gone past any
|
||||
* initial startDelay period and not yet ended).
|
||||
*
|
||||
* @return Whether the Animator is running.
|
||||
*/
|
||||
public abstract boolean isRunning();
|
||||
|
||||
/**
|
||||
* Returns whether this Animator has been started and not yet ended. This state is a superset
|
||||
* of the state of {@link #isRunning()}, because an Animator with a nonzero
|
||||
* {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the
|
||||
* delay phase, whereas {@link #isRunning()} will return true only after the delay phase
|
||||
* is complete.
|
||||
*
|
||||
* @return Whether the Animator has been started and not yet ended.
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
// Default method returns value for isRunning(). Subclasses should override to return a
|
||||
// real value.
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the set of listeners that are sent events through the life of an
|
||||
* animation, such as start, repeat, and end.
|
||||
*
|
||||
* @param listener the listener to be added to the current set of listeners for this animation.
|
||||
*/
|
||||
public void addListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
mListeners = new ArrayList<AnimatorListener>();
|
||||
}
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the set listening to this animation.
|
||||
*
|
||||
* @param listener the listener to be removed from the current set of listeners for this
|
||||
* animation.
|
||||
*/
|
||||
public void removeListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
return;
|
||||
}
|
||||
mListeners.remove(listener);
|
||||
if (mListeners.size() == 0) {
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
|
||||
* listening for events on this <code>Animator</code> object.
|
||||
*
|
||||
* @return ArrayList<AnimatorListener> The set of listeners.
|
||||
*/
|
||||
public ArrayList<AnimatorListener> getListeners() {
|
||||
return mListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners from this object. This is equivalent to calling
|
||||
* <code>getListeners()</code> followed by calling <code>clear()</code> on the
|
||||
* returned list of listeners.
|
||||
*/
|
||||
public void removeAllListeners() {
|
||||
if (mListeners != null) {
|
||||
mListeners.clear();
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator clone() {
|
||||
try {
|
||||
final Animator anim = (Animator) super.clone();
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> oldListeners = mListeners;
|
||||
anim.mListeners = new ArrayList<AnimatorListener>();
|
||||
int numListeners = oldListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
anim.mListeners.add(oldListeners.get(i));
|
||||
}
|
||||
}
|
||||
return anim;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* starting values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupStartValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* ending values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupEndValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation. Not all subclasses
|
||||
* operate on target objects (for example, {@link ValueAnimator}, but this method
|
||||
* is on the superclass for the convenience of dealing generically with those subclasses
|
||||
* that do handle targets.
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
public void setTarget(Object target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An animation listener receives notifications from an animation.
|
||||
* Notifications indicate animation related events, such as the end or the
|
||||
* repetition of the animation.</p>
|
||||
*/
|
||||
public static interface AnimatorListener {
|
||||
/**
|
||||
* <p>Notifies the start of the animation.</p>
|
||||
*
|
||||
* @param animation The started animation.
|
||||
*/
|
||||
void onAnimationStart(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the end of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which reached its end.
|
||||
*/
|
||||
void onAnimationEnd(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the cancellation of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which was canceled.
|
||||
*/
|
||||
void onAnimationCancel(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the repetition of the animation.</p>
|
||||
*
|
||||
* @param animation The animation which was repeated.
|
||||
*/
|
||||
void onAnimationRepeat(Animator animation);
|
||||
}
|
||||
}
|
@ -1,344 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class is used to instantiate animator XML files into Animator objects.
|
||||
* <p>
|
||||
* For performance reasons, inflation relies heavily on pre-processing of
|
||||
* XML files that is done at build time. Therefore, it is not currently possible
|
||||
* to use this inflater with an XmlPullParser over a plain XML file at runtime;
|
||||
* it only works with an XmlPullParser returned from a compiled resource (R.
|
||||
* <em>something</em> file.)
|
||||
*/
|
||||
public class AnimatorInflater {
|
||||
private static final int[] AnimatorSet = new int[] {
|
||||
/* 0 */ android.R.attr.ordering,
|
||||
};
|
||||
private static final int AnimatorSet_ordering = 0;
|
||||
|
||||
private static final int[] PropertyAnimator = new int[] {
|
||||
/* 0 */ android.R.attr.propertyName,
|
||||
};
|
||||
private static final int PropertyAnimator_propertyName = 0;
|
||||
|
||||
private static final int[] Animator = new int[] {
|
||||
/* 0 */ android.R.attr.interpolator,
|
||||
/* 1 */ android.R.attr.duration,
|
||||
/* 2 */ android.R.attr.startOffset,
|
||||
/* 3 */ android.R.attr.repeatCount,
|
||||
/* 4 */ android.R.attr.repeatMode,
|
||||
/* 5 */ android.R.attr.valueFrom,
|
||||
/* 6 */ android.R.attr.valueTo,
|
||||
/* 7 */ android.R.attr.valueType,
|
||||
};
|
||||
private static final int Animator_interpolator = 0;
|
||||
private static final int Animator_duration = 1;
|
||||
private static final int Animator_startOffset = 2;
|
||||
private static final int Animator_repeatCount = 3;
|
||||
private static final int Animator_repeatMode = 4;
|
||||
private static final int Animator_valueFrom = 5;
|
||||
private static final int Animator_valueTo = 6;
|
||||
private static final int Animator_valueType = 7;
|
||||
|
||||
/**
|
||||
* These flags are used when parsing AnimatorSet objects
|
||||
*/
|
||||
private static final int TOGETHER = 0;
|
||||
//private static final int SEQUENTIALLY = 1;
|
||||
|
||||
/**
|
||||
* Enum values used in XML attributes to indicate the value for mValueType
|
||||
*/
|
||||
private static final int VALUE_TYPE_FLOAT = 0;
|
||||
//private static final int VALUE_TYPE_INT = 1;
|
||||
//private static final int VALUE_TYPE_COLOR = 4;
|
||||
//private static final int VALUE_TYPE_CUSTOM = 5;
|
||||
|
||||
/**
|
||||
* Loads an {@link Animator} object from a resource
|
||||
*
|
||||
* @param context Application context used to access resources
|
||||
* @param id The resource id of the animation to load
|
||||
* @return The animator object reference by the specified id
|
||||
* @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
|
||||
*/
|
||||
public static Animator loadAnimator(Context context, int id)
|
||||
throws NotFoundException {
|
||||
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = context.getResources().getAnimation(id);
|
||||
return createAnimatorFromXml(context, parser);
|
||||
} catch (XmlPullParserException ex) {
|
||||
Resources.NotFoundException rnf =
|
||||
new Resources.NotFoundException("Can't load animation resource ID #0x" +
|
||||
Integer.toHexString(id));
|
||||
rnf.initCause(ex);
|
||||
throw rnf;
|
||||
} catch (IOException ex) {
|
||||
Resources.NotFoundException rnf =
|
||||
new Resources.NotFoundException("Can't load animation resource ID #0x" +
|
||||
Integer.toHexString(id));
|
||||
rnf.initCause(ex);
|
||||
throw rnf;
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
|
||||
}
|
||||
|
||||
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser,
|
||||
AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
Animator anim = null;
|
||||
ArrayList<Animator> childAnims = null;
|
||||
|
||||
// Make sure we are on a start tag.
|
||||
int type;
|
||||
int depth = parser.getDepth();
|
||||
|
||||
while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
|
||||
&& type != XmlPullParser.END_DOCUMENT) {
|
||||
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = parser.getName();
|
||||
|
||||
if (name.equals("objectAnimator")) {
|
||||
anim = loadObjectAnimator(c, attrs);
|
||||
} else if (name.equals("animator")) {
|
||||
anim = loadAnimator(c, attrs, null);
|
||||
} else if (name.equals("set")) {
|
||||
anim = new AnimatorSet();
|
||||
TypedArray a = c.obtainStyledAttributes(attrs,
|
||||
/*com.android.internal.R.styleable.*/AnimatorSet);
|
||||
|
||||
TypedValue orderingValue = new TypedValue();
|
||||
a.getValue(/*com.android.internal.R.styleable.*/AnimatorSet_ordering, orderingValue);
|
||||
int ordering = orderingValue.type == TypedValue.TYPE_INT_DEC ? orderingValue.data : TOGETHER;
|
||||
|
||||
createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim, ordering);
|
||||
a.recycle();
|
||||
} else {
|
||||
throw new RuntimeException("Unknown animator name: " + parser.getName());
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
if (childAnims == null) {
|
||||
childAnims = new ArrayList<Animator>();
|
||||
}
|
||||
childAnims.add(anim);
|
||||
}
|
||||
}
|
||||
if (parent != null && childAnims != null) {
|
||||
Animator[] animsArray = new Animator[childAnims.size()];
|
||||
int index = 0;
|
||||
for (Animator a : childAnims) {
|
||||
animsArray[index++] = a;
|
||||
}
|
||||
if (sequenceOrdering == TOGETHER) {
|
||||
parent.playTogether(animsArray);
|
||||
} else {
|
||||
parent.playSequentially(animsArray);
|
||||
}
|
||||
}
|
||||
|
||||
return anim;
|
||||
|
||||
}
|
||||
|
||||
private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs)
|
||||
throws NotFoundException {
|
||||
|
||||
ObjectAnimator anim = new ObjectAnimator();
|
||||
|
||||
loadAnimator(context, attrs, anim);
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/PropertyAnimator);
|
||||
|
||||
String propertyName = a.getString(/*com.android.internal.R.styleable.*/PropertyAnimator_propertyName);
|
||||
|
||||
anim.setPropertyName(propertyName);
|
||||
|
||||
a.recycle();
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new animation whose parameters come from the specified context and
|
||||
* attributes set.
|
||||
*
|
||||
* @param context the application environment
|
||||
* @param attrs the set of attributes holding the animation parameters
|
||||
*/
|
||||
private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim)
|
||||
throws NotFoundException {
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/Animator);
|
||||
|
||||
long duration = a.getInt(/*com.android.internal.R.styleable.*/Animator_duration, 0);
|
||||
|
||||
long startDelay = a.getInt(/*com.android.internal.R.styleable.*/Animator_startOffset, 0);
|
||||
|
||||
int valueType = a.getInt(/*com.android.internal.R.styleable.*/Animator_valueType,
|
||||
VALUE_TYPE_FLOAT);
|
||||
|
||||
if (anim == null) {
|
||||
anim = new ValueAnimator();
|
||||
}
|
||||
//TypeEvaluator evaluator = null;
|
||||
|
||||
int valueFromIndex = /*com.android.internal.R.styleable.*/Animator_valueFrom;
|
||||
int valueToIndex = /*com.android.internal.R.styleable.*/Animator_valueTo;
|
||||
|
||||
boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
|
||||
|
||||
TypedValue tvFrom = a.peekValue(valueFromIndex);
|
||||
boolean hasFrom = (tvFrom != null);
|
||||
int fromType = hasFrom ? tvFrom.type : 0;
|
||||
TypedValue tvTo = a.peekValue(valueToIndex);
|
||||
boolean hasTo = (tvTo != null);
|
||||
int toType = hasTo ? tvTo.type : 0;
|
||||
|
||||
if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
|
||||
(hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
|
||||
// special case for colors: ignore valueType and get ints
|
||||
getFloats = false;
|
||||
anim.setEvaluator(new ArgbEvaluator());
|
||||
}
|
||||
|
||||
if (getFloats) {
|
||||
float valueFrom;
|
||||
float valueTo;
|
||||
if (hasFrom) {
|
||||
if (fromType == TypedValue.TYPE_DIMENSION) {
|
||||
valueFrom = a.getDimension(valueFromIndex, 0f);
|
||||
} else {
|
||||
valueFrom = a.getFloat(valueFromIndex, 0f);
|
||||
}
|
||||
if (hasTo) {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = a.getDimension(valueToIndex, 0f);
|
||||
} else {
|
||||
valueTo = a.getFloat(valueToIndex, 0f);
|
||||
}
|
||||
anim.setFloatValues(valueFrom, valueTo);
|
||||
} else {
|
||||
anim.setFloatValues(valueFrom);
|
||||
}
|
||||
} else {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = a.getDimension(valueToIndex, 0f);
|
||||
} else {
|
||||
valueTo = a.getFloat(valueToIndex, 0f);
|
||||
}
|
||||
anim.setFloatValues(valueTo);
|
||||
}
|
||||
} else {
|
||||
int valueFrom;
|
||||
int valueTo;
|
||||
if (hasFrom) {
|
||||
if (fromType == TypedValue.TYPE_DIMENSION) {
|
||||
valueFrom = (int) a.getDimension(valueFromIndex, 0f);
|
||||
} else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||
valueFrom = a.getColor(valueFromIndex, 0);
|
||||
} else {
|
||||
valueFrom = a.getInt(valueFromIndex, 0);
|
||||
}
|
||||
if (hasTo) {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = (int) a.getDimension(valueToIndex, 0f);
|
||||
} else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||
valueTo = a.getColor(valueToIndex, 0);
|
||||
} else {
|
||||
valueTo = a.getInt(valueToIndex, 0);
|
||||
}
|
||||
anim.setIntValues(valueFrom, valueTo);
|
||||
} else {
|
||||
anim.setIntValues(valueFrom);
|
||||
}
|
||||
} else {
|
||||
if (hasTo) {
|
||||
if (toType == TypedValue.TYPE_DIMENSION) {
|
||||
valueTo = (int) a.getDimension(valueToIndex, 0f);
|
||||
} else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
|
||||
(toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
|
||||
valueTo = a.getColor(valueToIndex, 0);
|
||||
} else {
|
||||
valueTo = a.getInt(valueToIndex, 0);
|
||||
}
|
||||
anim.setIntValues(valueTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anim.setDuration(duration);
|
||||
anim.setStartDelay(startDelay);
|
||||
|
||||
if (a.hasValue(/*com.android.internal.R.styleable.*/Animator_repeatCount)) {
|
||||
anim.setRepeatCount(
|
||||
a.getInt(/*com.android.internal.R.styleable.*/Animator_repeatCount, 0));
|
||||
}
|
||||
if (a.hasValue(/*com.android.internal.R.styleable.*/Animator_repeatMode)) {
|
||||
anim.setRepeatMode(
|
||||
a.getInt(/*com.android.internal.R.styleable.*/Animator_repeatMode,
|
||||
ValueAnimator.RESTART));
|
||||
}
|
||||
//if (evaluator != null) {
|
||||
// anim.setEvaluator(evaluator);
|
||||
//}
|
||||
|
||||
final int resID =
|
||||
a.getResourceId(/*com.android.internal.R.styleable.*/Animator_interpolator, 0);
|
||||
if (resID > 0) {
|
||||
anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID));
|
||||
}
|
||||
a.recycle();
|
||||
|
||||
return anim;
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This adapter class provides empty implementations of the methods from {@link android.animation.Animator.AnimatorListener}.
|
||||
* Any custom listener that cares only about a subset of the methods of this listener can
|
||||
* simply subclass this adapter class instead of implementing the interface directly.
|
||||
*/
|
||||
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between integer
|
||||
* values that represent ARGB colors.
|
||||
*/
|
||||
public class ArgbEvaluator implements TypeEvaluator {
|
||||
|
||||
/**
|
||||
* This function returns the calculated in-between value for a color
|
||||
* given integers that represent the start and end values in the four
|
||||
* bytes of the 32-bit int. Each channel is separately linearly interpolated
|
||||
* and the resulting calculated values are recombined into the return value.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue A 32-bit int value representing colors in the
|
||||
* separate bytes of the parameter
|
||||
* @param endValue A 32-bit int value representing colors in the
|
||||
* separate bytes of the parameter
|
||||
* @return A value that is calculated to be the linearly interpolated
|
||||
* result, derived by separating the start and end values into separate
|
||||
* color channels and interpolating each one separately, recombining the
|
||||
* resulting values in the same way.
|
||||
*/
|
||||
public Object evaluate(float fraction, Object startValue, Object endValue) {
|
||||
int startInt = (Integer) startValue;
|
||||
int startA = (startInt >> 24);
|
||||
int startR = (startInt >> 16) & 0xff;
|
||||
int startG = (startInt >> 8) & 0xff;
|
||||
int startB = startInt & 0xff;
|
||||
|
||||
int endInt = (Integer) endValue;
|
||||
int endA = (endInt >> 24);
|
||||
int endR = (endInt >> 16) & 0xff;
|
||||
int endG = (endInt >> 8) & 0xff;
|
||||
int endB = endInt & 0xff;
|
||||
|
||||
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
|
||||
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
|
||||
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
|
||||
(int)((startB + (int)(fraction * (endB - startB))));
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>float</code> values.
|
||||
*/
|
||||
public class FloatEvaluator implements TypeEvaluator<Number> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>float</code> or
|
||||
* <code>Float</code>
|
||||
* @param endValue The end value; should be of type <code>float</code> or <code>Float</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Float evaluate(float fraction, Number startValue, Number endValue) {
|
||||
float startFloat = startValue.floatValue();
|
||||
return startFloat + fraction * (endValue.floatValue() - startFloat);
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* int, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
class FloatKeyframeSet extends KeyframeSet {
|
||||
private float firstValue;
|
||||
private float lastValue;
|
||||
private float deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public FloatKeyframeSet(FloatKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getFloatValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
FloatKeyframeSet newSet = new FloatKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public float getFloatValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
|
||||
lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + fraction * deltaValue;
|
||||
} else {
|
||||
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>int</code> values.
|
||||
*/
|
||||
public class IntEvaluator implements TypeEvaluator<Integer> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>int</code> or
|
||||
* <code>Integer</code>
|
||||
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
|
||||
int startInt = startValue;
|
||||
return (int)(startInt + fraction * (endValue - startInt));
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* float, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
class IntKeyframeSet extends KeyframeSet {
|
||||
private int firstValue;
|
||||
private int lastValue;
|
||||
private int deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public IntKeyframeSet(IntKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getIntValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
IntKeyframeSet newSet = new IntKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public int getIntValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
|
||||
lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + (int)(fraction * deltaValue);
|
||||
} else {
|
||||
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||
}
|
||||
IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,360 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This class holds a time/value pair for an animation. The Keyframe class is used
|
||||
* by {@link ValueAnimator} to define the values that the animation target will have over the course
|
||||
* of the animation. As the time proceeds from one keyframe to the other, the value of the
|
||||
* target object will animate between the value at the previous keyframe and the value at the
|
||||
* next keyframe. Each keyframe also holds an optional {@link TimeInterpolator}
|
||||
* object, which defines the time interpolation over the intervalue preceding the keyframe.
|
||||
*
|
||||
* <p>The Keyframe class itself is abstract. The type-specific factory methods will return
|
||||
* a subclass of Keyframe specific to the type of value being stored. This is done to improve
|
||||
* performance when dealing with the most common cases (e.g., <code>float</code> and
|
||||
* <code>int</code> values). Other types will fall into a more general Keyframe class that
|
||||
* treats its values as Objects. Unless your animation requires dealing with a custom type
|
||||
* or a data structure that needs to be animated directly (and evaluated using an implementation
|
||||
* of {@link TypeEvaluator}), you should stick to using float and int as animations using those
|
||||
* types have lower runtime overhead than other types.</p>
|
||||
*/
|
||||
public abstract class Keyframe implements Cloneable {
|
||||
/**
|
||||
* The time at which mValue will hold true.
|
||||
*/
|
||||
float mFraction;
|
||||
|
||||
/**
|
||||
* The type of the value in this Keyframe. This type is determined at construction time,
|
||||
* based on the type of the <code>value</code> object passed into the constructor.
|
||||
*/
|
||||
Class mValueType;
|
||||
|
||||
/**
|
||||
* The optional time interpolator for the interval preceding this keyframe. A null interpolator
|
||||
* (the default) results in linear interpolation over the interval.
|
||||
*/
|
||||
private /*Time*/Interpolator mInterpolator = null;
|
||||
|
||||
/**
|
||||
* Flag to indicate whether this keyframe has a valid value. This flag is used when an
|
||||
* animation first starts, to populate placeholder keyframes with real values derived
|
||||
* from the target object.
|
||||
*/
|
||||
boolean mHasValue = false;
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction, int value) {
|
||||
return new IntKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction) {
|
||||
return new IntKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction, float value) {
|
||||
return new FloatKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction) {
|
||||
return new FloatKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction, Object value) {
|
||||
return new ObjectKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction) {
|
||||
return new ObjectKeyframe(fraction, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this keyframe has a valid value. This method is called internally when
|
||||
* an {@link ObjectAnimator} first starts; keyframes without values are assigned values at
|
||||
* that time by deriving the value for the property from the target object.
|
||||
*
|
||||
* @return boolean Whether this object has a value assigned.
|
||||
*/
|
||||
public boolean hasValue() {
|
||||
return mHasValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for this Keyframe.
|
||||
*
|
||||
* @return The value for this Keyframe.
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
|
||||
/**
|
||||
* Sets the value for this Keyframe.
|
||||
*
|
||||
* @param value value for this Keyframe.
|
||||
*/
|
||||
public abstract void setValue(Object value);
|
||||
|
||||
/**
|
||||
* Gets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @return The time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public float getFraction() {
|
||||
return mFraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @param fraction time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public void setFraction(float fraction) {
|
||||
mFraction = fraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public /*Time*/Interpolator getInterpolator() {
|
||||
return mInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public void setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of keyframe. This information is used by ValueAnimator to determine the type of
|
||||
* {@link TypeEvaluator} to use when calculating values between keyframes. The type is based
|
||||
* on the type of Keyframe created.
|
||||
*
|
||||
* @return The type of the value stored in the Keyframe.
|
||||
*/
|
||||
public Class getType() {
|
||||
return mValueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Keyframe clone();
|
||||
|
||||
/**
|
||||
* This internal subclass is used for all types which are not int or float.
|
||||
*/
|
||||
static class ObjectKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
Object mValue;
|
||||
|
||||
ObjectKeyframe(float fraction, Object value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
mValueType = mHasValue ? value.getClass() : Object.class;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectKeyframe clone() {
|
||||
ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type int.
|
||||
*/
|
||||
static class IntKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
int mValue;
|
||||
|
||||
IntKeyframe(float fraction, int value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = int.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
IntKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = int.class;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Integer.class) {
|
||||
mValue = ((Integer)value).intValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframe clone() {
|
||||
IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type float.
|
||||
*/
|
||||
static class FloatKeyframe extends Keyframe {
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
float mValue;
|
||||
|
||||
FloatKeyframe(float fraction, float value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = float.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
FloatKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = float.class;
|
||||
}
|
||||
|
||||
public float getFloatValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Float.class) {
|
||||
mValue = ((Float)value).floatValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframe clone() {
|
||||
FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
import com.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
import com.nineoldandroids.animation.Keyframe.ObjectKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*/
|
||||
class KeyframeSet {
|
||||
|
||||
int mNumKeyframes;
|
||||
|
||||
Keyframe mFirstKeyframe;
|
||||
Keyframe mLastKeyframe;
|
||||
/*Time*/Interpolator mInterpolator; // only used in the 2-keyframe case
|
||||
ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
|
||||
TypeEvaluator mEvaluator;
|
||||
|
||||
|
||||
public KeyframeSet(Keyframe... keyframes) {
|
||||
mNumKeyframes = keyframes.length;
|
||||
mKeyframes = new ArrayList<Keyframe>();
|
||||
mKeyframes.addAll(Arrays.asList(keyframes));
|
||||
mFirstKeyframe = mKeyframes.get(0);
|
||||
mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
|
||||
mInterpolator = mLastKeyframe.getInterpolator();
|
||||
}
|
||||
|
||||
public static KeyframeSet ofInt(int... values) {
|
||||
int numKeyframes = values.length;
|
||||
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
|
||||
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new IntKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofFloat(float... values) {
|
||||
int numKeyframes = values.length;
|
||||
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
|
||||
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new FloatKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
|
||||
// if all keyframes of same primitive type, create the appropriate KeyframeSet
|
||||
int numKeyframes = keyframes.length;
|
||||
boolean hasFloat = false;
|
||||
boolean hasInt = false;
|
||||
boolean hasOther = false;
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
if (keyframes[i] instanceof FloatKeyframe) {
|
||||
hasFloat = true;
|
||||
} else if (keyframes[i] instanceof IntKeyframe) {
|
||||
hasInt = true;
|
||||
} else {
|
||||
hasOther = true;
|
||||
}
|
||||
}
|
||||
if (hasFloat && !hasInt && !hasOther) {
|
||||
FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
floatKeyframes[i] = (FloatKeyframe) keyframes[i];
|
||||
}
|
||||
return new FloatKeyframeSet(floatKeyframes);
|
||||
} else if (hasInt && !hasFloat && !hasOther) {
|
||||
IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
intKeyframes[i] = (IntKeyframe) keyframes[i];
|
||||
}
|
||||
return new IntKeyframeSet(intKeyframes);
|
||||
} else {
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyframeSet ofObject(Object... values) {
|
||||
int numKeyframes = values.length;
|
||||
ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
|
||||
keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TypeEvaluator to be used when calculating animated values. This object
|
||||
* is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
|
||||
* both of which assume their own evaluator to speed up calculations with those primitive
|
||||
* types.
|
||||
*
|
||||
* @param evaluator The TypeEvaluator to be used to calculate animated values.
|
||||
*/
|
||||
public void setEvaluator(TypeEvaluator evaluator) {
|
||||
mEvaluator = evaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
Keyframe[] newKeyframes = new Keyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = keyframes.get(i).clone();
|
||||
}
|
||||
KeyframeSet newSet = new KeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animated value, given the elapsed fraction of the animation (interpolated by the
|
||||
* animation's interpolator) and the evaluator used to calculate in-between values. This
|
||||
* function maps the input fraction to the appropriate keyframe interval and a fraction
|
||||
* between them and returns the interpolated value. Note that the input fraction may fall
|
||||
* outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
|
||||
* spring interpolation that might send the fraction past 1.0). We handle this situation by
|
||||
* just using the two keyframes at the appropriate end when the value is outside those bounds.
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation
|
||||
* @return The animated value.
|
||||
*/
|
||||
public Object getValue(float fraction) {
|
||||
|
||||
// Special-case optimization for the common case of only two keyframes
|
||||
if (mNumKeyframes == 2) {
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final Keyframe nextKeyframe = mKeyframes.get(1);
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = mFirstKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
} else if (fraction >= 1f) {
|
||||
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
|
||||
final /*Time*/Interpolator interpolator = mLastKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(mLastKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
Keyframe prevKeyframe = mFirstKeyframe;
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
Keyframe nextKeyframe = mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't reach here
|
||||
return mLastKeyframe.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = " ";
|
||||
for (int i = 0; i < mNumKeyframes; ++i) {
|
||||
returnVal += mKeyframes.get(i).getValue() + " ";
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
@ -1,515 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.nineoldandroids.util.Property;
|
||||
import com.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
/**
|
||||
* This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
|
||||
* The constructors of this class take parameters to define the target object that will be animated
|
||||
* as well as the name of the property that will be animated. Appropriate set/get functions
|
||||
* are then determined internally and the animation will call these functions as necessary to
|
||||
* animate the property.
|
||||
*
|
||||
* @see #setPropertyName(String)
|
||||
*
|
||||
*/
|
||||
public final class ObjectAnimator extends ValueAnimator {
|
||||
private static final boolean DBG = false;
|
||||
private static final Map<String, Property> PROXY_PROPERTIES = new HashMap<String, Property>();
|
||||
|
||||
static {
|
||||
PROXY_PROPERTIES.put("alpha", PreHoneycombCompat.ALPHA);
|
||||
PROXY_PROPERTIES.put("pivotX", PreHoneycombCompat.PIVOT_X);
|
||||
PROXY_PROPERTIES.put("pivotY", PreHoneycombCompat.PIVOT_Y);
|
||||
PROXY_PROPERTIES.put("translationX", PreHoneycombCompat.TRANSLATION_X);
|
||||
PROXY_PROPERTIES.put("translationY", PreHoneycombCompat.TRANSLATION_Y);
|
||||
PROXY_PROPERTIES.put("rotation", PreHoneycombCompat.ROTATION);
|
||||
PROXY_PROPERTIES.put("rotationX", PreHoneycombCompat.ROTATION_X);
|
||||
PROXY_PROPERTIES.put("rotationY", PreHoneycombCompat.ROTATION_Y);
|
||||
PROXY_PROPERTIES.put("scaleX", PreHoneycombCompat.SCALE_X);
|
||||
PROXY_PROPERTIES.put("scaleY", PreHoneycombCompat.SCALE_Y);
|
||||
PROXY_PROPERTIES.put("scrollX", PreHoneycombCompat.SCROLL_X);
|
||||
PROXY_PROPERTIES.put("scrollY", PreHoneycombCompat.SCROLL_Y);
|
||||
PROXY_PROPERTIES.put("x", PreHoneycombCompat.X);
|
||||
PROXY_PROPERTIES.put("y", PreHoneycombCompat.Y);
|
||||
}
|
||||
|
||||
// The target object on which the property exists, set in the constructor
|
||||
private Object mTarget;
|
||||
|
||||
private String mPropertyName;
|
||||
|
||||
private Property mProperty;
|
||||
|
||||
/**
|
||||
* Sets the name of the property that will be animated. This name is used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*
|
||||
* <p>For best performance of the mechanism that calls the setter function determined by the
|
||||
* name of the property being animated, use <code>float</code> or <code>int</code> typed values,
|
||||
* and make the setter function for those properties have a <code>void</code> return value. This
|
||||
* will cause the code to take an optimized path for these constrained circumstances. Other
|
||||
* property types and return types will work, but will have more overhead in processing
|
||||
* the requests due to normal reflection mechanisms.</p>
|
||||
*
|
||||
* <p>Note that the setter function derived from this property name
|
||||
* must take the same parameter type as the
|
||||
* <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
|
||||
* the setter function will fail.</p>
|
||||
*
|
||||
* <p>If this ObjectAnimator has been set up to animate several properties together,
|
||||
* using more than one PropertyValuesHolder objects, then setting the propertyName simply
|
||||
* sets the propertyName in the first of those PropertyValuesHolder objects.</p>
|
||||
*
|
||||
* @param propertyName The name of the property being animated. Should not be null.
|
||||
*/
|
||||
public void setPropertyName(String propertyName) {
|
||||
// mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// propertyName to be used later when setValues() is called if so.
|
||||
if (mValues != null) {
|
||||
PropertyValuesHolder valuesHolder = mValues[0];
|
||||
String oldName = valuesHolder.getPropertyName();
|
||||
valuesHolder.setPropertyName(propertyName);
|
||||
mValuesMap.remove(oldName);
|
||||
mValuesMap.put(propertyName, valuesHolder);
|
||||
}
|
||||
mPropertyName = propertyName;
|
||||
// New property/values/target should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property that will be animated. Property objects will take precedence over
|
||||
* properties specified by the {@link #setPropertyName(String)} method. Animations should
|
||||
* be set up to use one or the other, not both.
|
||||
*
|
||||
* @param property The property being animated. Should not be null.
|
||||
*/
|
||||
public void setProperty(Property property) {
|
||||
// mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// propertyName to be used later when setValues() is called if so.
|
||||
if (mValues != null) {
|
||||
PropertyValuesHolder valuesHolder = mValues[0];
|
||||
String oldName = valuesHolder.getPropertyName();
|
||||
valuesHolder.setProperty(property);
|
||||
mValuesMap.remove(oldName);
|
||||
mValuesMap.put(mPropertyName, valuesHolder);
|
||||
}
|
||||
if (mProperty != null) {
|
||||
mPropertyName = property.getName();
|
||||
}
|
||||
mProperty = property;
|
||||
// New property/values/target should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the property that will be animated. This name will be used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return mPropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ObjectAnimator object. This default constructor is primarily for
|
||||
* use internally; the other constructors which take parameters are more generally
|
||||
* useful.
|
||||
*/
|
||||
public ObjectAnimator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and name of the
|
||||
* property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
*/
|
||||
private ObjectAnimator(Object target, String propertyName) {
|
||||
mTarget = target;
|
||||
setPropertyName(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
*/
|
||||
private <T> ObjectAnimator(T target, Property<T, ?> property) {
|
||||
mTarget = target;
|
||||
setProperty(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setIntValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
anim.setIntValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setFloatValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
|
||||
float... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
anim.setFloatValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofObject(Object target, String propertyName,
|
||||
TypeEvaluator evaluator, Object... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setObjectValues(values);
|
||||
anim.setEvaluator(evaluator);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
|
||||
TypeEvaluator<V> evaluator, V... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
anim.setObjectValues(values);
|
||||
anim.setEvaluator(evaluator);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between the sets of values specified
|
||||
* in <code>PropertyValueHolder</code> objects. This variant should be used when animating
|
||||
* several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
|
||||
* you to associate a set of animation values with a property name.
|
||||
*
|
||||
* @param target The object whose property is to be animated. Depending on how the
|
||||
* PropertyValuesObjects were constructed, the target object should either have the {@link
|
||||
* android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
|
||||
* PropertyValuesHOlder objects were created with property names) the target object should have
|
||||
* public methods on it called <code>setName()</code>, where <code>name</code> is the name of
|
||||
* the property passed in as the <code>propertyName</code> parameter for each of the
|
||||
* PropertyValuesHolder objects.
|
||||
* @param values A set of PropertyValuesHolder objects whose values will be animated between
|
||||
* over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofPropertyValuesHolder(Object target,
|
||||
PropertyValuesHolder... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator();
|
||||
anim.mTarget = target;
|
||||
anim.setValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntValues(int... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
if (mProperty != null) {
|
||||
setValues(PropertyValuesHolder.ofInt(mProperty, values));
|
||||
} else {
|
||||
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
|
||||
}
|
||||
} else {
|
||||
super.setIntValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloatValues(float... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
if (mProperty != null) {
|
||||
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
|
||||
} else {
|
||||
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
|
||||
}
|
||||
} else {
|
||||
super.setFloatValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObjectValues(Object... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
if (mProperty != null) {
|
||||
setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values));
|
||||
} else {
|
||||
setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values));
|
||||
}
|
||||
} else {
|
||||
super.setObjectValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (DBG) {
|
||||
Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
PropertyValuesHolder pvh = mValues[i];
|
||||
ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
|
||||
Log.d("ObjectAnimator", " Values[" + i + "]: " +
|
||||
pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
|
||||
keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
|
||||
}
|
||||
}
|
||||
super.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called immediately before processing the first animation
|
||||
* frame of an animation. If there is a nonzero <code>startDelay</code>, the
|
||||
* function is called after that delay ends.
|
||||
* It takes care of the final initialization steps for the
|
||||
* animation. This includes setting mEvaluator, if the user has not yet
|
||||
* set it up, and the setter/getter methods, if the user did not supply
|
||||
* them.
|
||||
*
|
||||
* <p>Overriders of this method should call the superclass method to cause
|
||||
* internal mechanisms to be set up correctly.</p>
|
||||
*/
|
||||
@Override
|
||||
void initAnimation() {
|
||||
if (!mInitialized) {
|
||||
// mValueType may change due to setter/getter setup; do this before calling super.init(),
|
||||
// which uses mValueType to set up the default type evaluator.
|
||||
if ((mProperty == null) && AnimatorProxy.NEEDS_PROXY && (mTarget instanceof View) && PROXY_PROPERTIES.containsKey(mPropertyName)) {
|
||||
setProperty(PROXY_PROPERTIES.get(mPropertyName));
|
||||
}
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupSetterAndGetter(mTarget);
|
||||
}
|
||||
super.initAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the animation. The default duration is 300 milliseconds.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
* @return ObjectAnimator The object called with setDuration(). This return
|
||||
* value makes it easier to compose statements together that construct and then set the
|
||||
* duration, as in
|
||||
* <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
|
||||
*/
|
||||
@Override
|
||||
public ObjectAnimator setDuration(long duration) {
|
||||
super.setDuration(duration);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The target object whose property will be animated by this animation
|
||||
*
|
||||
* @return The object being animated
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
@Override
|
||||
public void setTarget(Object target) {
|
||||
if (mTarget != target) {
|
||||
final Object oldTarget = mTarget;
|
||||
mTarget = target;
|
||||
if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
|
||||
return;
|
||||
}
|
||||
// New target type should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupStartValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupStartValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupEndValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupEndValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called with the elapsed fraction of the animation during every
|
||||
* animation frame. This function turns the elapsed fraction into an interpolated fraction
|
||||
* and then into an animated value (from the evaluator. The function is called mostly during
|
||||
* animation updates, but it is also called when the <code>end()</code>
|
||||
* function is called, to set the final value on the property.
|
||||
*
|
||||
* <p>Overrides of this method must call the superclass to perform the calculation
|
||||
* of the animated value.</p>
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation.
|
||||
*/
|
||||
@Override
|
||||
void animateValue(float fraction) {
|
||||
super.animateValue(fraction);
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setAnimatedValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectAnimator clone() {
|
||||
final ObjectAnimator anim = (ObjectAnimator) super.clone();
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
|
||||
mTarget;
|
||||
if (mValues != null) {
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
returnVal += "\n " + mValues[i].toString();
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
package com.nineoldandroids.animation;
|
||||
|
||||
import android.view.View;
|
||||
import com.nineoldandroids.util.FloatProperty;
|
||||
import com.nineoldandroids.util.IntProperty;
|
||||
import com.nineoldandroids.util.Property;
|
||||
import com.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
final class PreHoneycombCompat {
|
||||
static Property<View, Float> ALPHA = new FloatProperty<View>("alpha") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setAlpha(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getAlpha();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> PIVOT_X = new FloatProperty<View>("pivotX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setPivotX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getPivotX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> PIVOT_Y = new FloatProperty<View>("pivotY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setPivotY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getPivotY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setTranslationX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getTranslationX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setTranslationY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getTranslationY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> ROTATION = new FloatProperty<View>("rotation") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setRotation(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getRotation();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setRotationX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getRotationX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setRotationY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getRotationY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setScaleX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScaleX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setScaleY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScaleY();
|
||||
}
|
||||
};
|
||||
static Property<View, Integer> SCROLL_X = new IntProperty<View>("scrollX") {
|
||||
@Override
|
||||
public void setValue(View object, int value) {
|
||||
AnimatorProxy.wrap(object).setScrollX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScrollX();
|
||||
}
|
||||
};
|
||||
static Property<View, Integer> SCROLL_Y = new IntProperty<View>("scrollY") {
|
||||
@Override
|
||||
public void setValue(View object, int value) {
|
||||
AnimatorProxy.wrap(object).setScrollY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(View object) {
|
||||
return AnimatorProxy.wrap(object).getScrollY();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> X = new FloatProperty<View>("x") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setX(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getX();
|
||||
}
|
||||
};
|
||||
static Property<View, Float> Y = new FloatProperty<View>("y") {
|
||||
@Override
|
||||
public void setValue(View object, float value) {
|
||||
AnimatorProxy.wrap(object).setY(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(View object) {
|
||||
return AnimatorProxy.wrap(object).getY();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//No instances
|
||||
private PreHoneycombCompat() {}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@
|
||||
package com.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This class provides a simple callback mechanism to listeners that is synchronized with other
|
||||
* animators in the system. There is no duration, interpolation, or object value-setting
|
||||
* with this Animator. Instead, it is simply started and proceeds to send out events on every
|
||||
* animation frame to its TimeListener (if set), with information about this animator,
|
||||
* the total elapsed time, and the time since the last animation frame.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TimeAnimator extends ValueAnimator {
|
||||
|
||||
private TimeListener mListener;
|
||||
private long mPreviousTime = -1;
|
||||
|
||||
@Override
|
||||
boolean animationFrame(long currentTime) {
|
||||
if (mPlayingState == STOPPED) {
|
||||
mPlayingState = RUNNING;
|
||||
if (mSeekTime < 0) {
|
||||
mStartTime = currentTime;
|
||||
} else {
|
||||
mStartTime = currentTime - mSeekTime;
|
||||
// Now that we're playing, reset the seek time
|
||||
mSeekTime = -1;
|
||||
}
|
||||
}
|
||||
if (mListener != null) {
|
||||
long totalTime = currentTime - mStartTime;
|
||||
long deltaTime = (mPreviousTime < 0) ? 0 : (currentTime - mPreviousTime);
|
||||
mPreviousTime = currentTime;
|
||||
mListener.onTimeUpdate(this, totalTime, deltaTime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener that is sent update events throughout the life of
|
||||
* an animation.
|
||||
*
|
||||
* @param listener the listener to be set.
|
||||
*/
|
||||
public void setTimeListener(TimeListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
void animateValue(float fraction) {
|
||||
// Noop
|
||||
}
|
||||
|
||||
@Override
|
||||
void initAnimation() {
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementors of this interface can set themselves as update listeners
|
||||
* to a <code>TimeAnimator</code> instance to receive callbacks on every animation
|
||||
* frame to receive the total time since the animator started and the delta time
|
||||
* since the last frame. The first time the listener is called, totalTime and
|
||||
* deltaTime should both be zero.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static interface TimeListener {
|
||||
/**
|
||||
* <p>Notifies listeners of the occurrence of another frame of the animation,
|
||||
* along with information about the elapsed time.</p>
|
||||
*
|
||||
* @param animation The animator sending out the notification.
|
||||
* @param totalTime The
|
||||
*/
|
||||
void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime);
|
||||
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
|
||||
* allow developers to create animations on arbitrary property types, by allowing them to supply
|
||||
* custom evaulators for types that are not automatically understood and used by the animation
|
||||
* system.
|
||||
*
|
||||
* @see ValueAnimator#setEvaluator(TypeEvaluator)
|
||||
*/
|
||||
public interface TypeEvaluator<T> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value.
|
||||
* @param endValue The end value.
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public T evaluate(float fraction, T startValue, T endValue);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.util;
|
||||
|
||||
/**
|
||||
* An implementation of {@link android.util.Property} to be used specifically with fields of type
|
||||
* <code>float</code>. This type-specific subclass enables performance benefit by allowing
|
||||
* calls to a {@link #set(Object, Float) set()} function that takes the primitive
|
||||
* <code>float</code> type and avoids autoboxing and other overhead associated with the
|
||||
* <code>Float</code> class.
|
||||
*
|
||||
* @param <T> The class on which the Property is declared.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class FloatProperty<T> extends Property<T, Float> {
|
||||
|
||||
public FloatProperty(String name) {
|
||||
super(Float.class, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
|
||||
* with fields of type <code>float</code>.
|
||||
*/
|
||||
public abstract void setValue(T object, float value);
|
||||
|
||||
@Override
|
||||
final public void set(T object, Float value) {
|
||||
setValue(object, value);
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.util;
|
||||
|
||||
/**
|
||||
* An implementation of {@link android.util.Property} to be used specifically with fields of type
|
||||
* <code>int</code>. This type-specific subclass enables performance benefit by allowing
|
||||
* calls to a {@link #set(Object, Integer) set()} function that takes the primitive
|
||||
* <code>int</code> type and avoids autoboxing and other overhead associated with the
|
||||
* <code>Integer</code> class.
|
||||
*
|
||||
* @param <T> The class on which the Property is declared.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class IntProperty<T> extends Property<T, Integer> {
|
||||
|
||||
public IntProperty(String name) {
|
||||
super(Integer.class, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
|
||||
* with fields of type <code>int</code>.
|
||||
*/
|
||||
public abstract void setValue(T object, int value);
|
||||
|
||||
@Override
|
||||
final public void set(T object, Integer value) {
|
||||
set(object, value.intValue());
|
||||
}
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.util;
|
||||
|
||||
/**
|
||||
* Thrown when code requests a {@link Property} on a class that does
|
||||
* not expose the appropriate method or field.
|
||||
*
|
||||
* @see Property#of(java.lang.Class, java.lang.Class, java.lang.String)
|
||||
*/
|
||||
public class NoSuchPropertyException extends RuntimeException {
|
||||
|
||||
public NoSuchPropertyException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.util;
|
||||
|
||||
|
||||
/**
|
||||
* A property is an abstraction that can be used to represent a <emb>mutable</em> value that is held
|
||||
* in a <em>host</em> object. The Property's {@link #set(Object, Object)} or {@link #get(Object)}
|
||||
* methods can be implemented in terms of the private fields of the host object, or via "setter" and
|
||||
* "getter" methods or by some other mechanism, as appropriate.
|
||||
*
|
||||
* @param <T> The class on which the property is declared.
|
||||
* @param <V> The type that this property represents.
|
||||
*/
|
||||
public abstract class Property<T, V> {
|
||||
|
||||
private final String mName;
|
||||
private final Class<V> mType;
|
||||
|
||||
/**
|
||||
* This factory method creates and returns a Property given the <code>class</code> and
|
||||
* <code>name</code> parameters, where the <code>"name"</code> parameter represents either:
|
||||
* <ul>
|
||||
* <li>a public <code>getName()</code> method on the class which takes no arguments, plus an
|
||||
* optional public <code>setName()</code> method which takes a value of the same type
|
||||
* returned by <code>getName()</code>
|
||||
* <li>a public <code>isName()</code> method on the class which takes no arguments, plus an
|
||||
* optional public <code>setName()</code> method which takes a value of the same type
|
||||
* returned by <code>isName()</code>
|
||||
* <li>a public <code>name</code> field on the class
|
||||
* </ul>
|
||||
*
|
||||
* <p>If either of the get/is method alternatives is found on the class, but an appropriate
|
||||
* <code>setName()</code> method is not found, the <code>Property</code> will be
|
||||
* {@link #isReadOnly() readOnly}. Calling the {@link #set(Object, Object)} method on such
|
||||
* a property is allowed, but will have no effect.</p>
|
||||
*
|
||||
* <p>If neither the methods nor the field are found on the class a
|
||||
* {@link NoSuchPropertyException} exception will be thrown.</p>
|
||||
*/
|
||||
public static <T, V> Property<T, V> of(Class<T> hostType, Class<V> valueType, String name) {
|
||||
return new ReflectiveProperty<T, V>(hostType, valueType, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes an identifying name and {@link #getType() type} for the property.
|
||||
*/
|
||||
public Property(Class<V> type, String name) {
|
||||
mName = name;
|
||||
mType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@link #set(Object, Object)} method does not set the value on the target
|
||||
* object (in which case the {@link #set(Object, Object) set()} method should throw a {@link
|
||||
* NoSuchPropertyException} exception). This may happen if the Property wraps functionality that
|
||||
* allows querying the underlying value but not setting it. For example, the {@link #of(Class,
|
||||
* Class, String)} factory method may return a Property with name "foo" for an object that has
|
||||
* only a <code>getFoo()</code> or <code>isFoo()</code> method, but no matching
|
||||
* <code>setFoo()</code> method.
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value on <code>object</code> which this property represents. If the method is unable
|
||||
* to set the value on the target object it will throw an {@link UnsupportedOperationException}
|
||||
* exception.
|
||||
*/
|
||||
public void set(T object, V value) {
|
||||
throw new UnsupportedOperationException("Property " + getName() +" is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value that this property represents on the given <code>object</code>.
|
||||
*/
|
||||
public abstract V get(T object);
|
||||
|
||||
/**
|
||||
* Returns the name for this property.
|
||||
*/
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type for this property.
|
||||
*/
|
||||
public Class<V> getType() {
|
||||
return mType;
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Internal class to automatically generate a Property for a given class/name pair, given the
|
||||
* specification of {@link Property#of(java.lang.Class, java.lang.Class, java.lang.String)}
|
||||
*/
|
||||
class ReflectiveProperty<T, V> extends Property<T, V> {
|
||||
|
||||
private static final String PREFIX_GET = "get";
|
||||
private static final String PREFIX_IS = "is";
|
||||
private static final String PREFIX_SET = "set";
|
||||
private Method mSetter;
|
||||
private Method mGetter;
|
||||
private Field mField;
|
||||
|
||||
/**
|
||||
* For given property name 'name', look for getName/isName method or 'name' field.
|
||||
* Also look for setName method (optional - could be readonly). Failing method getters and
|
||||
* field results in throwing NoSuchPropertyException.
|
||||
*
|
||||
* @param propertyHolder The class on which the methods or field are found
|
||||
* @param name The name of the property, where this name is capitalized and appended to
|
||||
* "get" and "is to search for the appropriate methods. If the get/is methods are not found,
|
||||
* the constructor will search for a field with that exact name.
|
||||
*/
|
||||
public ReflectiveProperty(Class<T> propertyHolder, Class<V> valueType, String name) {
|
||||
// TODO: cache reflection info for each new class/name pair
|
||||
super(valueType, name);
|
||||
char firstLetter = Character.toUpperCase(name.charAt(0));
|
||||
String theRest = name.substring(1);
|
||||
String capitalizedName = firstLetter + theRest;
|
||||
String getterName = PREFIX_GET + capitalizedName;
|
||||
try {
|
||||
mGetter = propertyHolder.getMethod(getterName, (Class<?>[]) null);
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
/* The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||
* getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback.
|
||||
*/
|
||||
mGetter = propertyHolder.getDeclaredMethod(getterName, (Class<?>[]) null);
|
||||
mGetter.setAccessible(true);
|
||||
} catch (NoSuchMethodException e2) {
|
||||
// getName() not available - try isName() instead
|
||||
getterName = PREFIX_IS + capitalizedName;
|
||||
try {
|
||||
mGetter = propertyHolder.getMethod(getterName, (Class<?>[]) null);
|
||||
} catch (NoSuchMethodException e3) {
|
||||
try {
|
||||
/* The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||
* getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback.
|
||||
*/
|
||||
mGetter = propertyHolder.getDeclaredMethod(getterName, (Class<?>[]) null);
|
||||
mGetter.setAccessible(true);
|
||||
} catch (NoSuchMethodException e4) {
|
||||
// Try public field instead
|
||||
try {
|
||||
mField = propertyHolder.getField(name);
|
||||
Class fieldType = mField.getType();
|
||||
if (!typesMatch(valueType, fieldType)) {
|
||||
throw new NoSuchPropertyException("Underlying type (" + fieldType + ") " +
|
||||
"does not match Property type (" + valueType + ")");
|
||||
}
|
||||
return;
|
||||
} catch (NoSuchFieldException e5) {
|
||||
// no way to access property - throw appropriate exception
|
||||
throw new NoSuchPropertyException("No accessor method or field found for"
|
||||
+ " property with name " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Class getterType = mGetter.getReturnType();
|
||||
// Check to make sure our getter type matches our valueType
|
||||
if (!typesMatch(valueType, getterType)) {
|
||||
throw new NoSuchPropertyException("Underlying type (" + getterType + ") " +
|
||||
"does not match Property type (" + valueType + ")");
|
||||
}
|
||||
String setterName = PREFIX_SET + capitalizedName;
|
||||
try {
|
||||
// mSetter = propertyHolder.getMethod(setterName, getterType);
|
||||
// The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||
mSetter = propertyHolder.getDeclaredMethod(setterName, getterType);
|
||||
mSetter.setAccessible(true);
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
// Okay to not have a setter - just a readonly property
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to check whether the type of the underlying field/method on the target
|
||||
* object matches the type of the Property. The extra checks for primitive types are because
|
||||
* generics will force the Property type to be a class, whereas the type of the underlying
|
||||
* method/field will probably be a primitive type instead. Accept float as matching Float,
|
||||
* etc.
|
||||
*/
|
||||
private boolean typesMatch(Class<V> valueType, Class getterType) {
|
||||
if (getterType != valueType) {
|
||||
if (getterType.isPrimitive()) {
|
||||
return (getterType == float.class && valueType == Float.class) ||
|
||||
(getterType == int.class && valueType == Integer.class) ||
|
||||
(getterType == boolean.class && valueType == Boolean.class) ||
|
||||
(getterType == long.class && valueType == Long.class) ||
|
||||
(getterType == double.class && valueType == Double.class) ||
|
||||
(getterType == short.class && valueType == Short.class) ||
|
||||
(getterType == byte.class && valueType == Byte.class) ||
|
||||
(getterType == char.class && valueType == Character.class);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T object, V value) {
|
||||
if (mSetter != null) {
|
||||
try {
|
||||
mSetter.invoke(object, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
} else if (mField != null) {
|
||||
try {
|
||||
mField.set(object, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Property " + getName() +" is read-only");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(T object) {
|
||||
if (mGetter != null) {
|
||||
try {
|
||||
return (V) mGetter.invoke(object, (Object[])null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
} else if (mField != null) {
|
||||
try {
|
||||
return (V) mField.get(object);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
// Should not get here: there should always be a non-null getter or field
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if there is no setter or public field underlying this Property.
|
||||
*/
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return (mSetter == null && mField == null);
|
||||
}
|
||||
}
|
@ -1,292 +0,0 @@
|
||||
package com.nineoldandroids.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import static com.nineoldandroids.view.animation.AnimatorProxy.NEEDS_PROXY;
|
||||
import static com.nineoldandroids.view.animation.AnimatorProxy.wrap;
|
||||
|
||||
public final class ViewHelper {
|
||||
private ViewHelper() {}
|
||||
|
||||
public static float getAlpha(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getAlpha() : Honeycomb.getAlpha(view);
|
||||
}
|
||||
|
||||
public static void setAlpha(View view, float alpha) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setAlpha(alpha);
|
||||
} else {
|
||||
Honeycomb.setAlpha(view, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getPivotX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getPivotX() : Honeycomb.getPivotX(view);
|
||||
}
|
||||
|
||||
public static void setPivotX(View view, float pivotX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setPivotX(pivotX);
|
||||
} else {
|
||||
Honeycomb.setPivotX(view, pivotX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getPivotY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getPivotY() : Honeycomb.getPivotY(view);
|
||||
}
|
||||
|
||||
public static void setPivotY(View view, float pivotY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setPivotY(pivotY);
|
||||
} else {
|
||||
Honeycomb.setPivotY(view, pivotY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getRotation(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getRotation() : Honeycomb.getRotation(view);
|
||||
}
|
||||
|
||||
public static void setRotation(View view, float rotation) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setRotation(rotation);
|
||||
} else {
|
||||
Honeycomb.setRotation(view, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getRotationX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getRotationX() : Honeycomb.getRotationX(view);
|
||||
}
|
||||
|
||||
public static void setRotationX(View view, float rotationX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setRotationX(rotationX);
|
||||
} else {
|
||||
Honeycomb.setRotationX(view, rotationX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getRotationY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getRotationY() : Honeycomb.getRotationY(view);
|
||||
}
|
||||
|
||||
public static void setRotationY(View view, float rotationY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setRotationY(rotationY);
|
||||
} else {
|
||||
Honeycomb.setRotationY(view, rotationY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScaleX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScaleX() : Honeycomb.getScaleX(view);
|
||||
}
|
||||
|
||||
public static void setScaleX(View view, float scaleX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScaleX(scaleX);
|
||||
} else {
|
||||
Honeycomb.setScaleX(view, scaleX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScaleY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScaleY() : Honeycomb.getScaleY(view);
|
||||
}
|
||||
|
||||
public static void setScaleY(View view, float scaleY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScaleY(scaleY);
|
||||
} else {
|
||||
Honeycomb.setScaleY(view, scaleY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScrollX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScrollX() : Honeycomb.getScrollX(view);
|
||||
}
|
||||
|
||||
public static void setScrollX(View view, int scrollX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScrollX(scrollX);
|
||||
} else {
|
||||
Honeycomb.setScrollX(view, scrollX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getScrollY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getScrollY() : Honeycomb.getScrollY(view);
|
||||
}
|
||||
|
||||
public static void setScrollY(View view, int scrollY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setScrollY(scrollY);
|
||||
} else {
|
||||
Honeycomb.setScrollY(view, scrollY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getTranslationX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getTranslationX() : Honeycomb.getTranslationX(view);
|
||||
}
|
||||
|
||||
public static void setTranslationX(View view, float translationX) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setTranslationX(translationX);
|
||||
} else {
|
||||
Honeycomb.setTranslationX(view, translationX);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getTranslationY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getTranslationY() : Honeycomb.getTranslationY(view);
|
||||
}
|
||||
|
||||
public static void setTranslationY(View view, float translationY) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setTranslationY(translationY);
|
||||
} else {
|
||||
Honeycomb.setTranslationY(view, translationY);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getX(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getX() : Honeycomb.getX(view);
|
||||
}
|
||||
|
||||
public static void setX(View view, float x) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setX(x);
|
||||
} else {
|
||||
Honeycomb.setX(view, x);
|
||||
}
|
||||
}
|
||||
|
||||
public static float getY(View view) {
|
||||
return NEEDS_PROXY ? wrap(view).getY() : Honeycomb.getY(view);
|
||||
}
|
||||
|
||||
public static void setY(View view, float y) {
|
||||
if (NEEDS_PROXY) {
|
||||
wrap(view).setY(y);
|
||||
} else {
|
||||
Honeycomb.setY(view, y);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Honeycomb {
|
||||
static float getAlpha(View view) {
|
||||
return view.getAlpha();
|
||||
}
|
||||
|
||||
static void setAlpha(View view, float alpha) {
|
||||
view.setAlpha(alpha);
|
||||
}
|
||||
|
||||
static float getPivotX(View view) {
|
||||
return view.getPivotX();
|
||||
}
|
||||
|
||||
static void setPivotX(View view, float pivotX) {
|
||||
view.setPivotX(pivotX);
|
||||
}
|
||||
|
||||
static float getPivotY(View view) {
|
||||
return view.getPivotY();
|
||||
}
|
||||
|
||||
static void setPivotY(View view, float pivotY) {
|
||||
view.setPivotY(pivotY);
|
||||
}
|
||||
|
||||
static float getRotation(View view) {
|
||||
return view.getRotation();
|
||||
}
|
||||
|
||||
static void setRotation(View view, float rotation) {
|
||||
view.setRotation(rotation);
|
||||
}
|
||||
|
||||
static float getRotationX(View view) {
|
||||
return view.getRotationX();
|
||||
}
|
||||
|
||||
static void setRotationX(View view, float rotationX) {
|
||||
view.setRotationX(rotationX);
|
||||
}
|
||||
|
||||
static float getRotationY(View view) {
|
||||
return view.getRotationY();
|
||||
}
|
||||
|
||||
static void setRotationY(View view, float rotationY) {
|
||||
view.setRotationY(rotationY);
|
||||
}
|
||||
|
||||
static float getScaleX(View view) {
|
||||
return view.getScaleX();
|
||||
}
|
||||
|
||||
static void setScaleX(View view, float scaleX) {
|
||||
view.setScaleX(scaleX);
|
||||
}
|
||||
|
||||
static float getScaleY(View view) {
|
||||
return view.getScaleY();
|
||||
}
|
||||
|
||||
static void setScaleY(View view, float scaleY) {
|
||||
view.setScaleY(scaleY);
|
||||
}
|
||||
|
||||
static float getScrollX(View view) {
|
||||
return view.getScrollX();
|
||||
}
|
||||
|
||||
static void setScrollX(View view, int scrollX) {
|
||||
view.setScrollX(scrollX);
|
||||
}
|
||||
|
||||
static float getScrollY(View view) {
|
||||
return view.getScrollY();
|
||||
}
|
||||
|
||||
static void setScrollY(View view, int scrollY) {
|
||||
view.setScrollY(scrollY);
|
||||
}
|
||||
|
||||
static float getTranslationX(View view) {
|
||||
return view.getTranslationX();
|
||||
}
|
||||
|
||||
static void setTranslationX(View view, float translationX) {
|
||||
view.setTranslationX(translationX);
|
||||
}
|
||||
|
||||
static float getTranslationY(View view) {
|
||||
return view.getTranslationY();
|
||||
}
|
||||
|
||||
static void setTranslationY(View view, float translationY) {
|
||||
view.setTranslationY(translationY);
|
||||
}
|
||||
|
||||
static float getX(View view) {
|
||||
return view.getX();
|
||||
}
|
||||
|
||||
static void setX(View view, float x) {
|
||||
view.setX(x);
|
||||
}
|
||||
|
||||
static float getY(View view) {
|
||||
return view.getY();
|
||||
}
|
||||
|
||||
static void setY(View view, float y) {
|
||||
view.setY(y);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.view;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
|
||||
/**
|
||||
* This class enables automatic and optimized animation of select properties on View objects.
|
||||
* If only one or two properties on a View object are being animated, then using an
|
||||
* {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
|
||||
* are well equipped to do the right thing to set the property and invalidate the view
|
||||
* appropriately. But if several properties are animated simultaneously, or if you just want a
|
||||
* more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
|
||||
* more well-suited to the task.
|
||||
*
|
||||
* <p>This class may provide better performance for several simultaneous animations, because
|
||||
* it will optimize invalidate calls to take place only once for several properties instead of each
|
||||
* animated property independently causing its own invalidation. Also, the syntax of using this
|
||||
* class could be easier to use because the caller need only tell the View object which
|
||||
* property to animate, and the value to animate either to or by, and this class handles the
|
||||
* details of configuring the underlying Animator class and starting it.</p>
|
||||
*
|
||||
* <p>This class is not constructed by the caller, but rather by the View whose properties
|
||||
* it will animate. Calls to {@link android.view.View#animate()} will return a reference
|
||||
* to the appropriate ViewPropertyAnimator object for that View.</p>
|
||||
*
|
||||
*/
|
||||
public abstract class ViewPropertyAnimator {
|
||||
private static final WeakHashMap<View, ViewPropertyAnimator> ANIMATORS =
|
||||
new WeakHashMap<View, ViewPropertyAnimator>(0);
|
||||
|
||||
/**
|
||||
* This method returns a ViewPropertyAnimator object, which can be used to animate specific
|
||||
* properties on this View.
|
||||
*
|
||||
* @param view View to animate.
|
||||
* @return The ViewPropertyAnimator associated with this View.
|
||||
*/
|
||||
public static ViewPropertyAnimator animate(View view) {
|
||||
ViewPropertyAnimator animator = ANIMATORS.get(view);
|
||||
if (animator == null) {
|
||||
final int version = Integer.valueOf(Build.VERSION.SDK);
|
||||
if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
animator = new ViewPropertyAnimatorICS(view);
|
||||
} else if (version >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
animator = new ViewPropertyAnimatorHC(view);
|
||||
} else {
|
||||
animator = new ViewPropertyAnimatorPreHC(view);
|
||||
}
|
||||
ANIMATORS.put(view, animator);
|
||||
}
|
||||
return animator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the duration for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
* @param duration The length of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setDuration(long duration);
|
||||
|
||||
/**
|
||||
* Returns the current duration of property animations. If the duration was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @see #setDuration(long)
|
||||
* @return The duration of animations, in milliseconds.
|
||||
*/
|
||||
public abstract long getDuration();
|
||||
|
||||
/**
|
||||
* Returns the current startDelay of property animations. If the startDelay was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @see #setStartDelay(long)
|
||||
* @return The startDelay of animations, in milliseconds.
|
||||
*/
|
||||
public abstract long getStartDelay();
|
||||
|
||||
/**
|
||||
* Sets the startDelay for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
* @param startDelay The delay of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setStartDelay(long startDelay);
|
||||
|
||||
/**
|
||||
* Sets the interpolator for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default interpolator for ValueAnimator. Calling this method
|
||||
* will cause the declared object to be used instead.
|
||||
*
|
||||
* @param interpolator The TimeInterpolator to be used for ensuing property animations.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator);
|
||||
|
||||
/**
|
||||
* Sets a listener for events in the underlying Animators that run the property
|
||||
* animations.
|
||||
*
|
||||
* @param listener The listener to be called with AnimatorListener events.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator setListener(Animator.AnimatorListener listener);
|
||||
|
||||
/**
|
||||
* Starts the currently pending property animations immediately. Calling <code>start()</code>
|
||||
* is optional because all animations start automatically at the next opportunity. However,
|
||||
* if the animations are needed to start immediately and synchronously (not at the time when
|
||||
* the next event is processed by the hierarchy, which is when the animations would begin
|
||||
* otherwise), then this method can be used.
|
||||
*/
|
||||
public abstract void start();
|
||||
|
||||
/**
|
||||
* Cancels all property animations that are currently running or pending.
|
||||
*/
|
||||
public abstract void cancel();
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>x</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator x(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>x</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator xBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>y</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator y(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>y</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator yBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotation</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setRotation(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotation(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotation</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setRotation(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationX</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setRotationX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationX(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationX</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setRotationX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationXBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationY</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setRotationY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationY(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>rotationY</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setRotationY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator rotationYBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationX</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setTranslationX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationX(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationX</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setTranslationX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationXBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationY</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setTranslationY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationY(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>translationY</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setTranslationY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator translationYBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleX</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setScaleX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleX(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleX</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setScaleX(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleXBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleY</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setScaleY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleY(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>scaleY</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setScaleY(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator scaleYBy(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>alpha</code> property to be animated to the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The value to be animated to.
|
||||
* @see View#setAlpha(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator alpha(float value);
|
||||
|
||||
/**
|
||||
* This method will cause the View's <code>alpha</code> property to be animated by the
|
||||
* specified value. Animations already running on the property will be canceled.
|
||||
*
|
||||
* @param value The amount to be animated by, as an offset from the current value.
|
||||
* @see View#setAlpha(float)
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public abstract ViewPropertyAnimator alphaBy(float value);
|
||||
}
|
@ -1,723 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.view;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.ValueAnimator;
|
||||
|
||||
class ViewPropertyAnimatorHC extends ViewPropertyAnimator {
|
||||
|
||||
/**
|
||||
* A WeakReference holding the View whose properties are being animated by this class.
|
||||
* This is set at construction time.
|
||||
*/
|
||||
private final WeakReference<View> mView;
|
||||
|
||||
/**
|
||||
* The duration of the underlying Animator object. By default, we don't set the duration
|
||||
* on the Animator and just use its default duration. If the duration is ever set on this
|
||||
* Animator, then we use the duration that it was set to.
|
||||
*/
|
||||
private long mDuration;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the duration has been set on this object. If not, we don't set
|
||||
* the duration on the underlying Animator, but instead just use its default duration.
|
||||
*/
|
||||
private boolean mDurationSet = false;
|
||||
|
||||
/**
|
||||
* The startDelay of the underlying Animator object. By default, we don't set the startDelay
|
||||
* on the Animator and just use its default startDelay. If the startDelay is ever set on this
|
||||
* Animator, then we use the startDelay that it was set to.
|
||||
*/
|
||||
private long mStartDelay = 0;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the startDelay has been set on this object. If not, we don't set
|
||||
* the startDelay on the underlying Animator, but instead just use its default startDelay.
|
||||
*/
|
||||
private boolean mStartDelaySet = false;
|
||||
|
||||
/**
|
||||
* The interpolator of the underlying Animator object. By default, we don't set the interpolator
|
||||
* on the Animator and just use its default interpolator. If the interpolator is ever set on
|
||||
* this Animator, then we use the interpolator that it was set to.
|
||||
*/
|
||||
private /*Time*/Interpolator mInterpolator;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the interpolator has been set on this object. If not, we don't set
|
||||
* the interpolator on the underlying Animator, but instead just use its default interpolator.
|
||||
*/
|
||||
private boolean mInterpolatorSet = false;
|
||||
|
||||
/**
|
||||
* Listener for the lifecycle events of the underlying
|
||||
*/
|
||||
private Animator.AnimatorListener mListener = null;
|
||||
|
||||
/**
|
||||
* This listener is the mechanism by which the underlying Animator causes changes to the
|
||||
* properties currently being animated, as well as the cleanup after an animation is
|
||||
* complete.
|
||||
*/
|
||||
private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
|
||||
|
||||
/**
|
||||
* This list holds the properties that have been asked to animate. We allow the caller to
|
||||
* request several animations prior to actually starting the underlying animator. This
|
||||
* enables us to run one single animator to handle several properties in parallel. Each
|
||||
* property is tossed onto the pending list until the animation actually starts (which is
|
||||
* done by posting it onto mView), at which time the pending list is cleared and the properties
|
||||
* on that list are added to the list of properties associated with that animator.
|
||||
*/
|
||||
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
|
||||
|
||||
/**
|
||||
* Constants used to associate a property being requested and the mechanism used to set
|
||||
* the property (this class calls directly into View to set the properties in question).
|
||||
*/
|
||||
private static final int NONE = 0x0000;
|
||||
private static final int TRANSLATION_X = 0x0001;
|
||||
private static final int TRANSLATION_Y = 0x0002;
|
||||
private static final int SCALE_X = 0x0004;
|
||||
private static final int SCALE_Y = 0x0008;
|
||||
private static final int ROTATION = 0x0010;
|
||||
private static final int ROTATION_X = 0x0020;
|
||||
private static final int ROTATION_Y = 0x0040;
|
||||
private static final int X = 0x0080;
|
||||
private static final int Y = 0x0100;
|
||||
private static final int ALPHA = 0x0200;
|
||||
|
||||
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
|
||||
ROTATION | ROTATION_X | ROTATION_Y | X | Y;
|
||||
|
||||
/**
|
||||
* The mechanism by which the user can request several properties that are then animated
|
||||
* together works by posting this Runnable to start the underlying Animator. Every time
|
||||
* a property animation is requested, we cancel any previous postings of the Runnable
|
||||
* and re-post it. This means that we will only ever run the Runnable (and thus start the
|
||||
* underlying animator) after the caller is done setting the properties that should be
|
||||
* animated together.
|
||||
*/
|
||||
private Runnable mAnimationStarter = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class holds information about the overall animation being run on the set of
|
||||
* properties. The mask describes which properties are being animated and the
|
||||
* values holder is the list of all property/value objects.
|
||||
*/
|
||||
private static class PropertyBundle {
|
||||
int mPropertyMask;
|
||||
ArrayList<NameValuesHolder> mNameValuesHolder;
|
||||
|
||||
PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
|
||||
mPropertyMask = propertyMask;
|
||||
mNameValuesHolder = nameValuesHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given property from being animated as a part of this
|
||||
* PropertyBundle. If the property was a part of this bundle, it returns
|
||||
* true to indicate that it was, in fact, canceled. This is an indication
|
||||
* to the caller that a cancellation actually occurred.
|
||||
*
|
||||
* @param propertyConstant The property whose cancellation is requested.
|
||||
* @return true if the given property is a part of this bundle and if it
|
||||
* has therefore been canceled.
|
||||
*/
|
||||
boolean cancel(int propertyConstant) {
|
||||
if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
|
||||
int count = mNameValuesHolder.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
|
||||
if (nameValuesHolder.mNameConstant == propertyConstant) {
|
||||
mNameValuesHolder.remove(i);
|
||||
mPropertyMask &= ~propertyConstant;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This list tracks the list of properties being animated by any particular animator.
|
||||
* In most situations, there would only ever be one animator running at a time. But it is
|
||||
* possible to request some properties to animate together, then while those properties
|
||||
* are animating, to request some other properties to animate together. The way that
|
||||
* works is by having this map associate the group of properties being animated with the
|
||||
* animator handling the animation. On every update event for an Animator, we ask the
|
||||
* map for the associated properties and set them accordingly.
|
||||
*/
|
||||
private HashMap<Animator, PropertyBundle> mAnimatorMap =
|
||||
new HashMap<Animator, PropertyBundle>();
|
||||
|
||||
/**
|
||||
* This is the information we need to set each property during the animation.
|
||||
* mNameConstant is used to set the appropriate field in View, and the from/delta
|
||||
* values are used to calculate the animated value for a given animation fraction
|
||||
* during the animation.
|
||||
*/
|
||||
private static class NameValuesHolder {
|
||||
int mNameConstant;
|
||||
float mFromValue;
|
||||
float mDeltaValue;
|
||||
NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
|
||||
mNameConstant = nameConstant;
|
||||
mFromValue = fromValue;
|
||||
mDeltaValue = deltaValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor, called by View. This is private by design, as the user should only
|
||||
* get a ViewPropertyAnimator by calling View.animate().
|
||||
*
|
||||
* @param view The View associated with this ViewPropertyAnimator
|
||||
*/
|
||||
ViewPropertyAnimatorHC(View view) {
|
||||
mView = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
* @param duration The length of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public ViewPropertyAnimator setDuration(long duration) {
|
||||
if (duration < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
duration);
|
||||
}
|
||||
mDurationSet = true;
|
||||
mDuration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current duration of property animations. If the duration was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @see #setDuration(long)
|
||||
* @return The duration of animations, in milliseconds.
|
||||
*/
|
||||
public long getDuration() {
|
||||
if (mDurationSet) {
|
||||
return mDuration;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator, since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return new ValueAnimator().getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
if (mStartDelaySet) {
|
||||
return mStartDelay;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator (0), since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setStartDelay(long startDelay) {
|
||||
if (startDelay < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
startDelay);
|
||||
}
|
||||
mStartDelaySet = true;
|
||||
mStartDelay = startDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolatorSet = true;
|
||||
mInterpolator = interpolator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
|
||||
(HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
|
||||
Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
runningAnim.cancel();
|
||||
}
|
||||
}
|
||||
mPendingAnimations.clear();
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator x(float value) {
|
||||
animateProperty(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator xBy(float value) {
|
||||
animatePropertyBy(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator y(float value) {
|
||||
animateProperty(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator yBy(float value) {
|
||||
animatePropertyBy(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotation(float value) {
|
||||
animateProperty(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationBy(float value) {
|
||||
animatePropertyBy(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationX(float value) {
|
||||
animateProperty(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationXBy(float value) {
|
||||
animatePropertyBy(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationY(float value) {
|
||||
animateProperty(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationYBy(float value) {
|
||||
animatePropertyBy(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationX(float value) {
|
||||
animateProperty(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationXBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationY(float value) {
|
||||
animateProperty(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationYBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleX(float value) {
|
||||
animateProperty(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleXBy(float value) {
|
||||
animatePropertyBy(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleY(float value) {
|
||||
animateProperty(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleYBy(float value) {
|
||||
animatePropertyBy(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alpha(float value) {
|
||||
animateProperty(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alphaBy(float value) {
|
||||
animatePropertyBy(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the underlying Animator for a set of properties. We use a single animator that
|
||||
* simply runs from 0 to 1, and then use that fractional value to set each property
|
||||
* value accordingly.
|
||||
*/
|
||||
private void startAnimation() {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
|
||||
ArrayList<NameValuesHolder> nameValueList =
|
||||
(ArrayList<NameValuesHolder>) mPendingAnimations.clone();
|
||||
mPendingAnimations.clear();
|
||||
int propertyMask = 0;
|
||||
int propertyCount = nameValueList.size();
|
||||
for (int i = 0; i < propertyCount; ++i) {
|
||||
NameValuesHolder nameValuesHolder = nameValueList.get(i);
|
||||
propertyMask |= nameValuesHolder.mNameConstant;
|
||||
}
|
||||
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
|
||||
animator.addUpdateListener(mAnimatorEventListener);
|
||||
animator.addListener(mAnimatorEventListener);
|
||||
if (mStartDelaySet) {
|
||||
animator.setStartDelay(mStartDelay);
|
||||
}
|
||||
if (mDurationSet) {
|
||||
animator.setDuration(mDuration);
|
||||
}
|
||||
if (mInterpolatorSet) {
|
||||
animator.setInterpolator(mInterpolator);
|
||||
}
|
||||
animator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various x(), y(), etc. methods. This stores the
|
||||
* constant name for the property along with the from/delta values that will be used to
|
||||
* calculate and set the property during the animation. This structure is added to the
|
||||
* pending animations, awaiting the eventual start() of the underlying animator. A
|
||||
* Runnable is posted to start the animation, and any pending such Runnable is canceled
|
||||
* (which enables us to end up starting just one animator for all of the properties
|
||||
* specified at one time).
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param toValue The value to which the property will animate
|
||||
*/
|
||||
private void animateProperty(int constantName, float toValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
float deltaValue = toValue - fromValue;
|
||||
animatePropertyBy(constantName, fromValue, deltaValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various xBy(), yBy(), etc. methods. This method is
|
||||
* just like animateProperty(), except the value is an offset from the property's
|
||||
* current value, instead of an absolute "to" value.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float byValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
animatePropertyBy(constantName, fromValue, byValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by animateProperty() and animatePropertyBy(), which handles the
|
||||
* details of adding a pending animation and posting the request to start the animation.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param startValue The starting value of the property
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float startValue, float byValue) {
|
||||
// First, cancel any existing animations on this property
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
Animator animatorToCancel = null;
|
||||
Set<Animator> animatorSet = mAnimatorMap.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
PropertyBundle bundle = mAnimatorMap.get(runningAnim);
|
||||
if (bundle.cancel(constantName)) {
|
||||
// property was canceled - cancel the animation if it's now empty
|
||||
// Note that it's safe to break out here because every new animation
|
||||
// on a property will cancel a previous animation on that property, so
|
||||
// there can only ever be one such animation running.
|
||||
if (bundle.mPropertyMask == NONE) {
|
||||
// the animation is no longer changing anything - cancel it
|
||||
animatorToCancel = runningAnim;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animatorToCancel != null) {
|
||||
animatorToCancel.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
|
||||
mPendingAnimations.add(nameValuePair);
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
v.post(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles setting the property values directly in the View object's fields.
|
||||
* propertyConstant tells it which property should be set, value is the value to set
|
||||
* the property to.
|
||||
*
|
||||
* @param propertyConstant The property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
private void setValue(int propertyConstant, float value) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//info.mTranslationX = value;
|
||||
v.setTranslationX(value);
|
||||
break;
|
||||
case TRANSLATION_Y:
|
||||
//info.mTranslationY = value;
|
||||
v.setTranslationY(value);
|
||||
break;
|
||||
case ROTATION:
|
||||
//info.mRotation = value;
|
||||
v.setRotation(value);
|
||||
break;
|
||||
case ROTATION_X:
|
||||
//info.mRotationX = value;
|
||||
v.setRotationX(value);
|
||||
break;
|
||||
case ROTATION_Y:
|
||||
//info.mRotationY = value;
|
||||
v.setRotationY(value);
|
||||
break;
|
||||
case SCALE_X:
|
||||
//info.mScaleX = value;
|
||||
v.setScaleX(value);
|
||||
break;
|
||||
case SCALE_Y:
|
||||
//info.mScaleY = value;
|
||||
v.setScaleY(value);
|
||||
break;
|
||||
case X:
|
||||
//info.mTranslationX = value - v.mLeft;
|
||||
v.setX(value);
|
||||
break;
|
||||
case Y:
|
||||
//info.mTranslationY = value - v.mTop;
|
||||
v.setY(value);
|
||||
break;
|
||||
case ALPHA:
|
||||
//info.mAlpha = value;
|
||||
v.setAlpha(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the value of the named property from the View object.
|
||||
*
|
||||
* @param propertyConstant The property whose value should be returned
|
||||
* @return float The value of the named property
|
||||
*/
|
||||
private float getValue(int propertyConstant) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//return info.mTranslationX;
|
||||
return v.getTranslationX();
|
||||
case TRANSLATION_Y:
|
||||
//return info.mTranslationY;
|
||||
return v.getTranslationY();
|
||||
case ROTATION:
|
||||
//return info.mRotation;
|
||||
return v.getRotation();
|
||||
case ROTATION_X:
|
||||
//return info.mRotationX;
|
||||
return v.getRotationX();
|
||||
case ROTATION_Y:
|
||||
//return info.mRotationY;
|
||||
return v.getRotationY();
|
||||
case SCALE_X:
|
||||
//return info.mScaleX;
|
||||
return v.getScaleX();
|
||||
case SCALE_Y:
|
||||
//return info.mScaleY;
|
||||
return v.getScaleY();
|
||||
case X:
|
||||
//return v.mLeft + info.mTranslationX;
|
||||
return v.getX();
|
||||
case Y:
|
||||
//return v.mTop + info.mTranslationY;
|
||||
return v.getY();
|
||||
case ALPHA:
|
||||
//return info.mAlpha;
|
||||
return v.getAlpha();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that handles the various Animator events. The only ones we care
|
||||
* about are the end event (which we use to clean up the animator map when an animator
|
||||
* finishes) and the update event (which we use to calculate the current value of each
|
||||
* property and then set it on the view object).
|
||||
*/
|
||||
private class AnimatorEventListener
|
||||
implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationCancel(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationRepeat(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(animation);
|
||||
}
|
||||
mAnimatorMap.remove(animation);
|
||||
// If the map is empty, it means all animation are done or canceled, so the listener
|
||||
// isn't needed anymore. Not nulling it would cause it to leak any objects used in
|
||||
// its implementation
|
||||
if (mAnimatorMap.isEmpty()) {
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value for each property and set it on the view. Invalidate
|
||||
* the view object appropriately, depending on which properties are being animated.
|
||||
*
|
||||
* @param animation The animator associated with the properties that need to be
|
||||
* set. This animator holds the animation fraction which we will use to calculate
|
||||
* the current value of each property.
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
// alpha requires slightly different treatment than the other (transform) properties.
|
||||
// The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
|
||||
// logic is dependent on how the view handles an internal call to onSetAlpha().
|
||||
// We track what kinds of properties are set, and how alpha is handled when it is
|
||||
// set, and perform the invalidation steps appropriately.
|
||||
//boolean alphaHandled = false;
|
||||
//mView.invalidateParentCaches();
|
||||
float fraction = animation.getAnimatedFraction();
|
||||
PropertyBundle propertyBundle = mAnimatorMap.get(animation);
|
||||
int propertyMask = propertyBundle.mPropertyMask;
|
||||
if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*false*/);
|
||||
}
|
||||
}
|
||||
ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
|
||||
if (valueList != null) {
|
||||
int count = valueList.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder values = valueList.get(i);
|
||||
float value = values.mFromValue + fraction * values.mDeltaValue;
|
||||
//if (values.mNameConstant == ALPHA) {
|
||||
// alphaHandled = mView.setAlphaNoInvalidation(value);
|
||||
//} else {
|
||||
setValue(values.mNameConstant, value);
|
||||
//}
|
||||
}
|
||||
}
|
||||
/*if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
mView.mTransformationInfo.mMatrixDirty = true;
|
||||
mView.mPrivateFlags |= View.DRAWN; // force another invalidation
|
||||
}*/
|
||||
// invalidate(false) in all cases except if alphaHandled gets set to true
|
||||
// via the call to setAlphaNoInvalidation(), above
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*alphaHandled*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,298 +0,0 @@
|
||||
package com.nineoldandroids.view;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import com.nineoldandroids.animation.Animator.AnimatorListener;
|
||||
|
||||
class ViewPropertyAnimatorICS extends ViewPropertyAnimator {
|
||||
/**
|
||||
* A value to be returned when the WeakReference holding the native implementation
|
||||
* returns <code>null</code>
|
||||
*/
|
||||
private final static long RETURN_WHEN_NULL = -1L;
|
||||
|
||||
/**
|
||||
* A WeakReference holding the native implementation of ViewPropertyAnimator
|
||||
*/
|
||||
private final WeakReference<android.view.ViewPropertyAnimator> mNative;
|
||||
|
||||
ViewPropertyAnimatorICS(View view) {
|
||||
mNative = new WeakReference<android.view.ViewPropertyAnimator>(view.animate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setDuration(long duration) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.setDuration(duration);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDuration() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
return n.getDuration();
|
||||
}
|
||||
return RETURN_WHEN_NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setStartDelay(long startDelay) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.setStartDelay(startDelay);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
return n.getStartDelay();
|
||||
}
|
||||
return RETURN_WHEN_NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setInterpolator(Interpolator interpolator) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.setInterpolator(interpolator);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setListener(final AnimatorListener listener) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
if (listener == null) {
|
||||
n.setListener(null);
|
||||
} else {
|
||||
n.setListener(new android.animation.Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(android.animation.Animator animation) {
|
||||
listener.onAnimationStart(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(android.animation.Animator animation) {
|
||||
listener.onAnimationRepeat(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(android.animation.Animator animation) {
|
||||
listener.onAnimationEnd(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(android.animation.Animator animation) {
|
||||
listener.onAnimationCancel(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator x(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.x(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator xBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.xBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator y(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.y(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator yBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.yBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotation(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotation(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationX(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationX(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationXBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationXBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationY(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationY(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationYBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.rotationYBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationX(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationX(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationXBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationXBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationY(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationY(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationYBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.translationYBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleX(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleX(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleXBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleXBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleY(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleY(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleYBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.scaleYBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alpha(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.alpha(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alphaBy(float value) {
|
||||
android.view.ViewPropertyAnimator n = mNative.get();
|
||||
if (n != null) {
|
||||
n.alphaBy(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,724 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.nineoldandroids.view;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.ValueAnimator;
|
||||
import com.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
class ViewPropertyAnimatorPreHC extends ViewPropertyAnimator {
|
||||
/**
|
||||
* Proxy animation class which will allow us access to post-Honeycomb properties that were not
|
||||
* otherwise available.
|
||||
*/
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
/**
|
||||
* A WeakReference holding the View whose properties are being animated by this class. This is
|
||||
* set at construction time.
|
||||
*/
|
||||
private final WeakReference<View> mView;
|
||||
|
||||
/**
|
||||
* The duration of the underlying Animator object. By default, we don't set the duration
|
||||
* on the Animator and just use its default duration. If the duration is ever set on this
|
||||
* Animator, then we use the duration that it was set to.
|
||||
*/
|
||||
private long mDuration;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the duration has been set on this object. If not, we don't set
|
||||
* the duration on the underlying Animator, but instead just use its default duration.
|
||||
*/
|
||||
private boolean mDurationSet = false;
|
||||
|
||||
/**
|
||||
* The startDelay of the underlying Animator object. By default, we don't set the startDelay
|
||||
* on the Animator and just use its default startDelay. If the startDelay is ever set on this
|
||||
* Animator, then we use the startDelay that it was set to.
|
||||
*/
|
||||
private long mStartDelay = 0;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the startDelay has been set on this object. If not, we don't set
|
||||
* the startDelay on the underlying Animator, but instead just use its default startDelay.
|
||||
*/
|
||||
private boolean mStartDelaySet = false;
|
||||
|
||||
/**
|
||||
* The interpolator of the underlying Animator object. By default, we don't set the interpolator
|
||||
* on the Animator and just use its default interpolator. If the interpolator is ever set on
|
||||
* this Animator, then we use the interpolator that it was set to.
|
||||
*/
|
||||
private /*Time*/Interpolator mInterpolator;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the interpolator has been set on this object. If not, we don't set
|
||||
* the interpolator on the underlying Animator, but instead just use its default interpolator.
|
||||
*/
|
||||
private boolean mInterpolatorSet = false;
|
||||
|
||||
/**
|
||||
* Listener for the lifecycle events of the underlying
|
||||
*/
|
||||
private Animator.AnimatorListener mListener = null;
|
||||
|
||||
/**
|
||||
* This listener is the mechanism by which the underlying Animator causes changes to the
|
||||
* properties currently being animated, as well as the cleanup after an animation is
|
||||
* complete.
|
||||
*/
|
||||
private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
|
||||
|
||||
/**
|
||||
* This list holds the properties that have been asked to animate. We allow the caller to
|
||||
* request several animations prior to actually starting the underlying animator. This
|
||||
* enables us to run one single animator to handle several properties in parallel. Each
|
||||
* property is tossed onto the pending list until the animation actually starts (which is
|
||||
* done by posting it onto mView), at which time the pending list is cleared and the properties
|
||||
* on that list are added to the list of properties associated with that animator.
|
||||
*/
|
||||
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
|
||||
|
||||
/**
|
||||
* Constants used to associate a property being requested and the mechanism used to set
|
||||
* the property (this class calls directly into View to set the properties in question).
|
||||
*/
|
||||
private static final int NONE = 0x0000;
|
||||
private static final int TRANSLATION_X = 0x0001;
|
||||
private static final int TRANSLATION_Y = 0x0002;
|
||||
private static final int SCALE_X = 0x0004;
|
||||
private static final int SCALE_Y = 0x0008;
|
||||
private static final int ROTATION = 0x0010;
|
||||
private static final int ROTATION_X = 0x0020;
|
||||
private static final int ROTATION_Y = 0x0040;
|
||||
private static final int X = 0x0080;
|
||||
private static final int Y = 0x0100;
|
||||
private static final int ALPHA = 0x0200;
|
||||
|
||||
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
|
||||
ROTATION | ROTATION_X | ROTATION_Y | X | Y;
|
||||
|
||||
/**
|
||||
* The mechanism by which the user can request several properties that are then animated
|
||||
* together works by posting this Runnable to start the underlying Animator. Every time
|
||||
* a property animation is requested, we cancel any previous postings of the Runnable
|
||||
* and re-post it. This means that we will only ever run the Runnable (and thus start the
|
||||
* underlying animator) after the caller is done setting the properties that should be
|
||||
* animated together.
|
||||
*/
|
||||
private Runnable mAnimationStarter = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class holds information about the overall animation being run on the set of
|
||||
* properties. The mask describes which properties are being animated and the
|
||||
* values holder is the list of all property/value objects.
|
||||
*/
|
||||
private static class PropertyBundle {
|
||||
int mPropertyMask;
|
||||
ArrayList<NameValuesHolder> mNameValuesHolder;
|
||||
|
||||
PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
|
||||
mPropertyMask = propertyMask;
|
||||
mNameValuesHolder = nameValuesHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given property from being animated as a part of this
|
||||
* PropertyBundle. If the property was a part of this bundle, it returns
|
||||
* true to indicate that it was, in fact, canceled. This is an indication
|
||||
* to the caller that a cancellation actually occurred.
|
||||
*
|
||||
* @param propertyConstant The property whose cancellation is requested.
|
||||
* @return true if the given property is a part of this bundle and if it
|
||||
* has therefore been canceled.
|
||||
*/
|
||||
boolean cancel(int propertyConstant) {
|
||||
if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
|
||||
int count = mNameValuesHolder.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
|
||||
if (nameValuesHolder.mNameConstant == propertyConstant) {
|
||||
mNameValuesHolder.remove(i);
|
||||
mPropertyMask &= ~propertyConstant;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This list tracks the list of properties being animated by any particular animator.
|
||||
* In most situations, there would only ever be one animator running at a time. But it is
|
||||
* possible to request some properties to animate together, then while those properties
|
||||
* are animating, to request some other properties to animate together. The way that
|
||||
* works is by having this map associate the group of properties being animated with the
|
||||
* animator handling the animation. On every update event for an Animator, we ask the
|
||||
* map for the associated properties and set them accordingly.
|
||||
*/
|
||||
private HashMap<Animator, PropertyBundle> mAnimatorMap =
|
||||
new HashMap<Animator, PropertyBundle>();
|
||||
|
||||
/**
|
||||
* This is the information we need to set each property during the animation.
|
||||
* mNameConstant is used to set the appropriate field in View, and the from/delta
|
||||
* values are used to calculate the animated value for a given animation fraction
|
||||
* during the animation.
|
||||
*/
|
||||
private static class NameValuesHolder {
|
||||
int mNameConstant;
|
||||
float mFromValue;
|
||||
float mDeltaValue;
|
||||
NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
|
||||
mNameConstant = nameConstant;
|
||||
mFromValue = fromValue;
|
||||
mDeltaValue = deltaValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor, called by View. This is private by design, as the user should only
|
||||
* get a ViewPropertyAnimator by calling View.animate().
|
||||
*
|
||||
* @param view The View associated with this ViewPropertyAnimator
|
||||
*/
|
||||
ViewPropertyAnimatorPreHC(View view) {
|
||||
mView = new WeakReference<View>(view);
|
||||
mProxy = AnimatorProxy.wrap(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration for the underlying animator that animates the requested properties.
|
||||
* By default, the animator uses the default value for ValueAnimator. Calling this method
|
||||
* will cause the declared value to be used instead.
|
||||
* @param duration The length of ensuing property animations, in milliseconds. The value
|
||||
* cannot be negative.
|
||||
* @return This object, allowing calls to methods in this class to be chained.
|
||||
*/
|
||||
public ViewPropertyAnimator setDuration(long duration) {
|
||||
if (duration < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
duration);
|
||||
}
|
||||
mDurationSet = true;
|
||||
mDuration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current duration of property animations. If the duration was set on this
|
||||
* object, that value is returned. Otherwise, the default value of the underlying Animator
|
||||
* is returned.
|
||||
*
|
||||
* @see #setDuration(long)
|
||||
* @return The duration of animations, in milliseconds.
|
||||
*/
|
||||
public long getDuration() {
|
||||
if (mDurationSet) {
|
||||
return mDuration;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator, since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return new ValueAnimator().getDuration();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartDelay() {
|
||||
if (mStartDelaySet) {
|
||||
return mStartDelay;
|
||||
} else {
|
||||
// Just return the default from ValueAnimator (0), since that's what we'd get if
|
||||
// the value has not been set otherwise
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setStartDelay(long startDelay) {
|
||||
if (startDelay < 0) {
|
||||
throw new IllegalArgumentException("Animators cannot have negative duration: " +
|
||||
startDelay);
|
||||
}
|
||||
mStartDelaySet = true;
|
||||
mStartDelay = startDelay;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolatorSet = true;
|
||||
mInterpolator = interpolator;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
|
||||
(HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
|
||||
Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
runningAnim.cancel();
|
||||
}
|
||||
}
|
||||
mPendingAnimations.clear();
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator x(float value) {
|
||||
animateProperty(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator xBy(float value) {
|
||||
animatePropertyBy(X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator y(float value) {
|
||||
animateProperty(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator yBy(float value) {
|
||||
animatePropertyBy(Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotation(float value) {
|
||||
animateProperty(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationBy(float value) {
|
||||
animatePropertyBy(ROTATION, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationX(float value) {
|
||||
animateProperty(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationXBy(float value) {
|
||||
animatePropertyBy(ROTATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationY(float value) {
|
||||
animateProperty(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator rotationYBy(float value) {
|
||||
animatePropertyBy(ROTATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationX(float value) {
|
||||
animateProperty(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationXBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationY(float value) {
|
||||
animateProperty(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator translationYBy(float value) {
|
||||
animatePropertyBy(TRANSLATION_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleX(float value) {
|
||||
animateProperty(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleXBy(float value) {
|
||||
animatePropertyBy(SCALE_X, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleY(float value) {
|
||||
animateProperty(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator scaleYBy(float value) {
|
||||
animatePropertyBy(SCALE_Y, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alpha(float value) {
|
||||
animateProperty(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewPropertyAnimator alphaBy(float value) {
|
||||
animatePropertyBy(ALPHA, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the underlying Animator for a set of properties. We use a single animator that
|
||||
* simply runs from 0 to 1, and then use that fractional value to set each property
|
||||
* value accordingly.
|
||||
*/
|
||||
private void startAnimation() {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
|
||||
ArrayList<NameValuesHolder> nameValueList =
|
||||
(ArrayList<NameValuesHolder>) mPendingAnimations.clone();
|
||||
mPendingAnimations.clear();
|
||||
int propertyMask = 0;
|
||||
int propertyCount = nameValueList.size();
|
||||
for (int i = 0; i < propertyCount; ++i) {
|
||||
NameValuesHolder nameValuesHolder = nameValueList.get(i);
|
||||
propertyMask |= nameValuesHolder.mNameConstant;
|
||||
}
|
||||
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
|
||||
animator.addUpdateListener(mAnimatorEventListener);
|
||||
animator.addListener(mAnimatorEventListener);
|
||||
if (mStartDelaySet) {
|
||||
animator.setStartDelay(mStartDelay);
|
||||
}
|
||||
if (mDurationSet) {
|
||||
animator.setDuration(mDuration);
|
||||
}
|
||||
if (mInterpolatorSet) {
|
||||
animator.setInterpolator(mInterpolator);
|
||||
}
|
||||
animator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various x(), y(), etc. methods. This stores the
|
||||
* constant name for the property along with the from/delta values that will be used to
|
||||
* calculate and set the property during the animation. This structure is added to the
|
||||
* pending animations, awaiting the eventual start() of the underlying animator. A
|
||||
* Runnable is posted to start the animation, and any pending such Runnable is canceled
|
||||
* (which enables us to end up starting just one animator for all of the properties
|
||||
* specified at one time).
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param toValue The value to which the property will animate
|
||||
*/
|
||||
private void animateProperty(int constantName, float toValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
float deltaValue = toValue - fromValue;
|
||||
animatePropertyBy(constantName, fromValue, deltaValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by the various xBy(), yBy(), etc. methods. This method is
|
||||
* just like animateProperty(), except the value is an offset from the property's
|
||||
* current value, instead of an absolute "to" value.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float byValue) {
|
||||
float fromValue = getValue(constantName);
|
||||
animatePropertyBy(constantName, fromValue, byValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, called by animateProperty() and animatePropertyBy(), which handles the
|
||||
* details of adding a pending animation and posting the request to start the animation.
|
||||
*
|
||||
* @param constantName The specifier for the property being animated
|
||||
* @param startValue The starting value of the property
|
||||
* @param byValue The amount by which the property will change
|
||||
*/
|
||||
private void animatePropertyBy(int constantName, float startValue, float byValue) {
|
||||
// First, cancel any existing animations on this property
|
||||
if (mAnimatorMap.size() > 0) {
|
||||
Animator animatorToCancel = null;
|
||||
Set<Animator> animatorSet = mAnimatorMap.keySet();
|
||||
for (Animator runningAnim : animatorSet) {
|
||||
PropertyBundle bundle = mAnimatorMap.get(runningAnim);
|
||||
if (bundle.cancel(constantName)) {
|
||||
// property was canceled - cancel the animation if it's now empty
|
||||
// Note that it's safe to break out here because every new animation
|
||||
// on a property will cancel a previous animation on that property, so
|
||||
// there can only ever be one such animation running.
|
||||
if (bundle.mPropertyMask == NONE) {
|
||||
// the animation is no longer changing anything - cancel it
|
||||
animatorToCancel = runningAnim;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animatorToCancel != null) {
|
||||
animatorToCancel.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
|
||||
mPendingAnimations.add(nameValuePair);
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.removeCallbacks(mAnimationStarter);
|
||||
v.post(mAnimationStarter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles setting the property values directly in the View object's fields.
|
||||
* propertyConstant tells it which property should be set, value is the value to set
|
||||
* the property to.
|
||||
*
|
||||
* @param propertyConstant The property to be set
|
||||
* @param value The value to set the property to
|
||||
*/
|
||||
private void setValue(int propertyConstant, float value) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//info.mTranslationX = value;
|
||||
mProxy.setTranslationX(value);
|
||||
break;
|
||||
case TRANSLATION_Y:
|
||||
//info.mTranslationY = value;
|
||||
mProxy.setTranslationY(value);
|
||||
break;
|
||||
case ROTATION:
|
||||
//info.mRotation = value;
|
||||
mProxy.setRotation(value);
|
||||
break;
|
||||
case ROTATION_X:
|
||||
//info.mRotationX = value;
|
||||
mProxy.setRotationX(value);
|
||||
break;
|
||||
case ROTATION_Y:
|
||||
//info.mRotationY = value;
|
||||
mProxy.setRotationY(value);
|
||||
break;
|
||||
case SCALE_X:
|
||||
//info.mScaleX = value;
|
||||
mProxy.setScaleX(value);
|
||||
break;
|
||||
case SCALE_Y:
|
||||
//info.mScaleY = value;
|
||||
mProxy.setScaleY(value);
|
||||
break;
|
||||
case X:
|
||||
//info.mTranslationX = value - mView.mLeft;
|
||||
mProxy.setX(value);
|
||||
break;
|
||||
case Y:
|
||||
//info.mTranslationY = value - mView.mTop;
|
||||
mProxy.setY(value);
|
||||
break;
|
||||
case ALPHA:
|
||||
//info.mAlpha = value;
|
||||
mProxy.setAlpha(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the value of the named property from the View object.
|
||||
*
|
||||
* @param propertyConstant The property whose value should be returned
|
||||
* @return float The value of the named property
|
||||
*/
|
||||
private float getValue(int propertyConstant) {
|
||||
//final View.TransformationInfo info = mView.mTransformationInfo;
|
||||
switch (propertyConstant) {
|
||||
case TRANSLATION_X:
|
||||
//return info.mTranslationX;
|
||||
return mProxy.getTranslationX();
|
||||
case TRANSLATION_Y:
|
||||
//return info.mTranslationY;
|
||||
return mProxy.getTranslationY();
|
||||
case ROTATION:
|
||||
//return info.mRotation;
|
||||
return mProxy.getRotation();
|
||||
case ROTATION_X:
|
||||
//return info.mRotationX;
|
||||
return mProxy.getRotationX();
|
||||
case ROTATION_Y:
|
||||
//return info.mRotationY;
|
||||
return mProxy.getRotationY();
|
||||
case SCALE_X:
|
||||
//return info.mScaleX;
|
||||
return mProxy.getScaleX();
|
||||
case SCALE_Y:
|
||||
//return info.mScaleY;
|
||||
return mProxy.getScaleY();
|
||||
case X:
|
||||
//return mView.mLeft + info.mTranslationX;
|
||||
return mProxy.getX();
|
||||
case Y:
|
||||
//return mView.mTop + info.mTranslationY;
|
||||
return mProxy.getY();
|
||||
case ALPHA:
|
||||
//return info.mAlpha;
|
||||
return mProxy.getAlpha();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that handles the various Animator events. The only ones we care
|
||||
* about are the end event (which we use to clean up the animator map when an animator
|
||||
* finishes) and the update event (which we use to calculate the current value of each
|
||||
* property and then set it on the view object).
|
||||
*/
|
||||
private class AnimatorEventListener
|
||||
implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationCancel(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationRepeat(animation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(animation);
|
||||
}
|
||||
mAnimatorMap.remove(animation);
|
||||
// If the map is empty, it means all animation are done or canceled, so the listener
|
||||
// isn't needed anymore. Not nulling it would cause it to leak any objects used in
|
||||
// its implementation
|
||||
if (mAnimatorMap.isEmpty()) {
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current value for each property and set it on the view. Invalidate
|
||||
* the view object appropriately, depending on which properties are being animated.
|
||||
*
|
||||
* @param animation The animator associated with the properties that need to be
|
||||
* set. This animator holds the animation fraction which we will use to calculate
|
||||
* the current value of each property.
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
// alpha requires slightly different treatment than the other (transform) properties.
|
||||
// The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
|
||||
// logic is dependent on how the view handles an internal call to onSetAlpha().
|
||||
// We track what kinds of properties are set, and how alpha is handled when it is
|
||||
// set, and perform the invalidation steps appropriately.
|
||||
//boolean alphaHandled = false;
|
||||
//mView.invalidateParentCaches();
|
||||
float fraction = animation.getAnimatedFraction();
|
||||
PropertyBundle propertyBundle = mAnimatorMap.get(animation);
|
||||
int propertyMask = propertyBundle.mPropertyMask;
|
||||
if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*false*/);
|
||||
}
|
||||
}
|
||||
ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
|
||||
if (valueList != null) {
|
||||
int count = valueList.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
NameValuesHolder values = valueList.get(i);
|
||||
float value = values.mFromValue + fraction * values.mDeltaValue;
|
||||
//if (values.mNameConstant == ALPHA) {
|
||||
// alphaHandled = mView.setAlphaNoInvalidation(value);
|
||||
//} else {
|
||||
setValue(values.mNameConstant, value);
|
||||
//}
|
||||
}
|
||||
}
|
||||
/*if ((propertyMask & TRANSFORM_MASK) != 0) {
|
||||
mView.mTransformationInfo.mMatrixDirty = true;
|
||||
mView.mPrivateFlags |= View.DRAWN; // force another invalidation
|
||||
}*/
|
||||
// invalidate(false) in all cases except if alphaHandled gets set to true
|
||||
// via the call to setAlphaNoInvalidation(), above
|
||||
View v = mView.get();
|
||||
if (v != null) {
|
||||
v.invalidate(/*alphaHandled*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,322 +0,0 @@
|
||||
package com.nineoldandroids.view.animation;
|
||||
|
||||
import android.graphics.Camera;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* A proxy class to allow for modifying post-3.0 view properties on all pre-3.0
|
||||
* platforms. <strong>DO NOT</strong> wrap your views with this class if you
|
||||
* are using {@code ObjectAnimator} as it will handle that itself.
|
||||
*/
|
||||
public final class AnimatorProxy extends Animation {
|
||||
/** Whether or not the current running platform needs to be proxied. */
|
||||
public static final boolean NEEDS_PROXY = Integer.valueOf(Build.VERSION.SDK).intValue() < Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
|
||||
new WeakHashMap<View, AnimatorProxy>();
|
||||
|
||||
/**
|
||||
* Create a proxy to allow for modifying post-3.0 view properties on all
|
||||
* pre-3.0 platforms. <strong>DO NOT</strong> wrap your views if you are
|
||||
* using {@code ObjectAnimator} as it will handle that itself.
|
||||
*
|
||||
* @param view View to wrap.
|
||||
* @return Proxy to post-3.0 properties.
|
||||
*/
|
||||
public static AnimatorProxy wrap(View view) {
|
||||
AnimatorProxy proxy = PROXIES.get(view);
|
||||
// This checks if the proxy already exists and whether it still is the animation of the given view
|
||||
if (proxy == null || proxy != view.getAnimation()) {
|
||||
proxy = new AnimatorProxy(view);
|
||||
PROXIES.put(view, proxy);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private final WeakReference<View> mView;
|
||||
private final Camera mCamera = new Camera();
|
||||
private boolean mHasPivot;
|
||||
|
||||
private float mAlpha = 1;
|
||||
private float mPivotX;
|
||||
private float mPivotY;
|
||||
private float mRotationX;
|
||||
private float mRotationY;
|
||||
private float mRotationZ;
|
||||
private float mScaleX = 1;
|
||||
private float mScaleY = 1;
|
||||
private float mTranslationX;
|
||||
private float mTranslationY;
|
||||
|
||||
private final RectF mBefore = new RectF();
|
||||
private final RectF mAfter = new RectF();
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
|
||||
private AnimatorProxy(View view) {
|
||||
setDuration(0); //perform transformation immediately
|
||||
setFillAfter(true); //persist transformation beyond duration
|
||||
view.setAnimation(this);
|
||||
mView = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return mAlpha;
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (mAlpha != alpha) {
|
||||
mAlpha = alpha;
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
public float getPivotX() {
|
||||
return mPivotX;
|
||||
}
|
||||
public void setPivotX(float pivotX) {
|
||||
if (!mHasPivot || mPivotX != pivotX) {
|
||||
prepareForUpdate();
|
||||
mHasPivot = true;
|
||||
mPivotX = pivotX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getPivotY() {
|
||||
return mPivotY;
|
||||
}
|
||||
public void setPivotY(float pivotY) {
|
||||
if (!mHasPivot || mPivotY != pivotY) {
|
||||
prepareForUpdate();
|
||||
mHasPivot = true;
|
||||
mPivotY = pivotY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getRotation() {
|
||||
return mRotationZ;
|
||||
}
|
||||
public void setRotation(float rotation) {
|
||||
if (mRotationZ != rotation) {
|
||||
prepareForUpdate();
|
||||
mRotationZ = rotation;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getRotationX() {
|
||||
return mRotationX;
|
||||
}
|
||||
public void setRotationX(float rotationX) {
|
||||
if (mRotationX != rotationX) {
|
||||
prepareForUpdate();
|
||||
mRotationX = rotationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getRotationY() {
|
||||
return mRotationY;
|
||||
}
|
||||
|
||||
public void setRotationY(float rotationY) {
|
||||
if (mRotationY != rotationY) {
|
||||
prepareForUpdate();
|
||||
mRotationY = rotationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
public void setScaleX(float scaleX) {
|
||||
if (mScaleX != scaleX) {
|
||||
prepareForUpdate();
|
||||
mScaleX = scaleX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getScaleY() {
|
||||
return mScaleY;
|
||||
}
|
||||
public void setScaleY(float scaleY) {
|
||||
if (mScaleY != scaleY) {
|
||||
prepareForUpdate();
|
||||
mScaleY = scaleY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public int getScrollX() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollX();
|
||||
}
|
||||
public void setScrollX(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(value, view.getScrollY());
|
||||
}
|
||||
}
|
||||
public int getScrollY() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollY();
|
||||
}
|
||||
public void setScrollY(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(view.getScrollX(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public float getTranslationX() {
|
||||
return mTranslationX;
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (mTranslationX != translationX) {
|
||||
prepareForUpdate();
|
||||
mTranslationX = translationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
return mTranslationY;
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (mTranslationY != translationY) {
|
||||
prepareForUpdate();
|
||||
mTranslationY = translationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getX() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getLeft() + mTranslationX;
|
||||
}
|
||||
public void setX(float x) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
setTranslationX(x - view.getLeft());
|
||||
}
|
||||
}
|
||||
public float getY() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getTop() + mTranslationY;
|
||||
}
|
||||
public void setY(float y) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
setTranslationY(y - view.getTop());
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareForUpdate() {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
computeRect(mBefore, view);
|
||||
}
|
||||
}
|
||||
private void invalidateAfterUpdate() {
|
||||
View view = mView.get();
|
||||
if (view == null || view.getParent() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final RectF after = mAfter;
|
||||
computeRect(after, view);
|
||||
after.union(mBefore);
|
||||
|
||||
((View)view.getParent()).invalidate(
|
||||
(int) Math.floor(after.left),
|
||||
(int) Math.floor(after.top),
|
||||
(int) Math.ceil(after.right),
|
||||
(int) Math.ceil(after.bottom));
|
||||
}
|
||||
|
||||
private void computeRect(final RectF r, View view) {
|
||||
// compute current rectangle according to matrix transformation
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
// use a rectangle at 0,0 to make sure we don't run into issues with scaling
|
||||
r.set(0, 0, w, h);
|
||||
|
||||
final Matrix m = mTempMatrix;
|
||||
m.reset();
|
||||
transformMatrix(m, view);
|
||||
mTempMatrix.mapRect(r);
|
||||
|
||||
r.offset(view.getLeft(), view.getTop());
|
||||
|
||||
// Straighten coords if rotations flipped them
|
||||
if (r.right < r.left) {
|
||||
final float f = r.right;
|
||||
r.right = r.left;
|
||||
r.left = f;
|
||||
}
|
||||
if (r.bottom < r.top) {
|
||||
final float f = r.top;
|
||||
r.top = r.bottom;
|
||||
r.bottom = f;
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMatrix(Matrix m, View view) {
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
final boolean hasPivot = mHasPivot;
|
||||
final float pX = hasPivot ? mPivotX : w / 2f;
|
||||
final float pY = hasPivot ? mPivotY : h / 2f;
|
||||
|
||||
final float rX = mRotationX;
|
||||
final float rY = mRotationY;
|
||||
final float rZ = mRotationZ;
|
||||
if ((rX != 0) || (rY != 0) || (rZ != 0)) {
|
||||
final Camera camera = mCamera;
|
||||
camera.save();
|
||||
camera.rotateX(rX);
|
||||
camera.rotateY(rY);
|
||||
camera.rotateZ(-rZ);
|
||||
camera.getMatrix(m);
|
||||
camera.restore();
|
||||
m.preTranslate(-pX, -pY);
|
||||
m.postTranslate(pX, pY);
|
||||
}
|
||||
|
||||
final float sX = mScaleX;
|
||||
final float sY = mScaleY;
|
||||
if ((sX != 1.0f) || (sY != 1.0f)) {
|
||||
m.postScale(sX, sY);
|
||||
final float sPX = -(pX / w) * ((sX * w) - w);
|
||||
final float sPY = -(pY / h) * ((sY * h) - h);
|
||||
m.postTranslate(sPX, sPY);
|
||||
}
|
||||
|
||||
m.postTranslate(mTranslationX, mTranslationY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
t.setAlpha(mAlpha);
|
||||
transformMatrix(t.getMatrix(), view);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user