List of usage examples for android.animation ObjectAnimator ofFloat
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty, Property<T, Float> yProperty, Path path)
Path
using two properties. From source file:com.berniesanders.fieldthebern.MainActivity.java
void animateBg(boolean show) { backgroundImage.setVisibility(View.VISIBLE); float toAlpha = show ? 1 : 0; ObjectAnimator.ofFloat(backgroundImage, "alpha", backgroundImage.getAlpha(), toAlpha).setDuration(100) .start();/* ww w .ja v a2s .com*/ }
From source file:com.modprobe.profit.ExpandingListView.java
/** * This method expands the view that was clicked and animates all the views * around it to make room for the expanding view. There are several steps required * to do this which are outlined below.//from ww w.java2 s . c o m * * 1. Store the current top and bottom bounds of each visible item in the listview. * 2. Update the layout parameters of the selected view. In the context of this * method, the view should be originally collapsed and set to some custom height. * The layout parameters are updated so as to wrap the content of the additional * text that is to be displayed. * * After invoking a layout to take place, the listview will order all the items * such that there is space for each view. This layout will be independent of what * the bounds of the items were prior to the layout so two pre-draw passes will * be made. This is necessary because after the layout takes place, some views that * were visible before the layout may now be off bounds but a reference to these * views is required so the animation completes as intended. * * 3. The first predraw pass will set the bounds of all the visible items to * their original location before the layout took place and then force another * layout. Since the bounds of the cells cannot be set directly, the method * setSelectionFromTop can be used to achieve a very similar effect. * 4. The expanding view's bounds are animated to what the final values should be * from the original bounds. * 5. The bounds above the expanding view are animated upwards while the bounds * below the expanding view are animated downwards. * 6. The extra text is faded in as its contents become visible throughout the * animation process. * * It is important to note that the listview is disabled during the animation * because the scrolling behaviour is unpredictable if the bounds of the items * within the listview are not constant during the scroll. */ private void expandView(final View view) { final SuggestionExpandingListViewItem viewObject = (SuggestionExpandingListViewItem) getItemAtPosition( getPositionForView(view)); /* Store the original top and bottom bounds of all the cells.*/ final int oldTop = view.getTop(); final int oldBottom = view.getBottom(); final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View v = getChildAt(i); ViewCompat.setHasTransientState(v, true); oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() }); } /* Update the layout so the extra content becomes visible.*/ final View expandingLayout = view.findViewById(R.id.expanding_layout); expandingLayout.setVisibility(View.VISIBLE); /* Add an onPreDraw Listener to the listview. onPreDraw will get invoked after onLayout * and onMeasure have run but before anything has been drawn. This * means that the final post layout properties for all the items have already been * determined, but still have not been rendered onto the screen.*/ final ViewTreeObserver observer = getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { /* Determine if this is the first or second pass.*/ if (!mShouldRemoveObserver) { mShouldRemoveObserver = true; /* Calculate what the parameters should be for setSelectionFromTop. * The ListView must be offset in a way, such that after the animation * takes place, all the cells that remain visible are rendered completely * by the ListView.*/ int newTop = view.getTop(); int newBottom = view.getBottom(); int newHeight = newBottom - newTop; int oldHeight = oldBottom - oldTop; int delta = newHeight - oldHeight; mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, delta, true); int currentTop = view.getTop(); int futureTop = oldTop - mTranslate[0]; int firstChildStartTop = getChildAt(0).getTop(); int firstVisiblePosition = getFirstVisiblePosition(); int deltaTop = currentTop - futureTop; int i; int childCount = getChildCount(); for (i = 0; i < childCount; i++) { View v = getChildAt(i); int height = v.getBottom() - Math.max(0, v.getTop()); if (deltaTop - height > 0) { firstVisiblePosition++; deltaTop -= height; } else { break; } } if (i > 0) { firstChildStartTop = 0; } setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop); /* Request another layout to update the layout parameters of the cells.*/ requestLayout(); /* Return false such that the ListView does not redraw its contents on * this layout but only updates all the parameters associated with its * children.*/ return false; } /* Remove the predraw listener so this method does not keep getting called. */ mShouldRemoveObserver = false; observer.removeOnPreDrawListener(this); int yTranslateTop = mTranslate[0]; int yTranslateBottom = mTranslate[1]; ArrayList<Animator> animations = new ArrayList<Animator>(); int index = indexOfChild(view); /* Loop through all the views that were on the screen before the cell was * expanded. Some cells will still be children of the ListView while * others will not. The cells that remain children of the ListView * simply have their bounds animated appropriately. The cells that are no * longer children of the ListView also have their bounds animated, but * must also be added to a list of views which will be drawn in dispatchDraw.*/ for (View v : oldCoordinates.keySet()) { int[] old = oldCoordinates.get(v); v.setTop(old[0]); v.setBottom(old[1]); if (v.getParent() == null) { mViewsToDraw.add(v); int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom; animations.add(getAnimation(v, delta, delta)); } else { int i = indexOfChild(v); if (v != view) { int delta = i > index ? yTranslateBottom : -yTranslateTop; animations.add(getAnimation(v, delta, delta)); } ViewCompat.setHasTransientState(v, false); } } /* Adds animation for expanding the cell that was clicked. */ animations.add(getAnimation(view, -yTranslateTop, yTranslateBottom)); /* Adds an animation for fading in the extra content. */ animations.add(ObjectAnimator.ofFloat(view.findViewById(R.id.expanding_layout), View.ALPHA, 0, 1)); /* Disabled the ListView for the duration of the animation.*/ setEnabled(false); setClickable(false); /* Play all the animations created above together at the same time. */ AnimatorSet s = new AnimatorSet(); s.playTogether(animations); s.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { viewObject.setExpanded(true); setEnabled(true); setClickable(true); if (mViewsToDraw.size() > 0) { for (View v : mViewsToDraw) { ViewCompat.setHasTransientState(v, false); } } mViewsToDraw.clear(); } }); s.start(); return true; } }); }
From source file:io.github.douglasjunior.androidSimpleTooltip.SimpleTooltip.java
@TargetApi(Build.VERSION_CODES.HONEYCOMB) private synchronized void startFloatingAnimation() { final String property = mGravity == Gravity.TOP || mGravity == Gravity.BOTTOM ? "translationY" : "translationX"; final ObjectAnimator anim1 = ObjectAnimator.ofFloat(mContentLayout, property, -mAnimationPadding, mAnimationPadding);/* w ww .jav a 2s . c om*/ anim1.setDuration(mAnimationDuration); anim1.setInterpolator(new AccelerateDecelerateInterpolator()); final ObjectAnimator anim2 = ObjectAnimator.ofFloat(mContentLayout, property, mAnimationPadding, -mAnimationPadding); anim2.setDuration(mAnimationDuration); anim2.setInterpolator(new AccelerateDecelerateInterpolator()); AnimatorSet set = new AnimatorSet(); set.playSequentially(anim1, anim2); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (isShowing()) { animation.start(); } } }); mAnimator = set; mAnimator.start(); }
From source file:com.gudong.appkit.ui.fragment.AppListFragment.java
@Override public void onClickListItemIcon(View iconView, AppEntity entity) { ObjectAnimator animatorRotation = ObjectAnimator.ofFloat(iconView, "rotation", 0, 360); ObjectAnimator scaleRotationX = ObjectAnimator.ofFloat(iconView, "scaleX", 0, 1F); ObjectAnimator scaleRotationY = ObjectAnimator.ofFloat(iconView, "scaleY", 0, 1F); AnimatorSet animationSet = new AnimatorSet(); animationSet.playTogether(animatorRotation, scaleRotationY, scaleRotationX); animationSet.setDuration(500);//from w w w. j av a 2 s . c o m animationSet.start(); }
From source file:com.shoshin.paidpay.ExpandingListView.java
/** * This method expands the view that was clicked and animates all the views * around it to make room for the expanding view. There are several steps required * to do this which are outlined below./*from w w w.j a v a2 s . com*/ * * 1. Store the current top and bottom bounds of each visible item in the listview. * 2. Update the layout parameters of the selected view. In the context of this * method, the view should be originally collapsed and set to some custom height. * The layout parameters are updated so as to wrap the content of the additional * text that is to be displayed. * * After invoking a layout to take place, the listview will order all the items * such that there is space for each view. This layout will be independent of what * the bounds of the items were prior to the layout so two pre-draw passes will * be made. This is necessary because after the layout takes place, some views that * were visible before the layout may now be off bounds but a reference to these * views is required so the animation completes as intended. * * 3. The first predraw pass will set the bounds of all the visible items to * their original location before the layout took place and then force another * layout. Since the bounds of the cells cannot be set directly, the method * setSelectionFromTop can be used to achieve a very similar effect. * 4. The expanding view's bounds are animated to what the final values should be * from the original bounds. * 5. The bounds above the expanding view are animated upwards while the bounds * below the expanding view are animated downwards. * 6. The extra text is faded in as its contents become visible throughout the * animation process. * * It is important to note that the listview is disabled during the animation * because the scrolling behaviour is unpredictable if the bounds of the items * within the listview are not constant during the scroll. */ private void expandView(final View view) { final ExpandableListItem viewObject = (ExpandableListItem) getItemAtPosition(getPositionForView(view)); /* Store the original top and bottom bounds of all the cells.*/ final int oldTop = view.getTop(); final int oldBottom = view.getBottom(); final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View v = getChildAt(i); ViewCompat.setHasTransientState(v, true); oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() }); } /* Update the layout so the extra content becomes visible.*/ final View expandingLayout = view.findViewById(R.id.expanding_layout); expandingLayout.setVisibility(View.VISIBLE); /* Add an onPreDraw Listener to the listview. onPreDraw will get invoked after onLayout * and onMeasure have run but before anything has been drawn. This * means that the final post layout properties for all the items have already been * determined, but still have not been rendered onto the screen.*/ final ViewTreeObserver observer = getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { /* Determine if this is the first or second pass.*/ if (!mShouldRemoveObserver) { mShouldRemoveObserver = true; /* Calculate what the parameters should be for setSelectionFromTop. * The ListView must be offset in a way, such that after the animation * takes place, all the cells that remain visible are rendered completely * by the ListView.*/ int newTop = view.getTop(); int newBottom = view.getBottom(); int newHeight = newBottom - newTop; int oldHeight = oldBottom - oldTop; int delta = newHeight - oldHeight; mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, delta, true); int currentTop = view.getTop(); int futureTop = oldTop - mTranslate[0]; int firstChildStartTop = getChildAt(0).getTop(); int firstVisiblePosition = getFirstVisiblePosition(); int deltaTop = currentTop - futureTop; int i; int childCount = getChildCount(); for (i = 0; i < childCount; i++) { View v = getChildAt(i); int height = v.getBottom() - Math.max(0, v.getTop()); if (deltaTop - height > 0) { firstVisiblePosition++; deltaTop -= height; } else { break; } } if (i > 0) { firstChildStartTop = 0; } setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop); /* Request another layout to update the layout parameters of the cells.*/ requestLayout(); /* Return false such that the ListView does not redraw its contents on * this layout but only updates all the parameters associated with its * children.*/ return false; } /* Remove the predraw listener so this method does not keep getting called. */ mShouldRemoveObserver = false; observer.removeOnPreDrawListener(this); int yTranslateTop = mTranslate[0]; int yTranslateBottom = mTranslate[1]; ArrayList<Animator> animations = new ArrayList<Animator>(); int index = indexOfChild(view); /* Loop through all the views that were on the screen before the cell was * expanded. Some cells will still be children of the ListView while * others will not. The cells that remain children of the ListView * simply have their bounds animated appropriately. The cells that are no * longer children of the ListView also have their bounds animated, but * must also be added to a list of views which will be drawn in dispatchDraw.*/ for (View v : oldCoordinates.keySet()) { int[] old = oldCoordinates.get(v); v.setTop(old[0]); v.setBottom(old[1]); if (v.getParent() == null) { mViewsToDraw.add(v); int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom; animations.add(getAnimation(v, delta, delta)); } else { int i = indexOfChild(v); if (v != view) { int delta = i > index ? yTranslateBottom : -yTranslateTop; animations.add(getAnimation(v, delta, delta)); } ViewCompat.setHasTransientState(v, false); } } /* Adds animation for expanding the cell that was clicked. */ animations.add(getAnimation(view, -yTranslateTop, yTranslateBottom)); /* Adds an animation for fading in the extra content. */ //TODO animations.add(ObjectAnimator.ofFloat(view.findViewById(R.id.expanding_layout), View.ALPHA, 0, 1)); /* Disabled the ListView for the duration of the animation.*/ setEnabled(false); setClickable(false); /* Play all the animations created above together at the same time. */ AnimatorSet s = new AnimatorSet(); s.playTogether(animations); s.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { viewObject.setExpanded(true); setEnabled(true); setClickable(true); if (mViewsToDraw.size() > 0) { for (View v : mViewsToDraw) { ViewCompat.setHasTransientState(v, false); } } mViewsToDraw.clear(); } }); s.start(); return true; } }); }
From source file:com.grepsound.activities.MainActivity.java
/** * This method animates the image fragment into the foreground by both * scaling and rotating the fragment's view, while also removing the * previously added translucent dark hover view. Upon the completion of * this animation, the image fragment regains focus since this method is * called from the onBackStackChanged method. *//*from w ww . java2 s.c om*/ public void slideForward(Animator.AnimatorListener listener) { View movingFragmentView = mMainFrag.getView(); PropertyValuesHolder rotateX = PropertyValuesHolder.ofFloat("rotationX", 40f); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f); ObjectAnimator movingFragmentAnimator = ObjectAnimator.ofPropertyValuesHolder(movingFragmentView, rotateX, scaleX, scaleY); ObjectAnimator darkHoverViewAnimator = ObjectAnimator.ofFloat(mDarkHoverView, "alpha", 0.5f, 0.0f); ObjectAnimator movingFragmentRotator = ObjectAnimator.ofFloat(movingFragmentView, "rotationX", 0); movingFragmentRotator.setStartDelay(getResources().getInteger(R.integer.half_slide_up_down_duration)); AnimatorSet s = new AnimatorSet(); s.playTogether(movingFragmentAnimator, movingFragmentRotator, darkHoverViewAnimator); s.setStartDelay(getResources().getInteger(R.integer.slide_up_down_duration)); s.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mIsAnimating = false; } }); s.start(); }
From source file:com.shoshin.paidpay.ExpandingListViewPayVia.java
/** * This method expands the view that was clicked and animates all the views * around it to make room for the expanding view. There are several steps required * to do this which are outlined below.//from ww w .jav a 2 s . c o m * * 1. Store the current top and bottom bounds of each visible item in the listview. * 2. Update the layout parameters of the selected view. In the context of this * method, the view should be originally collapsed and set to some custom height. * The layout parameters are updated so as to wrap the content of the additional * text that is to be displayed. * * After invoking a layout to take place, the listview will order all the items * such that there is space for each view. This layout will be independent of what * the bounds of the items were prior to the layout so two pre-draw passes will * be made. This is necessary because after the layout takes place, some views that * were visible before the layout may now be off bounds but a reference to these * views is required so the animation completes as intended. * * 3. The first predraw pass will set the bounds of all the visible items to * their original location before the layout took place and then force another * layout. Since the bounds of the cells cannot be set directly, the method * setSelectionFromTop can be used to achieve a very similar effect. * 4. The expanding view's bounds are animated to what the final values should be * from the original bounds. * 5. The bounds above the expanding view are animated upwards while the bounds * below the expanding view are animated downwards. * 6. The extra text is faded in as its contents become visible throughout the * animation process. * * It is important to note that the listview is disabled during the animation * because the scrolling behaviour is unpredictable if the bounds of the items * within the listview are not constant during the scroll. */ private void expandView(final View view) { final ExpandableCardsWithOffers viewObject = (ExpandableCardsWithOffers) getItemAtPosition( getPositionForView(view)); /* Store the original top and bottom bounds of all the cells.*/ final int oldTop = view.getTop(); final int oldBottom = view.getBottom(); final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View v = getChildAt(i); ViewCompat.setHasTransientState(v, true); oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() }); } /* Update the layout so the extra content becomes visible.*/ final View expandingLayout = view.findViewById(R.id.expanding_layout); expandingLayout.setVisibility(View.VISIBLE); /* Add an onPreDraw Listener to the listview. onPreDraw will get invoked after onLayout * and onMeasure have run but before anything has been drawn. This * means that the final post layout properties for all the items have already been * determined, but still have not been rendered onto the screen.*/ final ViewTreeObserver observer = getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { /* Determine if this is the first or second pass.*/ if (!mShouldRemoveObserver) { mShouldRemoveObserver = true; /* Calculate what the parameters should be for setSelectionFromTop. * The ListView must be offset in a way, such that after the animation * takes place, all the cells that remain visible are rendered completely * by the ListView.*/ int newTop = view.getTop(); int newBottom = view.getBottom(); int newHeight = newBottom - newTop; int oldHeight = oldBottom - oldTop; int delta = newHeight - oldHeight; mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, delta, true); int currentTop = view.getTop(); int futureTop = oldTop - mTranslate[0]; int firstChildStartTop = getChildAt(0).getTop(); int firstVisiblePosition = getFirstVisiblePosition(); int deltaTop = currentTop - futureTop; int i; int childCount = getChildCount(); for (i = 0; i < childCount; i++) { View v = getChildAt(i); int height = v.getBottom() - Math.max(0, v.getTop()); if (deltaTop - height > 0) { firstVisiblePosition++; deltaTop -= height; } else { break; } } if (i > 0) { firstChildStartTop = 0; } setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop); /* Request another layout to update the layout parameters of the cells.*/ requestLayout(); /* Return false such that the ListView does not redraw its contents on * this layout but only updates all the parameters associated with its * children.*/ return false; } /* Remove the predraw listener so this method does not keep getting called. */ mShouldRemoveObserver = false; observer.removeOnPreDrawListener(this); int yTranslateTop = mTranslate[0]; int yTranslateBottom = mTranslate[1]; ArrayList<Animator> animations = new ArrayList<Animator>(); int index = indexOfChild(view); /* Loop through all the views that were on the screen before the cell was * expanded. Some cells will still be children of the ListView while * others will not. The cells that remain children of the ListView * simply have their bounds animated appropriately. The cells that are no * longer children of the ListView also have their bounds animated, but * must also be added to a list of views which will be drawn in dispatchDraw.*/ for (View v : oldCoordinates.keySet()) { int[] old = oldCoordinates.get(v); v.setTop(old[0]); v.setBottom(old[1]); if (v.getParent() == null) { mViewsToDraw.add(v); int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom; animations.add(getAnimation(v, delta, delta)); } else { int i = indexOfChild(v); if (v != view) { int delta = i > index ? yTranslateBottom : -yTranslateTop; animations.add(getAnimation(v, delta, delta)); } ViewCompat.setHasTransientState(v, false); } } /* Adds animation for expanding the cell that was clicked. */ animations.add(getAnimation(view, -yTranslateTop, yTranslateBottom)); /* Adds an animation for fading in the extra content. */ //TODO animations.add(ObjectAnimator.ofFloat(view.findViewById(R.id.expanding_layout), View.ALPHA, 0, 1)); /* Disabled the ListView for the duration of the animation.*/ setEnabled(false); setClickable(false); /* Play all the animations created above together at the same time. */ AnimatorSet s = new AnimatorSet(); s.playTogether(animations); s.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { viewObject.setExpanded(true); setEnabled(true); setClickable(true); if (mViewsToDraw.size() > 0) { for (View v : mViewsToDraw) { ViewCompat.setHasTransientState(v, false); } } mViewsToDraw.clear(); } }); s.start(); return true; } }); }
From source file:com.rks.musicx.misc.utils.Helper.java
/** * Animate View/* w w w. ja v a2 s.c om*/ * * @param view * @return */ public static Animator[] getAnimator(View view) { return new Animator[] { ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0) }; }
From source file:eu.davidea.flexibleadapter.FlexibleAnimatorAdapter.java
/** * This is the default animator.<br/> * Alpha animator will be always automatically added. * <p><b>Note:</b> Only 1 animator of the same compatible type can be added.<br/> * Incompatible with ALPHA animator.</p> * * @param animators user defined list/*from w ww . j a va 2s .com*/ * @param view itemView to animate * @param alphaFrom starting alpha value */ private void addAlphaAnimator(@NonNull List<Animator> animators, @NonNull View view, @FloatRange(from = 0.0, to = 1.0) float alphaFrom) { if (animatorsUsed.contains(AnimatorEnum.ALPHA)) return; animators.add(ObjectAnimator.ofFloat(view, "alpha", alphaFrom, 1f)); animatorsUsed.add(AnimatorEnum.ALPHA); }
From source file:com.fada21.android.hydralist.expandable.ExpandingListViewDelegate.java
/** * <p>//from w w w. ja v a 2s . com * This method expands the view that was clicked and animates all the views around it to make room for the expanding view. There are several steps required * to do this which are outlined below. * </p> * * <li>Store the current top and bottom bounds of each visible item in the listview.</li> <li>Update the layout parameters of the selected view. In the * context of this method, the view should be originally collapsed and set to some custom height. The layout parameters are updated so as to wrap the * content of the additional text that is to be displayed.</li> * * <br/> * <br/> * <p> * After invoking a layout to take place, the listview will order all the items such that there is space for each view. This layout will be independent of * what the bounds of the items were prior to the layout so two pre-draw passes will be made. This is necessary because after the layout takes place, some * views that were visible before the layout may now be off bounds but a reference to these views is required so the animation completes as intended. * </p> * <br/> * * <li>The first predraw pass will set the bounds of all the visible items to their original location before the layout took place and then force another * layout. Since the bounds of the cells cannot be set directly, the method setSelectionFromTop can be used to achieve a very similar effect.</li> <li>The * expanding view's bounds are animated to what the final values should be from the original bounds.</li> <li>The bounds above the expanding view are * animated upwards while the bounds below the expanding view are animated downwards.</li> <li>The extra text is faded in as its contents become visible * throughout the animation process.</li> * * <br/> * <br/> * <p> * It is important to note that the listview is disabled during the animation because the scrolling behavior is unpredictable if the bounds of the items * within the listview are not constant during the scroll. * </p> * <br/> * * @param view * expanding view * @param position * item position in list * @param id * item id */ private void expandView(final View view, int position, long id) { // final ExpandableListItem item = (ExpandableListItem) nlv.getItemAtPosition(nlv.getPositionForView(view)); HydraListAdapter<ExpandableListItem> expandingAdapter = getExpandingAdapter(); final ExpandableListItem item = expandingAdapter.getDataProvider().get(position); ExpandingLayout expandingLayout = expandingAdapter.getExpandingHelper().getExpandedView(view, item); /* Store the original top and bottom bounds of all the cells. */ final int oldTop = view.getTop(); final int oldBottom = view.getBottom(); final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>(); int childCount = nlv.getChildCount(); for (int i = 0; i < childCount; i++) { View v = nlv.getChildAt(i); ViewCompat.setHasTransientState(v, true); oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() }); } /* Update the layout so the extra content becomes visible. */ expandingLayout.setVisibility(View.VISIBLE); /* * Add an onPreDraw Listener to the listview. onPreDraw will get invoked after onLayout * and onMeasure have run but before anything has been drawn. This * means that the final post layout properties for all the items have already been * determined, but still have not been rendered onto the screen. */ final ViewTreeObserver observer = nlv.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { /* Determine if this is the first or second pass. */ if (!mShouldRemoveObserver) { mShouldRemoveObserver = true; /* * Calculate what the parameters should be for setSelectionFromTop. * The ListView must be offset in a way, such that after the animation * takes place, all the cells that remain visible are rendered completely * by the ListView. */ int newTop = view.getTop(); int newBottom = view.getBottom(); int newHeight = newBottom - newTop; int oldHeight = oldBottom - oldTop; int delta = newHeight - oldHeight; mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, delta, true); int currentTop = view.getTop(); int futureTop = oldTop - mTranslate[0]; int firstChildStartTop = nlv.getChildAt(0).getTop(); int firstVisiblePosition = nlv.getFirstVisiblePosition(); int deltaTop = currentTop - futureTop; int i; int childCount = nlv.getChildCount(); for (i = 0; i < childCount; i++) { View v = nlv.getChildAt(i); int height = v.getBottom() - Math.max(0, v.getTop()); if (deltaTop - height > 0) { firstVisiblePosition++; deltaTop -= height; } else { break; } } if (i > 0) { firstChildStartTop = 0; } nlv.setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop); /* Request another layout to update the layout parameters of the cells. */ nlv.requestLayout(); /* * Return false such that the ListView does not redraw its contents on * this layout but only updates all the parameters associated with its * children. */ return false; } /* Remove the predraw listener so this method does not keep getting called. */ mShouldRemoveObserver = false; observer.removeOnPreDrawListener(this); int yTranslateTop = mTranslate[0]; int yTranslateBottom = mTranslate[1]; ArrayList<Animator> animations = new ArrayList<Animator>(); int index = nlv.indexOfChild(view); /* * Loop through all the views that were on the screen before the cell was * expanded. Some cells will still be children of the ListView while * others will not. The cells that remain children of the ListView * simply have their bounds animated appropriately. The cells that are no * longer children of the ListView also have their bounds animated, but * must also be added to a list of views which will be drawn in dispatchDraw. */ for (View v : oldCoordinates.keySet()) { int[] old = oldCoordinates.get(v); v.setTop(old[0]); v.setBottom(old[1]); if (v.getParent() == null) { mViewsToDraw.add(v); int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom; animations.add(getAnimation(v, delta, delta)); } else { int i = nlv.indexOfChild(v); if (v != view) { int delta = i > index ? yTranslateBottom : -yTranslateTop; animations.add(getAnimation(v, delta, delta)); } ViewCompat.setHasTransientState(v, false); } } /* Adds animation for expanding the cell that was clicked. */ animations.add(getAnimation(view, -yTranslateTop, yTranslateBottom)); /* Adds an animation for fading in the extra content. */ animations.add(ObjectAnimator.ofFloat( view.findViewById(getExpandingAdapter().getExpandingHelper().getExpandingLayout()), View.ALPHA, 0, 1)); /* Disabled the ListView for the duration of the animation. */ nlv.setEnabled(false); nlv.setClickable(false); /* Play all the animations created above together at the same time. */ AnimatorSet s = new AnimatorSet(); s.playTogether(animations); s.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { item.setExpanded(true); nlv.setEnabled(true); nlv.setClickable(true); if (mViewsToDraw.size() > 0) { for (View v : mViewsToDraw) { ViewCompat.setHasTransientState(v, false); } } mViewsToDraw.clear(); } }); s.start(); return true; } }); }