Exemplo n.º 1
0
 /**
  * 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() {
   if (mRTBackend != null && mRTBackend.startAnimation(this)) {
     return;
   }
   mView.setHasTransientState(true);
   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));
   if (mPendingSetupAction != null) {
     mAnimatorSetupMap.put(animator, mPendingSetupAction);
     mPendingSetupAction = null;
   }
   if (mPendingCleanupAction != null) {
     mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
     mPendingCleanupAction = null;
   }
   if (mPendingOnStartAction != null) {
     mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
     mPendingOnStartAction = null;
   }
   if (mPendingOnEndAction != null) {
     mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
     mPendingOnEndAction = null;
   }
   animator.addUpdateListener(mAnimatorEventListener);
   animator.addListener(mAnimatorEventListener);
   if (mStartDelaySet) {
     animator.setStartDelay(mStartDelay);
   }
   if (mDurationSet) {
     animator.setDuration(mDuration);
   }
   if (mInterpolatorSet) {
     animator.setInterpolator(mInterpolator);
   }
   animator.start();
 }
Exemplo n.º 2
0
  /**
   * This method collapses the view that was clicked and animates all the views around it to close
   * around the collapsing view. There are several steps required to do this which are outlined
   * below.
   *
   * <p>1. Update the layout parameters of the view clicked so as to minimize its height to the
   * original collapsed (default) state. 2. After invoking a layout, the listview will shift all the
   * cells so as to display them most efficiently. Therefore, during the first predraw pass, the
   * listview must be offset by some amount such that given the custom bound change upon collapse,
   * all the cells that need to be on the screen after the layout are rendered by the listview. 3.
   * On the second predraw pass, all the items are first returned to their original location (before
   * the first layout). 4. The collapsing view's bounds are animated to what the final values should
   * be. 5. The bounds above the collapsing view are animated downwards while the bounds below the
   * collapsing view are animated upwards. 6. The extra text is faded out as its contents become
   * visible throughout the animation process.
   */
  private void prepareCollapseView(final CardView view, final View expandingLayout) {
    final Card card = (Card) 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);
      if (Build.VERSION.SDK_INT >= 16) {
        v.setHasTransientState(true);
      }
      oldCoordinates.put(v, new int[] {v.getTop(), v.getBottom()});
    }

    /* Update the layout so the extra content becomes invisible.*/
    view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, view.getCollapsedHeight()));

    /* Add an onPreDraw listener. */
    final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(
        new ViewTreeObserver.OnPreDrawListener() {

          @Override
          public boolean onPreDraw() {

            if (!mShouldRemoveObserver) {
              /*Same as for expandingView, the parameters for setSelectionFromTop must
               * be determined such that the necessary cells of the ListView are rendered
               * and added to it.*/
              mShouldRemoveObserver = true;

              int newTop = view.getTop();
              int newBottom = view.getBottom();

              int newHeight = newBottom - newTop;
              int oldHeight = oldBottom - oldTop;
              int deltaHeight = oldHeight - newHeight;

              mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, deltaHeight, false);

              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;
              }

              setSelection(firstVisiblePosition);
              // setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop);

              requestLayout();

              return false;
            }

            mShouldRemoveObserver = false;
            observer.removeOnPreDrawListener(this);

            int yTranslateTop = mTranslate[0];
            int yTranslateBottom = mTranslate[1];

            int index = indexOfChild(view);
            int numOfColumns = getNumColumns();
            int rowOfSelectedItem = (int) index / numOfColumns;

            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
              View v = getChildAt(i);
              int[] old = oldCoordinates.get(v);
              if (old != null) {
                /* If the cell was present in the ListView before the collapse and
                 * after the collapse then the bounds are reset to their old values.*/
                v.setTop(old[0]);
                v.setBottom(old[1]);
                if (Build.VERSION.SDK_INT >= 16) {
                  v.setHasTransientState(false);
                }
              } else {
                /* If the cell is present in the ListView after the collapse but
                 * not before the collapse then the bounds are calculated using
                 * the bottom and top translation of the collapsing cell.*/
                int rowOfv = (int) i / numOfColumns;
                int delta =
                    (i > index && rowOfv > rowOfSelectedItem) ? yTranslateBottom : -yTranslateTop;
                v.setTop(v.getTop() + delta);
                v.setBottom(v.getBottom() + delta);
              }
            }

            /* Animates all the cells present on the screen after the collapse. */
            ArrayList<Animator> animations = new ArrayList<Animator>();
            for (int i = 0; i < childCount; i++) {
              View v = getChildAt(i);
              if (v != view) {
                float diff = i > index ? -yTranslateBottom : yTranslateTop;
                animations.add(getAnimation(v, diff, diff));
              }
            }

            /*
            ValueAnimator animator = ValueAnimator.ofInt( yTranslateTop,-yTranslateBottom);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    int value = (Integer) valueAnimator.getAnimatedValue();

                    ViewGroup.LayoutParams layoutParams = expandingLayout.getLayoutParams();
                    layoutParams.height = value;
                    expandingLayout.setLayoutParams(layoutParams);
                }
            });
            animations.add(animator);*/

            /* Adds animation for collapsing the cell that was clicked. */
            animations.add(getAnimation(view, yTranslateTop, -yTranslateBottom));

            /* Adds an animation for fading out the extra content. */
            animations.add(ObjectAnimator.ofFloat(expandingLayout, ALPHA, 1, 0));

            /* 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) {
                    expandingLayout.setVisibility(View.GONE);
                    view.setLayoutParams(
                        new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
                    view.setExpanded(false);
                    setEnabled(true);
                    setClickable(true);
                    /* Note that alpha must be set back to 1 in case this view is reused
                     * by a cell that was expanded, but not yet collapsed, so its state
                     * should persist in an expanded state with the extra content visible.*/
                    expandingLayout.setAlpha(1);

                    if (card.getOnCollapseAnimatorEndListener() != null)
                      card.getOnCollapseAnimatorEndListener().onCollapseEnd(card);
                  }
                });
            s.start();

            return true;
          }
        });
  }
