ActionBar tab mode using fragments; needs styles.

Change-Id: I8f931dae447e7b64de827d3c17766e5f8ad794e2
This commit is contained in:
Adam Powell
2010-07-02 10:09:44 -07:00
parent 31a4dbf5ca
commit 661c908e4e
5 changed files with 721 additions and 7 deletions

View File

@@ -22,6 +22,9 @@ import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.Menu;
@@ -31,6 +34,8 @@ import android.widget.LinearLayout;
import android.widget.SpinnerAdapter;
import android.widget.ViewAnimator;
import java.util.ArrayList;
/**
* ActionBarImpl is the ActionBar implementation used
* by devices of all screen sizes. If it detects a compatible decor,
@@ -42,10 +47,21 @@ public class ActionBarImpl extends ActionBar {
private static final int NORMAL_VIEW = 0;
private static final int CONTEXT_VIEW = 1;
private static final int TAB_SWITCH_SHOW_HIDE = 0;
private static final int TAB_SWITCH_ADD_REMOVE = 1;
private Activity mActivity;
private ViewAnimator mAnimatorView;
private ActionBarView mActionView;
private ActionBarContextView mUpperContextView;
private LinearLayout mLowerContextView;
private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
private int mTabContainerViewId = android.R.id.content;
private TabImpl mSelectedTab;
private int mTabSwitchMode = TAB_SWITCH_ADD_REMOVE;
private ContextMode mContextMode;
@@ -64,7 +80,9 @@ public class ActionBarImpl extends ActionBar {
}
};
public ActionBarImpl(View decor) {
public ActionBarImpl(Activity activity) {
final View decor = activity.getWindow().getDecorView();
mActivity = activity;
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
mUpperContextView = (ActionBarContextView) decor.findViewById(
com.android.internal.R.id.action_context_bar);
@@ -83,32 +101,54 @@ public class ActionBarImpl extends ActionBar {
}
public void setCustomNavigationMode(View view) {
cleanupTabs();
mActionView.setCustomNavigationView(view);
mActionView.setCallback(null);
}
public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback) {
cleanupTabs();
mActionView.setCallback(callback);
mActionView.setNavigationMode(NAVIGATION_MODE_DROPDOWN_LIST);
mActionView.setDropdownAdapter(adapter);
}
public void setStandardNavigationMode() {
cleanupTabs();
mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
mActionView.setCallback(null);
}
public void setStandardNavigationMode(CharSequence title) {
cleanupTabs();
setStandardNavigationMode(title, null);
}
public void setStandardNavigationMode(CharSequence title, CharSequence subtitle) {
cleanupTabs();
mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
mActionView.setTitle(title);
mActionView.setSubtitle(subtitle);
mActionView.setCallback(null);
}
private void cleanupTabs() {
if (mSelectedTab != null) {
selectTab(null);
}
if (!mTabs.isEmpty()) {
if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
final FragmentTransaction trans = mActivity.openFragmentTransaction();
final int tabCount = mTabs.size();
for (int i = 0; i < tabCount; i++) {
trans.remove(mTabs.get(i).getFragment());
}
trans.commit();
}
mTabs.clear();
}
}
public void setTitle(CharSequence title) {
mActionView.setTitle(title);
}
@@ -174,6 +214,113 @@ public class ActionBarImpl extends ActionBar {
}
}
private void configureTab(Tab tab, int position) {
final TabImpl tabi = (TabImpl) tab;
final boolean isFirstTab = mTabs.isEmpty();
final FragmentTransaction trans = mActivity.openFragmentTransaction();
final Fragment frag = tabi.getFragment();
tabi.setPosition(position);
mTabs.add(position, tabi);
if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
if (!frag.isAdded()) {
trans.add(mTabContainerViewId, frag);
}
}
if (isFirstTab) {
if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
trans.show(frag);
} else if (mTabSwitchMode == TAB_SWITCH_ADD_REMOVE) {
trans.add(mTabContainerViewId, frag);
}
mSelectedTab = tabi;
} else {
if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
trans.hide(frag);
}
}
trans.commit();
}
@Override
public void addTab(Tab tab) {
mActionView.addTab(tab);
configureTab(tab, mTabs.size());
}
@Override
public void insertTab(Tab tab, int position) {
mActionView.insertTab(tab, position);
configureTab(tab, position);
}
@Override
public Tab newTab() {
return new TabImpl();
}
@Override
public void removeTab(Tab tab) {
removeTabAt(tab.getPosition());
}
@Override
public void removeTabAt(int position) {
mActionView.removeTabAt(position);
mTabs.remove(position);
final int newTabCount = mTabs.size();
for (int i = position; i < newTabCount; i++) {
mTabs.get(i).setPosition(i);
}
selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
}
@Override
public void setTabNavigationMode() {
mActionView.setNavigationMode(NAVIGATION_MODE_TABS);
}
@Override
public void setTabNavigationMode(int containerViewId) {
mTabContainerViewId = containerViewId;
setTabNavigationMode();
}
@Override
public void selectTab(Tab tab) {
if (mSelectedTab == tab) {
return;
}
mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
final FragmentTransaction trans = mActivity.openFragmentTransaction();
if (mSelectedTab != null) {
if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
trans.hide(mSelectedTab.getFragment());
} else if (mTabSwitchMode == TAB_SWITCH_ADD_REMOVE) {
trans.remove(mSelectedTab.getFragment());
}
}
if (tab != null) {
if (mTabSwitchMode == TAB_SWITCH_SHOW_HIDE) {
trans.show(tab.getFragment());
} else if (mTabSwitchMode == TAB_SWITCH_ADD_REMOVE) {
trans.add(mTabContainerViewId, tab.getFragment());
}
}
mSelectedTab = (TabImpl) tab;
trans.commit();
}
@Override
public void selectTabAt(int position) {
selectTab(mTabs.get(position));
}
/**
* @hide
*/
@@ -233,6 +380,60 @@ public class ActionBarImpl extends ActionBar {
if (!actionItem.invoke()) {
mCallback.onContextItemClicked(this, item);
}
}
}
/**
* @hide
*/
public class TabImpl extends ActionBar.Tab {
private Fragment mFragment;
private Drawable mIcon;
private CharSequence mText;
private int mPosition;
@Override
public Fragment getFragment() {
return mFragment;
}
@Override
public Drawable getIcon() {
return mIcon;
}
@Override
public int getPosition() {
return mPosition;
}
public void setPosition(int position) {
mPosition = position;
}
@Override
public CharSequence getText() {
return mText;
}
@Override
public void setFragment(Fragment fragment) {
mFragment = fragment;
}
@Override
public void setIcon(Drawable icon) {
mIcon = icon;
}
@Override
public void setText(CharSequence text) {
mText = text;
}
@Override
public void select() {
selectTab(this);
}
}
}

