diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
| commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
| tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/widget/TabWidget.java | |
| parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/widget/TabWidget.java')
| -rw-r--r-- | core/java/android/widget/TabWidget.java | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java new file mode 100644 index 000000000000..20cddcb3bfb2 --- /dev/null +++ b/core/java/android/widget/TabWidget.java @@ -0,0 +1,289 @@ +/* + * 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 android.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.View.OnFocusChangeListener; + + + +/** + * + * Displays a list of tab labels representing each page in the parent's tab + * collection. The container object for this widget is + * {@link android.widget.TabHost TabHost}. When the user selects a tab, this + * object sends a message to the parent container, TabHost, to tell it to switch + * the displayed page. You typically won't use many methods directly on this + * object. The container TabHost is used to add labels, add the callback + * handler, and manage callbacks. You might call this object to iterate the list + * of tabs, or to tweak the layout of the tab list, but most methods should be + * called on the containing TabHost object. + */ +public class TabWidget extends LinearLayout implements OnFocusChangeListener { + + + private OnTabSelectionChanged mSelectionChangedListener; + private int mSelectedTab = 0; + private Drawable mBottomLeftStrip; + private Drawable mBottomRightStrip; + private boolean mStripMoved; + + public TabWidget(Context context) { + this(context, null); + } + + public TabWidget(Context context, AttributeSet attrs) { + this(context, attrs, com.android.internal.R.attr.tabWidgetStyle); + } + + public TabWidget(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs); + initTabWidget(); + + TypedArray a = + context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget, + defStyle, 0); + + a.recycle(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mStripMoved = true; + super.onSizeChanged(w, h, oldw, oldh); + } + + private void initTabWidget() { + setOrientation(LinearLayout.HORIZONTAL); + mBottomLeftStrip = mContext.getResources().getDrawable( + com.android.internal.R.drawable.tab_bottom_left); + mBottomRightStrip = mContext.getResources().getDrawable( + com.android.internal.R.drawable.tab_bottom_right); + // Deal with focus, as we don't want the focus to go by default + // to a tab other than the current tab + setFocusable(true); + setOnFocusChangeListener(this); + } + + @Override + public void childDrawableStateChanged(View child) { + if (child == getChildAt(mSelectedTab)) { + // To make sure that the bottom strip is redrawn + invalidate(); + } + super.childDrawableStateChanged(child); + } + + @Override + public void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + View selectedChild = getChildAt(mSelectedTab); + + mBottomLeftStrip.setState(selectedChild.getDrawableState()); + mBottomRightStrip.setState(selectedChild.getDrawableState()); + + if (mStripMoved) { + Rect selBounds = new Rect(); // Bounds of the selected tab indicator + selBounds.left = selectedChild.getLeft(); + selBounds.right = selectedChild.getRight(); + final int myHeight = getHeight(); + mBottomLeftStrip.setBounds( + Math.min(0, selBounds.left + - mBottomLeftStrip.getIntrinsicWidth()), + myHeight - mBottomLeftStrip.getIntrinsicHeight(), + selBounds.left, + getHeight()); + mBottomRightStrip.setBounds( + selBounds.right, + myHeight - mBottomRightStrip.getIntrinsicHeight(), + Math.max(getWidth(), + selBounds.right + mBottomRightStrip.getIntrinsicWidth()), + myHeight); + mStripMoved = false; + } + + mBottomLeftStrip.draw(canvas); + mBottomRightStrip.draw(canvas); + } + + /** + * Sets the current tab. + * This method is used to bring a tab to the front of the Widget, + * and is used to post to the rest of the UI that a different tab + * has been brought to the foreground. + * + * Note, this is separate from the traditional "focus" that is + * employed from the view logic. + * + * For instance, if we have a list in a tabbed view, a user may be + * navigating up and down the list, moving the UI focus (orange + * highlighting) through the list items. The cursor movement does + * not effect the "selected" tab though, because what is being + * scrolled through is all on the same tab. The selected tab only + * changes when we navigate between tabs (moving from the list view + * to the next tabbed view, in this example). + * + * To move both the focus AND the selected tab at once, please use + * {@link #setCurrentTab}. Normally, the view logic takes care of + * adjusting the focus, so unless you're circumventing the UI, + * you'll probably just focus your interest here. + * + * @param index The tab that you want to indicate as the selected + * tab (tab brought to the front of the widget) + * + * @see #focusCurrentTab + */ + public void setCurrentTab(int index) { + if (index < 0 || index >= getChildCount()) { + return; + } + + getChildAt(mSelectedTab).setSelected(false); + mSelectedTab = index; + getChildAt(mSelectedTab).setSelected(true); + mStripMoved = true; + } + + /** + * Sets the current tab and focuses the UI on it. + * This method makes sure that the focused tab matches the selected + * tab, normally at {@link #setCurrentTab}. Normally this would not + * be an issue if we go through the UI, since the UI is responsible + * for calling TabWidget.onFocusChanged(), but in the case where we + * are selecting the tab programmatically, we'll need to make sure + * focus keeps up. + * + * @param index The tab that you want focused (highlighted in orange) + * and selected (tab brought to the front of the widget) + * + * @see #setCurrentTab + */ + public void focusCurrentTab(int index) { + final int oldTab = mSelectedTab; + + // set the tab + setCurrentTab(index); + + // change the focus if applicable. + if (oldTab != index) { + getChildAt(index).requestFocus(); + } + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + int count = getChildCount(); + + for (int i=0; i<count; i++) { + View child = getChildAt(i); + child.setEnabled(enabled); + } + } + + @Override + public void addView(View child) { + if (child.getLayoutParams() == null) { + final LinearLayout.LayoutParams lp = new LayoutParams( + 0, + ViewGroup.LayoutParams.WRAP_CONTENT, 1); + lp.setMargins(0, 0, 0, 0); + child.setLayoutParams(lp); + } + + // Ensure you can navigate to the tab with the keyboard, and you can touch it + child.setFocusable(true); + child.setClickable(true); + + super.addView(child); + + // TODO: detect this via geometry with a tabwidget listener rather + // than potentially interfere with the view's listener + child.setOnClickListener(new TabClickListener(getChildCount() - 1)); + child.setOnFocusChangeListener(this); + } + + + + + /** + * Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator. + */ + void setTabSelectionListener(OnTabSelectionChanged listener) { + mSelectionChangedListener = listener; + } + + public void onFocusChange(View v, boolean hasFocus) { + if (v == this && hasFocus) { + getChildAt(mSelectedTab).requestFocus(); + return; + } + + if (hasFocus) { + int i = 0; + while (i < getChildCount()) { + if (getChildAt(i) == v) { + setCurrentTab(i); + mSelectionChangedListener.onTabSelectionChanged(i, false); + break; + } + i++; + } + } + } + + // registered with each tab indicator so we can notify tab host + private class TabClickListener implements OnClickListener { + + private final int mTabIndex; + + private TabClickListener(int tabIndex) { + mTabIndex = tabIndex; + } + + public void onClick(View v) { + mSelectionChangedListener.onTabSelectionChanged(mTabIndex, true); + } + } + + /** + * Let {@link TabHost} know that the user clicked on a tab indicator. + */ + static interface OnTabSelectionChanged { + /** + * Informs the TabHost which tab was selected. It also indicates + * if the tab was clicked/pressed or just focused into. + * + * @param tabIndex index of the tab that was selected + * @param clicked whether the selection changed due to a touch/click + * or due to focus entering the tab through navigation. Pass true + * if it was due to a press/click and false otherwise. + */ + void onTabSelectionChanged(int tabIndex, boolean clicked); + } + +} + |
