238 lines
7.5 KiB
Java
238 lines
7.5 KiB
Java
|
/*
|
||
|
* Copyright (C) 2011 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.support.v7.internal.view.menu;
|
||
|
|
||
|
import android.content.Context;
|
||
|
import android.support.v4.view.ViewCompat;
|
||
|
import android.view.LayoutInflater;
|
||
|
import android.view.View;
|
||
|
import android.view.ViewGroup;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
|
||
|
/**
|
||
|
* Base class for MenuPresenters that have a consistent container view and item views. Behaves
|
||
|
* similarly to an AdapterView in that existing item views will be reused if possible when items
|
||
|
* change.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public abstract class BaseMenuPresenter implements MenuPresenter {
|
||
|
|
||
|
protected Context mSystemContext;
|
||
|
protected Context mContext;
|
||
|
protected MenuBuilder mMenu;
|
||
|
protected LayoutInflater mSystemInflater;
|
||
|
protected LayoutInflater mInflater;
|
||
|
private Callback mCallback;
|
||
|
|
||
|
private int mMenuLayoutRes;
|
||
|
private int mItemLayoutRes;
|
||
|
|
||
|
protected MenuView mMenuView;
|
||
|
|
||
|
private int mId;
|
||
|
|
||
|
/**
|
||
|
* Construct a new BaseMenuPresenter.
|
||
|
*
|
||
|
* @param context Context for generating system-supplied views
|
||
|
* @param menuLayoutRes Layout resource ID for the menu container view
|
||
|
* @param itemLayoutRes Layout resource ID for a single item view
|
||
|
*/
|
||
|
public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
|
||
|
mSystemContext = context;
|
||
|
mSystemInflater = LayoutInflater.from(context);
|
||
|
mMenuLayoutRes = menuLayoutRes;
|
||
|
mItemLayoutRes = itemLayoutRes;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void initForMenu(Context context, MenuBuilder menu) {
|
||
|
mContext = context;
|
||
|
mInflater = LayoutInflater.from(mContext);
|
||
|
mMenu = menu;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public MenuView getMenuView(ViewGroup root) {
|
||
|
if (mMenuView == null) {
|
||
|
mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
|
||
|
mMenuView.initialize(mMenu);
|
||
|
updateMenuView(true);
|
||
|
}
|
||
|
|
||
|
return mMenuView;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reuses item views when it can
|
||
|
*/
|
||
|
public void updateMenuView(boolean cleared) {
|
||
|
final ViewGroup parent = (ViewGroup) mMenuView;
|
||
|
if (parent == null) return;
|
||
|
|
||
|
int childIndex = 0;
|
||
|
if (mMenu != null) {
|
||
|
mMenu.flagActionItems();
|
||
|
ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||
|
final int itemCount = visibleItems.size();
|
||
|
for (int i = 0; i < itemCount; i++) {
|
||
|
MenuItemImpl item = visibleItems.get(i);
|
||
|
if (shouldIncludeItem(childIndex, item)) {
|
||
|
final View convertView = parent.getChildAt(childIndex);
|
||
|
final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
|
||
|
((MenuView.ItemView) convertView).getItemData() : null;
|
||
|
final View itemView = getItemView(item, convertView, parent);
|
||
|
if (item != oldItem) {
|
||
|
// Don't let old states linger with new data.
|
||
|
itemView.setPressed(false);
|
||
|
ViewCompat.jumpDrawablesToCurrentState(itemView);
|
||
|
}
|
||
|
if (itemView != convertView) {
|
||
|
addItemView(itemView, childIndex);
|
||
|
}
|
||
|
childIndex++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove leftover views.
|
||
|
while (childIndex < parent.getChildCount()) {
|
||
|
if (!filterLeftoverView(parent, childIndex)) {
|
||
|
childIndex++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add an item view at the given index.
|
||
|
*
|
||
|
* @param itemView View to add
|
||
|
* @param childIndex Index within the parent to insert at
|
||
|
*/
|
||
|
protected void addItemView(View itemView, int childIndex) {
|
||
|
final ViewGroup currentParent = (ViewGroup) itemView.getParent();
|
||
|
if (currentParent != null) {
|
||
|
currentParent.removeView(itemView);
|
||
|
}
|
||
|
((ViewGroup) mMenuView).addView(itemView, childIndex);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Filter the child view at index and remove it if appropriate.
|
||
|
* @param parent Parent to filter from
|
||
|
* @param childIndex Index to filter
|
||
|
* @return true if the child view at index was removed
|
||
|
*/
|
||
|
protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||
|
parent.removeViewAt(childIndex);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public void setCallback(Callback cb) {
|
||
|
mCallback = cb;
|
||
|
}
|
||
|
|
||
|
public Callback getCallback() {
|
||
|
return mCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a new item view that can be re-bound to other item data later.
|
||
|
*
|
||
|
* @return The new item view
|
||
|
*/
|
||
|
public MenuView.ItemView createItemView(ViewGroup parent) {
|
||
|
return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Prepare an item view for use. See AdapterView for the basic idea at work here.
|
||
|
* This may require creating a new item view, but well-behaved implementations will
|
||
|
* re-use the view passed as convertView if present. The returned view will be populated
|
||
|
* with data from the item parameter.
|
||
|
*
|
||
|
* @param item Item to present
|
||
|
* @param convertView Existing view to reuse
|
||
|
* @param parent Intended parent view - use for inflation.
|
||
|
* @return View that presents the requested menu item
|
||
|
*/
|
||
|
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||
|
MenuView.ItemView itemView;
|
||
|
if (convertView instanceof MenuView.ItemView) {
|
||
|
itemView = (MenuView.ItemView) convertView;
|
||
|
} else {
|
||
|
itemView = createItemView(parent);
|
||
|
}
|
||
|
bindItemView(item, itemView);
|
||
|
return (View) itemView;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Bind item data to an existing item view.
|
||
|
*
|
||
|
* @param item Item to bind
|
||
|
* @param itemView View to populate with item data
|
||
|
*/
|
||
|
public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
|
||
|
|
||
|
/**
|
||
|
* Filter item by child index and item data.
|
||
|
*
|
||
|
* @param childIndex Indended presentation index of this item
|
||
|
* @param item Item to present
|
||
|
* @return true if this item should be included in this menu presentation; false otherwise
|
||
|
*/
|
||
|
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||
|
if (mCallback != null) {
|
||
|
mCallback.onCloseMenu(menu, allMenusAreClosing);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean onSubMenuSelected(SubMenuBuilder menu) {
|
||
|
if (mCallback != null) {
|
||
|
return mCallback.onOpenSubMenu(menu);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public boolean flagActionItems() {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public int getId() {
|
||
|
return mId;
|
||
|
}
|
||
|
|
||
|
public void setId(int id) {
|
||
|
mId = id;
|
||
|
}
|
||
|
}
|