List of usage examples for android.animation ValueAnimator setDuration
@Override public ValueAnimator setDuration(long duration)
From source file:com.n2hsu.launcher.Page.java
public void onFlingToDelete(PointF vel) { final long startTime = AnimationUtils.currentAnimationTimeMillis(); // NOTE: Because it takes time for the first frame of animation to // actually be // called and we expect the animation to be a continuation of the fling, // we have//from ww w. j a v a 2 s .c om // to account for the time that has elapsed since the fling finished. // And since // we don't have a startDelay, we will always get call to update when we // call // start() (which we want to ignore). final TimeInterpolator tInterpolator = new TimeInterpolator() { private int mCount = -1; private long mStartTime; private float mOffset; /* Anonymous inner class ctor */ { mStartTime = startTime; } @Override public float getInterpolation(float t) { if (mCount < 0) { mCount++; } else if (mCount == 0) { mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() - mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION); mCount++; } return Math.min(1f, mOffset + t); } }; final Rect from = new Rect(); final View dragView = mDragView; from.left = (int) dragView.getTranslationX(); from.top = (int) dragView.getTranslationY(); AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel, from, startTime, FLING_TO_DELETE_FRICTION); final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView); // Create and start the animation ValueAnimator mDropAnim = new ValueAnimator(); mDropAnim.setInterpolator(tInterpolator); mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION); mDropAnim.setFloatValues(0f, 1f); mDropAnim.addUpdateListener(updateCb); mDropAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { onAnimationEndRunnable.run(); } }); mDropAnim.start(); mDeferringForDelete = true; }
From source file:com.android.launcher3.CellLayout.java
public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, int delay, boolean permanent, boolean adjustOccupied) { ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); boolean[][] occupied = mOccupied; if (!permanent) { occupied = mTmpOccupied;//from w w w .j a v a 2 s . c o m } if (clc.indexOfChild(child) != -1) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final ItemInfo info = (ItemInfo) child.getTag(); // We cancel any existing animations if (mReorderAnimators.containsKey(lp)) { mReorderAnimators.get(lp).cancel(); mReorderAnimators.remove(lp); } final int oldX = lp.x; final int oldY = lp.y; if (adjustOccupied) { occupied[lp.cellX][lp.cellY] = false; occupied[cellX][cellY] = true; } lp.isLockedToGrid = true; if (permanent) { lp.cellX = info.cellX = cellX; lp.cellY = info.cellY = cellY; } else { lp.tmpCellX = cellX; lp.tmpCellY = cellY; } clc.setupLp(lp); lp.isLockedToGrid = false; final int newX = lp.x; final int newY = lp.y; lp.x = oldX; lp.y = oldY; // Exit early if we're not actually moving the view if (oldX == newX && oldY == newY) { lp.isLockedToGrid = true; return true; } ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f); va.setDuration(duration); mReorderAnimators.put(lp, va); va.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float r = ((Float) animation.getAnimatedValue()).floatValue(); lp.x = (int) ((1 - r) * oldX + r * newX); lp.y = (int) ((1 - r) * oldY + r * newY); child.requestLayout(); } }); va.addListener(new AnimatorListenerAdapter() { boolean cancelled = false; public void onAnimationEnd(Animator animation) { // If the animation was cancelled, it means that another animation // has interrupted this one, and we don't want to lock the item into // place just yet. if (!cancelled) { lp.isLockedToGrid = true; child.requestLayout(); } if (mReorderAnimators.containsKey(lp)) { mReorderAnimators.remove(lp); } } public void onAnimationCancel(Animator animation) { cancelled = true; } }); va.setStartDelay(delay); va.start(); return true; } return false; }
From source file:com.android.leanlauncher.CellLayout.java
public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, int delay, boolean permanent, boolean adjustOccupied) { ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); boolean[][] occupied = mOccupied; if (!permanent) { occupied = mTmpOccupied;/*from w w w .ja v a 2 s . c o m*/ } if (clc.indexOfChild(child) != -1) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final ItemInfo info = (ItemInfo) child.getTag(); // We cancel any existing animations if (mReorderAnimators.containsKey(lp)) { mReorderAnimators.get(lp).cancel(); mReorderAnimators.remove(lp); } final int oldX = lp.x; final int oldY = lp.y; if (adjustOccupied) { occupied[lp.cellX][lp.cellY] = false; occupied[cellX][cellY] = true; } lp.isLockedToGrid = true; if (permanent) { lp.cellX = info.cellX = cellX; lp.cellY = info.cellY = cellY; } else { lp.tmpCellX = cellX; lp.tmpCellY = cellY; } clc.setupLp(lp); lp.isLockedToGrid = false; final int newX = lp.x; final int newY = lp.y; lp.x = oldX; lp.y = oldY; // Exit early if we're not actually moving the view if (oldX == newX && oldY == newY) { lp.isLockedToGrid = true; return true; } ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f); va.setDuration(duration); mReorderAnimators.put(lp, va); va.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float r = (Float) animation.getAnimatedValue(); lp.x = (int) ((1 - r) * oldX + r * newX); lp.y = (int) ((1 - r) * oldY + r * newY); child.requestLayout(); } }); va.addListener(new AnimatorListenerAdapter() { boolean cancelled = false; public void onAnimationEnd(Animator animation) { // If the animation was cancelled, it means that another animation // has interrupted this one, and we don't want to lock the item into // place just yet. if (!cancelled) { lp.isLockedToGrid = true; child.requestLayout(); } if (mReorderAnimators.containsKey(lp)) { mReorderAnimators.remove(lp); } } public void onAnimationCancel(Animator animation) { cancelled = true; } }); va.setStartDelay(delay); va.start(); return true; } return false; }
From source file:com.zyk.launcher.AsyncTaskCallback.java
@Override public void onClick(View v) { // When we have exited all apps or are in transition, disregard clicks if (!mLauncher.isAllAppsVisible() || mLauncher.getWorkspace().isSwitchingState() || !(v instanceof PagedViewWidget)) return;/*from www . j a v a 2s .c o m*/ // Let the user know that they have to long press to add a widget if (mWidgetInstructionToast != null) { mWidgetInstructionToast.cancel(); } mWidgetInstructionToast = Toast.makeText(getContext(), R.string.long_press_widget_to_add, Toast.LENGTH_SHORT); mWidgetInstructionToast.show(); // Create a little animation to show that the widget can move float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); tyuAnim.setDuration(125); ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); tydAnim.setDuration(100); bounce.play(tyuAnim).before(tydAnim); bounce.setInterpolator(new AccelerateInterpolator()); bounce.start(); }
From source file:cw.kop.autobackground.sources.SourceListFragment.java
private void startEditFragment(final View view, final int position) { sourceList.setOnItemClickListener(null); sourceList.setEnabled(false);/*from www .ja va 2 s . com*/ listAdapter.saveData(); Source dataItem = listAdapter.getItem(position); final SourceInfoFragment sourceInfoFragment = new SourceInfoFragment(); sourceInfoFragment.setImageDrawable(((ImageView) view.findViewById(R.id.source_image)).getDrawable()); Bundle arguments = new Bundle(); arguments.putInt("position", position); arguments.putString("type", dataItem.getType()); arguments.putString("title", dataItem.getTitle()); arguments.putString("data", dataItem.getData()); arguments.putInt("num", dataItem.getNum()); arguments.putBoolean("use", dataItem.isUse()); arguments.putBoolean("preview", dataItem.isPreview()); String imageFileName = dataItem.getImageFile().getAbsolutePath(); if (imageFileName != null && imageFileName.length() > 0) { arguments.putString("image", imageFileName); } else { arguments.putString("image", ""); } arguments.putBoolean("use_time", dataItem.isUseTime()); arguments.putString("time", dataItem.getTime()); sourceInfoFragment.setArguments(arguments); final RelativeLayout sourceContainer = (RelativeLayout) view.findViewById(R.id.source_container); final CardView sourceCard = (CardView) view.findViewById(R.id.source_card); final View imageOverlay = view.findViewById(R.id.source_image_overlay); final EditText sourceTitle = (EditText) view.findViewById(R.id.source_title); final ImageView deleteButton = (ImageView) view.findViewById(R.id.source_delete_button); final ImageView viewButton = (ImageView) view.findViewById(R.id.source_view_image_button); final ImageView editButton = (ImageView) view.findViewById(R.id.source_edit_button); final LinearLayout sourceExpandContainer = (LinearLayout) view.findViewById(R.id.source_expand_container); final float cardStartShadow = sourceCard.getPaddingLeft(); final float viewStartHeight = sourceContainer.getHeight(); final float viewStartY = view.getY(); final int viewStartPadding = view.getPaddingLeft(); final float textStartX = sourceTitle.getX(); final float textStartY = sourceTitle.getY(); final float textTranslationY = sourceTitle.getHeight(); /*+ TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());*/ Animation animation = new Animation() { private boolean needsFragment = true; @Override protected void applyTransformation(float interpolatedTime, Transformation t) { if (needsFragment && interpolatedTime >= 1) { needsFragment = false; getFragmentManager().beginTransaction() .add(R.id.content_frame, sourceInfoFragment, "source_info_fragment") .addToBackStack(null).setTransition(FragmentTransaction.TRANSIT_NONE).commit(); } int newPadding = Math.round(viewStartPadding * (1 - interpolatedTime)); int newShadowPadding = (int) (cardStartShadow * (1.0f - interpolatedTime)); sourceCard.setShadowPadding(newShadowPadding, 0, newShadowPadding, 0); ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).topMargin = newShadowPadding; ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).bottomMargin = newShadowPadding; ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).leftMargin = newShadowPadding; ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).rightMargin = newShadowPadding; view.setPadding(newPadding, 0, newPadding, 0); view.setY(viewStartY - interpolatedTime * viewStartY); ViewGroup.LayoutParams params = sourceContainer.getLayoutParams(); params.height = (int) (viewStartHeight + (screenHeight - viewStartHeight) * interpolatedTime); sourceContainer.setLayoutParams(params); sourceTitle.setY(textStartY + interpolatedTime * textTranslationY); sourceTitle.setX(textStartX + viewStartPadding - newPadding); deleteButton.setAlpha(1.0f - interpolatedTime); viewButton.setAlpha(1.0f - interpolatedTime); editButton.setAlpha(1.0f - interpolatedTime); sourceExpandContainer.setAlpha(1.0f - interpolatedTime); } @Override public boolean willChangeBounds() { return true; } }; animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (needsListReset) { Parcelable state = sourceList.onSaveInstanceState(); sourceList.setAdapter(null); sourceList.setAdapter(listAdapter); sourceList.onRestoreInstanceState(state); sourceList.setOnItemClickListener(SourceListFragment.this); sourceList.setEnabled(true); needsListReset = false; } } @Override public void onAnimationRepeat(Animation animation) { } }); ValueAnimator cardColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), AppSettings.getDialogColor(appContext), getResources().getColor(AppSettings.getBackgroundColorResource())); cardColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceContainer.setBackgroundColor((Integer) animation.getAnimatedValue()); } }); ValueAnimator titleColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), sourceTitle.getCurrentTextColor(), getResources().getColor(R.color.BLUE_OPAQUE)); titleColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceTitle.setTextColor((Integer) animation.getAnimatedValue()); } }); ValueAnimator titleShadowAlphaAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), AppSettings.getColorFilterInt(appContext), getResources().getColor(android.R.color.transparent)); titleShadowAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceTitle.setShadowLayer(4, 0, 0, (Integer) animation.getAnimatedValue()); } }); ValueAnimator imageOverlayAlphaAnimation = ValueAnimator.ofFloat(imageOverlay.getAlpha(), 0f); imageOverlayAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { imageOverlay.setAlpha((Float) animation.getAnimatedValue()); } }); int transitionTime = INFO_ANIMATION_TIME; DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f); animation.setDuration(transitionTime); cardColorAnimation.setDuration(transitionTime); titleColorAnimation.setDuration(transitionTime); titleShadowAlphaAnimation.setDuration(transitionTime); animation.setInterpolator(decelerateInterpolator); cardColorAnimation.setInterpolator(decelerateInterpolator); titleColorAnimation.setInterpolator(decelerateInterpolator); titleShadowAlphaAnimation.setInterpolator(decelerateInterpolator); if (imageOverlay.getAlpha() > 0) { imageOverlayAlphaAnimation.start(); } handler.postDelayed(new Runnable() { @Override public void run() { if (needsListReset) { Parcelable state = sourceList.onSaveInstanceState(); sourceList.setAdapter(null); sourceList.setAdapter(listAdapter); sourceList.onRestoreInstanceState(state); sourceList.setOnItemClickListener(SourceListFragment.this); sourceList.setEnabled(true); needsListReset = false; } } }, (long) (transitionTime * 1.1f)); needsListReset = true; view.startAnimation(animation); cardColorAnimation.start(); titleColorAnimation.start(); titleShadowAlphaAnimation.start(); }
From source file:com.heinrichreimersoftware.materialintro.app.IntroActivity.java
private void smoothScrollPagerTo(final int position) { if (miPager.isFakeDragging()) return;/* ww w . j av a 2 s . c o m*/ ValueAnimator animator = ValueAnimator.ofFloat(miPager.getCurrentItem(), position); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (miPager.isFakeDragging()) miPager.endFakeDrag(); miPager.setCurrentItem(position); } @Override public void onAnimationCancel(Animator animation) { if (miPager.isFakeDragging()) miPager.endFakeDrag(); } }); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float position = (Float) animation.getAnimatedValue(); fakeDragToPosition(position); } private boolean fakeDragToPosition(float position) { // The following mimics the underlying calculations in ViewPager float scrollX = miPager.getScrollX(); int pagerWidth = miPager.getWidth(); int currentPosition = miPager.getCurrentItem(); if (position > currentPosition && Math.floor(position) != currentPosition && position % 1 != 0) { miPager.setCurrentItem((int) Math.floor(position), false); } else if (position < currentPosition && Math.ceil(position) != currentPosition && position % 1 != 0) { miPager.setCurrentItem((int) Math.ceil(position), false); } if (!miPager.isFakeDragging() && !miPager.beginFakeDrag()) return false; miPager.fakeDragBy(scrollX - pagerWidth * position); return true; } }); int distance = Math.abs(position - miPager.getCurrentItem()); animator.setInterpolator(pageScrollInterpolator); animator.setDuration(calculateScrollDuration(distance)); animator.start(); }
From source file:com.android.launcher2.Launcher.java
/** * Runs a new animation that scales up icons that were added while Launcher was in the * background.//from w w w . j av a2s . c o m * * @param immediate whether to run the animation or show the results immediately */ private void runNewAppsAnimation(boolean immediate) { AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); Collection<Animator> bounceAnims = new ArrayList<Animator>(); // Order these new views spatially so that they animate in order Collections.sort(mNewShortcutAnimateViews, new Comparator<View>() { @Override public int compare(View a, View b) { CellLayout.LayoutParams alp = (CellLayout.LayoutParams) a.getLayoutParams(); CellLayout.LayoutParams blp = (CellLayout.LayoutParams) b.getLayoutParams(); int cellCountX = LauncherModel.getCellCountX(); return (alp.cellY * cellCountX + alp.cellX) - (blp.cellY * cellCountX + blp.cellX); } }); // Animate each of the views in place (or show them immediately if requested) if (immediate) { for (View v : mNewShortcutAnimateViews) { v.setAlpha(1f); v.setScaleX(1f); v.setScaleY(1f); } } else { for (int i = 0; i < mNewShortcutAnimateViews.size(); ++i) { View v = mNewShortcutAnimateViews.get(i); ValueAnimator bounceAnim = LauncherAnimUtils.ofPropertyValuesHolder(v, PropertyValuesHolder.ofFloat("alpha", 1f), PropertyValuesHolder.ofFloat("scaleX", 1f), PropertyValuesHolder.ofFloat("scaleY", 1f)); bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION); bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY); bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator()); bounceAnims.add(bounceAnim); } anim.playTogether(bounceAnims); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (mWorkspace != null) { mWorkspace.postDelayed(mBuildLayersRunnable, 500); } } }); anim.start(); } // Clean up mNewShortcutAnimatePage = -1; mNewShortcutAnimateViews.clear(); new Thread("clearNewAppsThread") { public void run() { mSharedPrefs.edit().putInt(InstallShortcutReceiver.NEW_APPS_PAGE_KEY, -1) .putStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, null).commit(); } }.start(); }
From source file:se.oort.clockify.widget.sgv.StaggeredGridView.java
/** * Performs layout animation of child views. * @throws IllegalStateException Exception is thrown of currently set animation mode is * not recognized./*from w w w.j av a2 s . c om*/ */ private void handleLayoutAnimation() throws IllegalStateException { final List<Animator> animators = new ArrayList<Animator>(); // b/8422632 - Without this dummy first animator, startDelays of subsequent animators won't // be honored correctly; all animators will block regardless of startDelay until the first // animator in the AnimatorSet truly starts playing. final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(0); animators.add(anim); addOutAnimatorsForStaleViews(animators, mAnimationOutMode); // Play the In animators at a slight delay after all Out animators have started. final int animationInStartDelay = animators.size() > 0 ? (SgvAnimationHelper.getDefaultAnimationDuration() / 2) : 0; addInAnimators(animators, mAnimationInMode, animationInStartDelay); if (animators != null && animators.size() > 0) { final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(animators); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mIsCurrentAnimationCanceled = false; mCurrentRunningAnimatorSet = animatorSet; } @Override public void onAnimationCancel(Animator animation) { mIsCurrentAnimationCanceled = true; } @Override public void onAnimationEnd(Animator animation) { if (!mIsCurrentAnimationCanceled) { // If this animation ended naturally, not because it was canceled, then // reset the animation mode back to ANIMATION_MODE_NONE. However, if // the animation was canceled by a data change, then keep the mode as is, // so that on a re-layout, we can resume animation from the views' current // positions. resetAnimationMode(); } mCurrentRunningAnimatorSet = null; } }); Log.v(LOG_TAG, "starting"); animatorSet.start(); } else { resetAnimationMode(); } mViewsToAnimateOut.clear(); mChildRectsForAnimation.clear(); }
From source file:app.umitems.greenclock.widget.sgv.StaggeredGridView.java
/** * Performs layout animation of child views. * @throws IllegalStateException Exception is thrown of currently set animation mode is * not recognized.// ww w. j a va 2s .c o m */ private void handleLayoutAnimation() throws IllegalStateException { final List<Animator> animators = new ArrayList<Animator>(); // b/8422632 - Without this dummy first animator, startDelays of subsequent animators won't // be honored correctly; all animators will block regardless of startDelay until the first // animator in the AnimatorSet truly starts playing. final ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(0); animators.add(anim); addOutAnimatorsForStaleViews(animators, mAnimationOutMode); // Play the In animators at a slight delay after all Out animators have started. final int animationInStartDelay = animators.size() > 0 ? (SgvAnimationHelper.getDefaultAnimationDuration() / 2) : 0; addInAnimators(animators, mAnimationInMode, animationInStartDelay); if (animators != null && animators.size() > 0) { final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(animators); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mIsCurrentAnimationCanceled = false; mCurrentRunningAnimatorSet = animatorSet; } @Override public void onAnimationCancel(Animator animation) { mIsCurrentAnimationCanceled = true; } @Override public void onAnimationEnd(Animator animation) { if (!mIsCurrentAnimationCanceled) { // If this animation ended naturally, not because it was canceled, then // reset the animation mode back to ANIMATION_MODE_NONE. However, if // the animation was canceled by a data change, then keep the mode as is, // so that on a re-layout, we can resume animation from the views' current // positions. resetAnimationMode(); } mCurrentRunningAnimatorSet = null; } }); Log.v(TAG, "starting"); animatorSet.start(); } else { resetAnimationMode(); } mViewsToAnimateOut.clear(); mChildRectsForAnimation.clear(); }
From source file:com.gu.swiperefresh.ProgressDrawable.java
private void setupAnimators() { final Ring ring = mRing; final ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override// ww w . ja va2 s . c o m public void onAnimationUpdate(ValueAnimator animation) { float interpolatedTime = Float.valueOf(animation.getAnimatedValue().toString()); if (mFinishing) { applyFinishTranslation(interpolatedTime, ring); } else { // The minProgressArc is calculated from 0 to create an // angle that matches the stroke width. final float minProgressArc = getMinProgressArc(ring); final float startingEndTrim = ring.getStartingEndTrim(); final float startingTrim = ring.getStartingStartTrim(); final float startingRotation = ring.getStartingRotation(); updateRingColor(interpolatedTime, ring); // Moving the start trim only occurs in the first 50% of a // single ring animation if (interpolatedTime <= START_TRIM_DURATION_OFFSET) { // scale the interpolatedTime so that the full // transformation from 0 - 1 takes place in the // remaining time final float scaledTime = (interpolatedTime) / (1.0f - START_TRIM_DURATION_OFFSET); final float startTrim = startingTrim + ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime)); ring.setStartTrim(startTrim); } // Moving the end trim starts after 50% of a single ring // animation completes if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) { // scale the interpolatedTime so that the full // transformation from 0 - 1 takes place in the // remaining time final float minArc = MAX_PROGRESS_ARC - minProgressArc; float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET) / (1.0f - START_TRIM_DURATION_OFFSET); final float endTrim = startingEndTrim + (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime)); ring.setEndTrim(endTrim); } final float rotation = startingRotation + (0.25f * interpolatedTime); ring.setRotation(rotation); float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime) + (FULL_ROTATION * (mRotationCount / NUM_POINTS)); setRotation(groupRotation); } } }); animator.setRepeatCount(Animation.INFINITE); animator.setRepeatMode(ValueAnimator.RESTART); animator.setInterpolator(LINEAR_INTERPOLATOR); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationStart(Animator animation) { mRotationCount = 0; } @Override public void onAnimationRepeat(Animator animation) { ring.storeOriginals(); ring.goToNextColor(); ring.setStartTrim(ring.getEndTrim()); if (mFinishing) { // finished closing the last ring from the swipe gesture; go // into progress mode mFinishing = false; animation.setDuration(ANIMATION_DURATION); ring.setShowArrow(false); } else { mRotationCount = (mRotationCount + 1) % (NUM_POINTS); } } }); mAnimation = animator; }