View File

@@ -31,8 +31,10 @@ import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
@@ -85,6 +87,7 @@ public class ActionBarView extends ViewGroup {
private TextView mTitleView;
private TextView mSubtitleView;
private Spinner mSpinner;
private LinearLayout mTabLayout;
private View mCustomNavView;
private boolean mShowMenu;
@@ -128,7 +131,8 @@ public class ActionBarView extends ViewGroup {
ApplicationInfo info = context.getApplicationInfo();
PackageManager pm = context.getPackageManager();
mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, ActionBar.NAVIGATION_MODE_STANDARD);
mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
ActionBar.NAVIGATION_MODE_STANDARD);
mTitle = a.getText(R.styleable.ActionBar_title);
mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT);
@@ -271,6 +275,11 @@ public class ActionBarView extends ViewGroup {
mCustomNavView = null;
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
if (mTabLayout != null) {
removeView(mTabLayout);
mTabLayout = null;
}
}
switch (mode) {
@@ -286,6 +295,10 @@ public class ActionBarView extends ViewGroup {
case ActionBar.NAVIGATION_MODE_CUSTOM:
addView(mCustomNavView);
break;
case ActionBar.NAVIGATION_MODE_TABS:
mTabLayout = new LinearLayout(getContext());
addView(mTabLayout);
break;
}
mNavigationMode = mode;
requestLayout();
@@ -308,6 +321,35 @@ public class ActionBarView extends ViewGroup {
return mDisplayOptions;
}
private TabView createTabView(ActionBar.Tab tab) {
final TabView tabView = new TabView(getContext(), tab);
tabView.setFocusable(true);
tabView.setOnClickListener(new TabClickListener());
return tabView;
}
public void addTab(ActionBar.Tab tab) {
final boolean isFirst = mTabLayout.getChildCount() == 0;
final TabView tabView = createTabView(tab);
mTabLayout.addView(tabView);
if (isFirst) {
tabView.setSelected(true);
}
}
public void insertTab(ActionBar.Tab tab, int position) {
final boolean isFirst = mTabLayout.getChildCount() == 0;
final TabView tabView = createTabView(tab);
mTabLayout.addView(tabView, position);
if (isFirst) {
tabView.setSelected(true);
}
}
public void removeTabAt(int position) {
mTabLayout.removeViewAt(position);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
// Used by custom nav views if they don't supply layout params. Everything else
@@ -356,7 +398,7 @@ public class ActionBarView extends ViewGroup {
case ActionBar.NAVIGATION_MODE_TABS:
throw new UnsupportedOperationException(
"Tab navigation isn't supported yet!");
"Inflating tab navigation isn't supported yet!");
case ActionBar.NAVIGATION_MODE_CUSTOM:
if (mCustomNavView != null) {
@@ -381,6 +423,14 @@ public class ActionBarView extends ViewGroup {
addView(mTitleLayout);
}
public void setTabSelected(int position) {
final int tabCount = mTabLayout.getChildCount();
for (int i = 0; i < tabCount; i++) {
final View child = mTabLayout.getChildAt(i);
child.setSelected(i == position);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
@@ -442,6 +492,13 @@ public class ActionBarView extends ViewGroup {
MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
if (mTabLayout != null) {
mTabLayout.measure(
MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
break;
}
setMeasuredDimension(contentWidth, mContentHeight);
@@ -486,6 +543,10 @@ public class ActionBarView extends ViewGroup {
x += positionChild(mCustomNavView, x, y, contentHeight) + mSpacing;
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
if (mTabLayout != null) {
x += positionChild(mTabLayout, x, y, contentHeight) + mSpacing;
}
}
x = r - l - getPaddingRight();
@@ -515,4 +576,59 @@ public class ActionBarView extends ViewGroup {
return childWidth;
}
private static class TabView extends LinearLayout {
private ActionBar.Tab mTab;
public TabView(Context context, ActionBar.Tab tab) {
super(context);
mTab = tab;
// TODO Style tabs based on the theme
final Drawable icon = tab.getIcon();
final CharSequence text = tab.getText();
if (icon != null) {
ImageView iconView = new ImageView(context);
iconView.setImageDrawable(icon);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_VERTICAL;
iconView.setLayoutParams(lp);
addView(iconView);
}
if (text != null) {
TextView textView = new TextView(context);
textView.setText(text);
textView.setSingleLine();
textView.setEllipsize(TruncateAt.END);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_VERTICAL;
textView.setLayoutParams(lp);
addView(textView);
}
setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT, 1));
}
public ActionBar.Tab getTab() {
return mTab;
}
}
private class TabClickListener implements OnClickListener {
public void onClick(View view) {
TabView tabView = (TabView) view;
tabView.getTab().select();
final int tabCount = mTabLayout.getChildCount();
for (int i = 0; i < tabCount; i++) {
final View child = mTabLayout.getChildAt(i);
child.setSelected(child == view);
}
}
}
}