Exemplo n.º 3
0
  private void prepareExpandView(final CardView view, final View expandingLayout) {
    final Card card = (Card) 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);
      if (Build.VERSION.SDK_INT >= 16) {
        v.setHasTransientState(true);
      }
      oldCoordinates.put(v, new int[] {v.getTop(), v.getBottom()});
    }

    /* Update the layout so the extra content becomes visible.*/
    if (expandingLayout != null) 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;
              }

              setSelection(firstVisiblePosition);
              // 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);
            int numOfColumns = getNumColumns();
            int rowOfSelectedItem = (int) index / numOfColumns;

            /* 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 rowOfv = (int) i / numOfColumns;
                  int delta =
                      (i > index && rowOfv > rowOfSelectedItem) ? yTranslateBottom : -yTranslateTop;
                  animations.add(getAnimation(v, delta, delta));
                }
                v.setHasTransientState(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(expandingLayout, 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) {
                    view.setExpanded(true); // card.setExpanded(true);
                    setEnabled(true);
                    setClickable(true);
                    if (mViewsToDraw.size() > 0) {
                      for (View v : mViewsToDraw) {
                        if (Build.VERSION.SDK_INT >= 16) {
                          v.setHasTransientState(false);
                        }
                      }
                    }
                    mViewsToDraw.clear();

                    if (card.getOnExpandAnimatorEndListener() != null)
                      card.getOnExpandAnimatorEndListener().onExpandEnd(card);
                  }
                });
            s.start();
            return true;
          }
        });
  }
Exemplo n.º 4
0
 public static void setHasTransientState(View view, boolean hasTransientState) {
   view.setHasTransientState(hasTransientState);
 }