コード例 #1
0
  /**
   * Determine the positions for the views. This is the main part of the algorithm.
   *
   * @param resultState The result state to update if a change to the properties of a child occurs
   * @param algorithmState The state in which the current pass of the algorithm is currently in
   * @param ambientState The current ambient state
   */
  private void updatePositionsForState(
      StackScrollState resultState,
      StackScrollAlgorithmState algorithmState,
      AmbientState ambientState) {
    Log.d(TAG, "updatePositionsForState: ");
    // The starting position of the bottom stack peek
    float bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize;

    // The position where the bottom stack starts.
    float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;

    // The y coordinate of the current child.
    float currentYPosition = 0.0f;

    // How far in is the element currently transitioning into the bottom stack.
    float yPositionInScrollView = 0.0f;

    // If we have a heads-up higher than the collapsed height we need to add the difference to
    // the padding of all other elements, i.e push in the top stack slightly.
    ExpandableNotificationRow topHeadsUpEntry = ambientState.getTopHeadsUpEntry();

    int childCount = algorithmState.visibleChildren.size();
    int numberOfElementsCompletelyIn =
        algorithmState.partialInTop == 1.0f
            ? algorithmState.lastTopStackIndex
            : (int) algorithmState.itemsInTopStack;
    for (int i = 0; i < childCount; i++) {
      ExpandableView child = algorithmState.visibleChildren.get(i);
      StackViewState childViewState = resultState.getViewStateForView(child);
      childViewState.location = StackViewState.LOCATION_UNKNOWN;
      int childHeight = getMaxAllowedChildHeight(child, ambientState);
      float yPositionInScrollViewAfterElement =
          yPositionInScrollView + childHeight + mPaddingBetweenElements;
      float scrollOffset = yPositionInScrollView - algorithmState.scrollY + mCollapsedSize;

      if (i == algorithmState.lastTopStackIndex + 1) {
        // Normally the position of this child is the position in the regular scrollview,
        // but if the two stacks are very close to each other,
        // then have have to push it even more upwards to the position of the bottom
        // stack start.
        currentYPosition = Math.min(scrollOffset, bottomStackStart);
      }
      childViewState.yTranslation = currentYPosition;

      // The y position after this element
      float nextYPosition = currentYPosition + childHeight + mPaddingBetweenElements;

      if (i <= algorithmState.lastTopStackIndex) {
        // Case 1:
        // We are in the top Stack
        updateStateForTopStackChild(
            algorithmState,
            numberOfElementsCompletelyIn,
            i,
            childHeight,
            childViewState,
            scrollOffset);
        clampPositionToTopStackEnd(childViewState, childHeight);

        // check if we are overlapping with the bottom stack
        if (childViewState.yTranslation + childHeight + mPaddingBetweenElements >= bottomStackStart
            && !mIsExpansionChanging
            && i != 0
            && mIsSmallScreen) {
          // we just collapse this element slightly
          int newSize =
              (int)
                  Math.max(
                      bottomStackStart - mPaddingBetweenElements - childViewState.yTranslation,
                      mCollapsedSize);
          childViewState.height = newSize;
          updateStateForChildTransitioningInBottom(
              algorithmState,
              bottomStackStart,
              bottomPeekStart,
              childViewState.yTranslation,
              childViewState,
              childHeight);
        }
        clampPositionToBottomStackStart(childViewState, childViewState.height, ambientState);
      } else if (nextYPosition >= bottomStackStart) {
        // Case 2:
        // We are in the bottom stack.
        if (currentYPosition >= bottomStackStart) {
          // According to the regular scroll view we are fully translated out of the
          // bottom of the screen so we are fully in the bottom stack
          updateStateForChildFullyInBottomStack(
              algorithmState, bottomStackStart, childViewState, childHeight, ambientState);
        } else {
          // According to the regular scroll view we are currently translating out of /
          // into the bottom of the screen
          updateStateForChildTransitioningInBottom(
              algorithmState,
              bottomStackStart,
              bottomPeekStart,
              currentYPosition,
              childViewState,
              childHeight);
        }
      } else {
        // Case 3:
        // We are in the regular scroll area.
        childViewState.location = StackViewState.LOCATION_MAIN_AREA;
        clampYTranslation(childViewState, childHeight, ambientState);
      }

      // The first card is always rendered.
      if (i == 0) {
        childViewState.alpha = 1.0f;
        childViewState.yTranslation = Math.max(mCollapsedSize - algorithmState.scrollY, 0);
        if (childViewState.yTranslation + childViewState.height
            > bottomPeekStart - mCollapseSecondCardPadding) {
          childViewState.height =
              (int)
                  Math.max(
                      bottomPeekStart - mCollapseSecondCardPadding - childViewState.yTranslation,
                      mCollapsedSize);
        }
        childViewState.location = StackViewState.LOCATION_FIRST_CARD;
      }
      if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
        Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
      }
      currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
      yPositionInScrollView = yPositionInScrollViewAfterElement;

      if (ambientState.isShadeExpanded() && topHeadsUpEntry != null && child != topHeadsUpEntry) {
        childViewState.yTranslation += topHeadsUpEntry.getHeadsUpHeight() - mCollapsedSize;
      }
      childViewState.yTranslation +=
          ambientState.getTopPadding() + ambientState.getStackTranslation();
    }
    updateHeadsUpStates(resultState, algorithmState, ambientState);
  }