Android Open Source - mvfa Tab Host






From Project

Back to project page mvfa.

License

The source code is released under:

GNU General Public License

If you think the Android project mvfa listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/* Modifications to use add ability to switch the position and visibility of tabs
 * and also to add replaceContent(Intent intent) method to TabSpec.
 * //from w  ww. j a v a 2 s. c  o  m
 * Modifications Copyright (C) 2009 Justin Shapcott, nEx.Software
 *
 * 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.
 */

/* Original Copyright Information
 * 
 * Copyright (C) 2006 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 my.android.widget;

import java.util.ArrayList;
import java.util.List;

import android.app.LocalActivityManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import be.benvd.mvforandroid.R;

/**
 * Container for a tabbed window view. This object holds two children: a set of
 * tab labels that the user clicks to select a specific tab, and a FrameLayout
 * object that displays the contents of that page. The individual elements are
 * typically controlled using this container object, rather than setting values
 * on the child elements themselves.
 */
public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener
  {

  private TabWidget mTabWidget;
  private FrameLayout mTabContent;
  private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
  /**
   * This field should be made private, so it is hidden from the SDK. {@hide
   * 
   * 
   * }
   */
  protected int mCurrentTab = -1;
  private View mCurrentView = null;
  /**
   * This field should be made private, so it is hidden from the SDK. {@hide
   * 
   * 
   * }
   */
  protected LocalActivityManager mLocalActivityManager = null;
  private OnTabChangeListener mOnTabChangeListener;
  private OnKeyListener mTabKeyListener;

  public TabHost(Context context)
    {
    super(context);
    initTabHost();
    }

  public TabHost(Context context, AttributeSet attrs)
    {
    super(context, attrs);
    initTabHost();
    }

  private final void initTabHost()
    {
    setFocusableInTouchMode(true);
    setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);

    mCurrentTab = -1;
    mCurrentView = null;
    }

  /**
   * Get a new {@link TabSpec} associated with this tab host.
   * 
   * @param tag
   *            required tag of tab.
   */
  public TabSpec newTabSpec(String tag)
    {
    return new TabSpec(tag);
    }

  /**
   * <p>
   * Call setup() before adding tabs if loading TabHost using findViewById().
   * <i><b>However</i></b>: You do not need to call setup() after getTabHost()
   * in {@link my.android.app.TabActivity TabActivity}. Example:
   * </p>
   * 
   * <pre>
   * mTabHost = (TabHost) findViewById(R.id.tabhost);
   * mTabHost.setup();
   * mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
   */
  public void setup()
    {
    mTabWidget = (TabWidget) findViewById(android.R.id.tabs);
    if(mTabWidget == null)
      {
      throw new RuntimeException("Your TabHost must have a TabWidget whose id attribute is 'android.R.id.tabs'");
      }

    // KeyListener to attach to all tabs. Detects non-navigation keys
    // and relays them to the tab content.
    mTabKeyListener = new OnKeyListener()
      {
        public boolean onKey(View v, int keyCode, KeyEvent event)
          {
          switch(keyCode)
            {
            case KeyEvent.KEYCODE_DPAD_CENTER:
            case KeyEvent.KEYCODE_DPAD_LEFT:
            case KeyEvent.KEYCODE_DPAD_RIGHT:
            case KeyEvent.KEYCODE_DPAD_UP:
            case KeyEvent.KEYCODE_DPAD_DOWN:
            case KeyEvent.KEYCODE_ENTER:
              return false;

            }
          mTabContent.requestFocus(View.FOCUS_FORWARD);
          return mTabContent.dispatchKeyEvent(event);
          }

      };

    mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged()
      {
        public void onTabSelectionChanged(int tabIndex, boolean clicked)
          {
          setCurrentTab(tabIndex);
          if(clicked)
            {
            mTabContent.requestFocus(View.FOCUS_FORWARD);
            }
          }
      });

    mTabContent = (FrameLayout) findViewById(android.R.id.tabcontent);
    if(mTabContent == null)
      {
      throw new RuntimeException("Your TabHost must have a FrameLayout whose id attribute is 'android.R.id.tabcontent'");
      }
    }

  /**
   * If you are using {@link TabSpec#setContent(android.content.Intent)}, this
   * must be called since the activityGroup is needed to launch the local
   * activity.
   * 
   * This is done for you if you extend {@link my.android.app.TabActivity}.
   * 
   * @param activityGroup
   *            Used to launch activities for tab content.
   */
  public void setup(LocalActivityManager activityGroup)
    {
    setup();
    mLocalActivityManager = activityGroup;
    }

  @Override
  protected void onAttachedToWindow()
    {
    super.onAttachedToWindow();
    final ViewTreeObserver treeObserver = getViewTreeObserver();
    if(treeObserver != null)
      {
      treeObserver.addOnTouchModeChangeListener(this);
      }
    }

  @Override
  protected void onDetachedFromWindow()
    {
    super.onDetachedFromWindow();
    final ViewTreeObserver treeObserver = getViewTreeObserver();
    if(treeObserver != null)
      {
      treeObserver.removeOnTouchModeChangeListener(this);
      }
    }

  /**
   * {@inheritDoc}
   */
  public void onTouchModeChanged(boolean isInTouchMode)
    {
    if(!isInTouchMode)
      {
      // leaving touch mode.. if nothing has focus, let's give it to
      // the indicator of the current tab
      if(!mCurrentView.hasFocus() || mCurrentView.isFocused())
        {
        mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
        }
      }
    }

  /**
   * Add a tab.
   * 
   * @param tabSpec
   *            Specifies how to create the indicator and content.
   */
  public void addTab(TabSpec tabSpec)
    {

    if(tabSpec.mIndicatorStrategy == null)
      {
      throw new IllegalArgumentException("you must specify a way to create the tab indicator.");
      }

    if(tabSpec.mContentStrategy == null)
      {
      throw new IllegalArgumentException("you must specify a way to create the tab content");
      }
    View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
    tabIndicator.setOnKeyListener(mTabKeyListener);

    // If this is a custom view, then do not draw the bottom strips for
    // the tab indicators.
    if(tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy)
      {
      mTabWidget.setDrawBottomStrips(false);
      }
    mTabWidget.addView(tabIndicator);
    mTabSpecs.add(tabSpec);

    if(mCurrentTab == -1)
      {
      setCurrentTab(0);
      }
    }

  /**
   * Removes all tabs from the tab widget associated with this tab host.
   */
  public void clearAllTabs()
    {
    mTabWidget.removeAllViews();
    initTabHost();
    mTabContent.removeAllViews();
    mTabSpecs.clear();
    requestLayout();
    invalidate();
    }

  public TabWidget getTabWidget()
    {
    return mTabWidget;
    }

  public int getCurrentTab()
    {
    return mCurrentTab;
    }

  public String getCurrentTabTag()
    {
    if(mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size())
      {
      return mTabSpecs.get(mCurrentTab).getTag();
      }
    return null;
    }

  public View getCurrentTabView()
    {
    if(mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size())
      {
      return mTabWidget.getChildTabViewAt(mCurrentTab);
      }
    return null;
    }

  public View getCurrentView()
    {
    return mCurrentView;
    }

  public void setCurrentTabByTag(String tag)
    {
    int i;
    for(i = 0; i < mTabSpecs.size(); i++)
      {
      if(mTabSpecs.get(i).getTag().equals(tag))
        {
        setCurrentTab(i);
        break;
        }
      }
    }

  /**
   * Get the FrameLayout which holds tab content
   */
  public FrameLayout getTabContentView()
    {
    return mTabContent;
    }

  @Override
  public boolean dispatchKeyEvent(KeyEvent event)
    {
    final boolean handled = super.dispatchKeyEvent(event);

    // unhandled key ups change focus to tab indicator for embedded
    // activities
    // when there is nothing that will take focus from default focus
    // searching
    if(!handled && (event.getAction() == KeyEvent.ACTION_DOWN) && (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP)
    /* && (mCurrentView.isRootNamespace()) */
    && (mCurrentView.hasFocus()) && (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null))
      {
      mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
      playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
      return true;
      }
    return handled;
    }

  @Override
  public void dispatchWindowFocusChanged(boolean hasFocus)
    {
    mCurrentView.dispatchWindowFocusChanged(hasFocus);
    }

  public void setCurrentTab(int index)
    {
    if(index < 0 || index >= mTabSpecs.size())
      {
      return;
      }

    if(index == mCurrentTab)
      {
      return;
      }

    // notify old tab content
    if(mCurrentTab != -1)
      {
      mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();
      }

    mCurrentTab = index;
    final TabHost.TabSpec spec = mTabSpecs.get(index);

    // Call the tab widget's focusCurrentTab(), instead of just
    // selecting the tab.
    mTabWidget.focusCurrentTab(mCurrentTab);

    // tab content
    mCurrentView = spec.mContentStrategy.getContentView();

    if(mCurrentView.getParent() == null)
      {
      mTabContent.addView(mCurrentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
      }

    if(!mTabWidget.hasFocus())
      {
      // if the tab widget didn't take focus (likely because we're in
      // touch mode)
      // give the current tab content view a shot
      mCurrentView.requestFocus();
      }

    // mTabContent.requestFocus(View.FOCUS_FORWARD);
    invokeOnTabChangeListener();
    }

  /**
   * Register a callback to be invoked when the selected state of any of the
   * items in this list changes
   * 
   * @param l
   *            The callback that will run
   */
  public void setOnTabChangedListener(OnTabChangeListener l)
    {
    mOnTabChangeListener = l;
    }

  private void invokeOnTabChangeListener()
    {
    if(this.getTabContentView() instanceof Switcher)
      {
      ((Switcher) this.getTabContentView()).setCurrentIndex(this.getCurrentTab());
      }
    if(mOnTabChangeListener != null)
      {
      mOnTabChangeListener.onTabChanged(getCurrentTabTag());
      }
    }

  public void moveTabsToBottom()
    {
    TabWidget MyTabWidget = this.getTabWidget();
    LinearLayout MyTabWidgetParent = (LinearLayout) MyTabWidget.getParent();
    MyTabWidgetParent.removeView(MyTabWidget);
    MyTabWidgetParent.addView(MyTabWidget);
    }

  public void moveTabsToTop()
    {
    TabWidget MyTabWidget = this.getTabWidget();
    LinearLayout MyTabWidgetParent = (LinearLayout) MyTabWidget.getParent();
    MyTabWidgetParent.removeView(MyTabWidget);
    MyTabWidgetParent.addView(MyTabWidget, 0);
    }

  public void hideTabs()
    {
    TabWidget MyTabWidget = this.getTabWidget();
    MyTabWidget.setVisibility(View.GONE);
    }

  public void showTabs()
    {
    TabWidget MyTabWidget = this.getTabWidget();
    MyTabWidget.setVisibility(View.VISIBLE);
    }

  /**
   * Interface definition for a callback to be invoked when tab changed
   */
  public interface OnTabChangeListener
    {
    void onTabChanged(String tabId);
    }

  /**
   * Makes the content of a tab when it is selected. Use this if your tab
   * content needs to be created on demand, i.e. you are not showing an
   * existing view or starting an activity.
   */
  public interface TabContentFactory
    {
    /**
     * Callback to make the tab contents
     * 
     * @param tag
     *            Which tab was selected.
     * @return The view to display the contents of the selected tab.
     */
    View createTabContent(String tag);
    }

  /**
   * A tab has a tab indicator, content, and a tag that is used to keep track
   * of it. This builder helps choose among these options.
   * 
   * For the tab indicator, your choices are: 1) set a label 2) set a label
   * and an icon
   * 
   * For the tab content, your choices are: 1) the id of a {@link View} 2) a
   * {@link TabContentFactory} that creates the {@link View} content. 3) an
   * {@link Intent} that launches an {@link my.android.app.Activity}.
   */
  public class TabSpec
    {

    private String mTag;

    private IndicatorStrategy mIndicatorStrategy;
    private ContentStrategy mContentStrategy;

    private TabSpec(String tag)
      {
      mTag = tag;
      }

    /**
     * Specify a label as the tab indicator.
     */
    public TabSpec setIndicator(CharSequence label)
      {
      mIndicatorStrategy = new LabelIndicatorStrategy(label);
      return this;
      }

    /**
     * Specify a label and icon as the tab indicator.
     */
    public TabSpec setIndicator(CharSequence label, Drawable icon)
      {
      mIndicatorStrategy = new LabelAndIconIndicatorStrategy(label, icon);
      return this;
      }

    /**
     * Specify a view as the tab indicator.
     */
    public TabSpec setIndicator(View view)
      {
      mIndicatorStrategy = new ViewIndicatorStrategy(view);
      return this;
      }

    /**
     * Specify the id of the view that should be used as the content of the
     * tab.
     */
    public TabSpec setContent(int viewId)
      {
      mContentStrategy = new ViewIdContentStrategy(viewId);
      return this;
      }

    /**
     * Specify a {@link my.android.widget.TabHost.TabContentFactory} to use
     * to create the content of the tab.
     */
    public TabSpec setContent(TabContentFactory contentFactory)
      {
      mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);
      return this;
      }

    /**
     * Specify an intent to use to launch an activity as the tab content.
     */
    public TabSpec setContent(Intent intent)
      {
      mContentStrategy = new IntentContentStrategy(mTag, intent);
      return this;
      }

    public String getTag()
      {
      return mTag;
      }

    // Added this as a convenient way to replace the content of the TabSpec
    // when content is an Activity.
    // Tell the tab to close, destroy the underlying activity so it isn't in
    // limbo, then recreate the tab
    // This could be done for other content types but for the purpose of
    // this tutorial, I am only doing this.
    public TabSpec replaceContent(Intent intent)
      {
      mContentStrategy.tabClosed();
      mLocalActivityManager.destroyActivity(this.getTag(), true);
      mContentStrategy = new IntentContentStrategy(mTag, intent);
      mCurrentView = mContentStrategy.getContentView();
      if(mCurrentView.getParent() == null)
        {
        mTabContent.addView(mCurrentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
        }
      return this;
      }
    }

  /**
   * Specifies what you do to create a tab indicator.
   */
  private static interface IndicatorStrategy
    {

    /**
     * Return the view for the indicator.
     */
    View createIndicatorView();
    }

  /**
   * Specifies what you do to manage the tab content.
   */
  private static interface ContentStrategy
    {

    /**
     * Return the content view. The view should may be cached locally.
     */
    View getContentView();

    /**
     * Perhaps do something when the tab associated with this content has
     * been closed (i.e make it invisible, or remove it).
     */
    void tabClosed();
    }

  /**
   * How to create a tab indicator that just has a label.
   */
  private class LabelIndicatorStrategy implements IndicatorStrategy
    {

    private final CharSequence mLabel;

    private LabelIndicatorStrategy(CharSequence label)
      {
      mLabel = label;
      }

    public View createIndicatorView()
      {
      LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      View tabIndicator = inflater.inflate(R.layout.tab_indicator, mTabWidget, // tab
                                            // widget
                                            // is
                                            // the
                                            // parent
          false); // no inflate params

      final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
      tv.setText(mLabel);

      return tabIndicator;
      }
    }

  /**
   * How we create a tab indicator that has a label and an icon
   */
  private class LabelAndIconIndicatorStrategy implements IndicatorStrategy
    {

    private final CharSequence mLabel;
    private final Drawable mIcon;

    private LabelAndIconIndicatorStrategy(CharSequence label, Drawable icon)
      {
      mLabel = label;
      mIcon = icon;
      }

    public View createIndicatorView()
      {
      LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      View tabIndicator = inflater.inflate(R.layout.tab_indicator, mTabWidget, // tab
                                            // widget
                                            // is
                                            // the
                                            // parent
          false); // no inflate params

      final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
      tv.setText(mLabel);

      final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
      iconView.setImageDrawable(mIcon);

      return tabIndicator;
      }
    }

  /**
   * How to create a tab indicator by specifying a view.
   */
  private class ViewIndicatorStrategy implements IndicatorStrategy
    {

    private final View mView;

    private ViewIndicatorStrategy(View view)
      {
      mView = view;
      }

    public View createIndicatorView()
      {
      return mView;
      }
    }

  /**
   * How to create the tab content via a view id.
   */
  private class ViewIdContentStrategy implements ContentStrategy
    {

    private final View mView;

    private ViewIdContentStrategy(int viewId)
      {
      mView = mTabContent.findViewById(viewId);
      if(mView != null)
        {
        mView.setVisibility(View.GONE);
        }
      else
        {
        throw new RuntimeException("Could not create tab content because " + "could not find view with id " + viewId);
        }
      }

    public View getContentView()
      {
      mView.setVisibility(View.VISIBLE);
      return mView;
      }

    public void tabClosed()
      {
      mView.setVisibility(View.GONE);
      }
    }

  /**
   * How tab content is managed using {@link TabContentFactory}.
   */
  private class FactoryContentStrategy implements ContentStrategy
    {
    private View mTabContent;
    private final CharSequence mTag;
    private TabContentFactory mFactory;

    public FactoryContentStrategy(CharSequence tag, TabContentFactory factory)
      {
      mTag = tag;
      mFactory = factory;
      }

    public View getContentView()
      {
      if(mTabContent == null)
        {
        mTabContent = mFactory.createTabContent(mTag.toString());
        }
      mTabContent.setVisibility(View.VISIBLE);
      return mTabContent;
      }

    public void tabClosed()
      {
      mTabContent.setVisibility(View.INVISIBLE);
      }
    }

  /**
   * How tab content is managed via an {@link Intent}: the content view is the
   * decorview of the launched activity.
   */
  private class IntentContentStrategy implements ContentStrategy
    {

    private final String mTag;
    private final Intent mIntent;

    private View mLaunchedView;

    private IntentContentStrategy(String tag, Intent intent)
      {
      mTag = tag;
      mIntent = intent;
      }

    public View getContentView()
      {
      if(mLocalActivityManager == null)
        {
        throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");
        }
      final Window w = mLocalActivityManager.startActivity(mTag, mIntent);
      final View wd = w != null ? w.getDecorView() : null;
      if(mLaunchedView != wd && mLaunchedView != null)
        {
        if(mLaunchedView.getParent() != null)
          {
          mTabContent.removeView(mLaunchedView);
          }
        }
      mLaunchedView = wd;

      if(mLaunchedView != null)
        {
        mLaunchedView.setVisibility(View.VISIBLE);
        mLaunchedView.setFocusableInTouchMode(true);
        ((ViewGroup) mLaunchedView).setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
        }
      return mLaunchedView;
      }

    public void tabClosed()
      {
      if(mLaunchedView != null)
        {
        mLaunchedView.setVisibility(View.GONE);
        }
      }
    }
  }




Java Source Code List

be.benvd.mvforandroid.CreditActivity.java
be.benvd.mvforandroid.MainActivity.java
be.benvd.mvforandroid.SettingsActivity.java
be.benvd.mvforandroid.TopupsActivity.java
be.benvd.mvforandroid.UsageActivity.java
be.benvd.mvforandroid.data.DatabaseHelper.java
be.benvd.mvforandroid.data.MVDataHelper.java
be.benvd.mvforandroid.data.MVDataService.java
be.benvd.mvforandroid.data.OnAlarmReceiver.java
be.benvd.mvforandroid.data.OnBootReceiver.java
be.benvd.mvforandroid.widgets.WidgetProvider.java
com.commonsware.cwac.merge.MergeAdapter.java
com.commonsware.cwac.sacklist.SackOfViewsAdapter.java
com.commonsware.cwac.wakeful.WakefulIntentService.java
my.android.app.TabActivity.java
my.android.widget.Switcher.java
my.android.widget.TabHost.java
my.android.widget.TabWidget.java