Example #1
0
  /**
   * This method determines which menu items get to be 'action items' that will appear in an action
   * bar and which items should be 'overflow items' in a secondary menu. The rules are as follows:
   *
   * <p>Items are considered for inclusion in the order specified within the menu. There is a limit
   * of mMaxActionItems as a total count, optionally including the overflow menu button itself. This
   * is a soft limit; if an item shares a group ID with an item previously included as an action
   * item, the new item will stay with its group and become an action item itself even if it breaks
   * the max item count limit. This is done to limit the conceptual complexity of the items
   * presented within an action bar. Only a few unrelated concepts should be presented to the user
   * in this space, and groups are treated as a single concept.
   *
   * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This limit may
   * be broken by a single item that exceeds the remaining space, but no further items may be added.
   * If an item that is part of a group cannot fit within the remaining measured width, the entire
   * group will be demoted to overflow. This is done to ensure room for navigation and other
   * affordances in the action bar as well as reduce general UI clutter.
   *
   * <p>The space freed by demoting a full group cannot be consumed by future menu items. Once items
   * begin to overflow, all future items become overflow items as well. This is to avoid inadvertent
   * reordering that may break the app's intended design.
   */
  public void flagActionItems() {
    if (!mIsActionItemsStale) {
      return;
    }

    // Presenters flag action items as needed.
    boolean flagged = false;
    for (WeakReference<MenuPresenter> ref : mPresenters) {
      final MenuPresenter presenter = ref.get();
      if (presenter == null) {
        mPresenters.remove(ref);
      } else {
        flagged |= presenter.flagActionItems();
      }
    }

    if (flagged) {
      mActionItems.clear();
      mNonActionItems.clear();
      ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
      final int itemsSize = visibleItems.size();
      for (int i = 0; i < itemsSize; i++) {
        MenuItemImpl item = visibleItems.get(i);
        if (item.isActionButton()) {
          mActionItems.add(item);
        } else {
          mNonActionItems.add(item);
        }
      }
    } else {
      // Nobody flagged anything, everything is a non-action item.
      // (This happens during a first pass with no action-item presenters.)
      mActionItems.clear();
      mNonActionItems.clear();
      mNonActionItems.addAll(getVisibleItems());
    }
    mIsActionItemsStale = false;
  }
    public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
      super(context, subMenu);
      // UNUSED mSubMenu = subMenu;

      MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
      if (!item.isActionButton()) {
        // Give a reasonable anchor to nested submenus.
        setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
      }

      setCallback(mPopupPresenterCallback);

      boolean preserveIconSpacing = false;
      final int count = subMenu.size();
      for (int i = 0; i < count; i++) {
        MenuItem childItem = subMenu.getItem(i);
        if (childItem.isVisible() && childItem.getIcon() != null) {
          preserveIconSpacing = true;
          break;
        }
      }
      setForceShowIcon(preserveIconSpacing);
    }
  public boolean flagActionItems() {
    final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
    final int itemsSize = visibleItems.size();
    int maxActions = mMaxItems;
    int widthLimit = mActionItemWidthLimit;
    final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    final ViewGroup parent = (ViewGroup) mMenuView;

    int requiredItems = 0;
    int requestedItems = 0;
    int firstActionWidth = 0;
    boolean hasOverflow = false;
    for (int i = 0; i < itemsSize; i++) {
      MenuItemImpl item = visibleItems.get(i);
      if (item.requiresActionButton()) {
        requiredItems++;
      } else if (item.requestsActionButton()) {
        requestedItems++;
      } else {
        hasOverflow = true;
      }
      if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
        // Overflow everything if we have an expanded action view and we're
        // space constrained.
        maxActions = 0;
      }
    }

    // Reserve a spot for the overflow item if needed.
    if (mReserveOverflow && (hasOverflow || requiredItems + requestedItems > maxActions)) {
      maxActions--;
    }
    maxActions -= requiredItems;

    final SparseBooleanArray seenGroups = mActionButtonGroups;
    seenGroups.clear();

    int cellSize = 0;
    int cellsRemaining = 0;
    if (mStrictWidthLimit) {
      cellsRemaining = widthLimit / mMinCellSize;
      final int cellSizeRemaining = widthLimit % mMinCellSize;
      cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
    }

    // Flag as many more requested items as will fit.
    for (int i = 0; i < itemsSize; i++) {
      MenuItemImpl item = visibleItems.get(i);

      if (item.requiresActionButton()) {
        View v = getItemView(item, mScrapActionButtonView, parent);
        if (mScrapActionButtonView == null) {
          mScrapActionButtonView = v;
        }
        if (mStrictWidthLimit) {
          cellsRemaining -=
              ActionMenuView.measureChildForCells(v, cellSize, cellsRemaining, querySpec, 0);
        } else {
          v.measure(querySpec, querySpec);
        }
        final int measuredWidth = v.getMeasuredWidth();
        widthLimit -= measuredWidth;
        if (firstActionWidth == 0) {
          firstActionWidth = measuredWidth;
        }
        final int groupId = item.getGroupId();
        if (groupId != 0) {
          seenGroups.put(groupId, true);
        }
        item.setIsActionButton(true);
      } else if (item.requestsActionButton()) {
        // Items in a group with other items that already have an action slot
        // can break the max actions rule, but not the width limit.
        final int groupId = item.getGroupId();
        final boolean inGroup = seenGroups.get(groupId);
        boolean isAction =
            (maxActions > 0 || inGroup)
                && widthLimit > 0
                && (!mStrictWidthLimit || cellsRemaining > 0);

        if (isAction) {
          View v = getItemView(item, mScrapActionButtonView, parent);
          if (mScrapActionButtonView == null) {
            mScrapActionButtonView = v;
          }
          if (mStrictWidthLimit) {
            final int cells =
                ActionMenuView.measureChildForCells(v, cellSize, cellsRemaining, querySpec, 0);
            cellsRemaining -= cells;
            if (cells == 0) {
              isAction = false;
            }
          } else {
            v.measure(querySpec, querySpec);
          }
          final int measuredWidth = v.getMeasuredWidth();
          widthLimit -= measuredWidth;
          if (firstActionWidth == 0) {
            firstActionWidth = measuredWidth;
          }

          if (mStrictWidthLimit) {
            isAction &= widthLimit >= 0;
          } else {
            // Did this push the entire first item past the limit?
            isAction &= widthLimit + firstActionWidth > 0;
          }
        }

        if (isAction && groupId != 0) {
          seenGroups.put(groupId, true);
        } else if (inGroup) {
          // We broke the width limit. Demote the whole group, they all overflow now.
          seenGroups.put(groupId, false);
          for (int j = 0; j < i; j++) {
            MenuItemImpl areYouMyGroupie = visibleItems.get(j);
            if (areYouMyGroupie.getGroupId() == groupId) {
              // Give back the action slot
              if (areYouMyGroupie.isActionButton()) maxActions++;
              areYouMyGroupie.setIsActionButton(false);
            }
          }
        }

        if (isAction) maxActions--;

        item.setIsActionButton(isAction);
      }
    }
    return true;
  }
 @Override
 public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
   return item.isActionButton();
 }