/*
* 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 com.jecelyin.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import com.jecelyin.editor.R;
/**
*
* 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.
*
* <p>See the <a href="{@docRoot}resources/tutorials/views/hello-tabwidget.html">Tab Layout
* tutorial</a>.</p>
*
* @attr ref android.R.styleable#TabWidget_divider
* @attr ref android.R.styleable#TabWidget_tabStripEnabled
* @attr ref android.R.styleable#TabWidget_tabStripLeft
* @attr ref android.R.styleable#TabWidget_tabStripRight
*/
public class TabWidget extends LinearLayout {
private OnTabSelectionChanged mSelectionChangedListener;
private int mSelectedTab = 0;
private PopupWindow mPopup;
private int mMenuCurrentIndex;
private OnMenuClickListener mOnMenuClickListener;
public static final int MENU_ACTION_CLOSE_ONE = 0;
public static final int MENU_ACTION_CLOSE_OTHER = 1;
public static final int MENU_ACTION_CLOSE_RIGHT = 2;
public static final int MENU_ACTION_CLOSE_ALL = 3;
public TabWidget(Context context) {
super(context);
//this(context, attrs, com.android.internal.R.attr.tabWidgetStyle);
initTabWidget(context);
}
public TabWidget(Context context, AttributeSet attrs) {
super(context, attrs);
//this(context, attrs, com.android.internal.R.attr.tabWidgetStyle);
initTabWidget(context);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
private void initTabWidget(final Context context) {
// Deal with focus, as we don't want the focus to go by default
// to a tab other than the current tab
setFocusable(true);
View mView = (View)LayoutInflater.from(context).inflate(R.layout.tab_menu, null);
//不能这么用,一定要传正确的context,不然无法点其它地方关闭菜单
//mPopup = new PopupWindow(mView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mPopup = new PopupWindow(context);
mPopup.setContentView(mView);
//mPopup.setWindowLayoutMode(context.getResources().getDimensionPixelSize(R.dimen.menu_width), ViewGroup.LayoutParams.WRAP_CONTENT);
//mPopup.setWidth(context.getResources().getDimensionPixelSize(R.dimen.menu_width));
mPopup.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
//点击其它地方关闭菜单
mPopup.setOutsideTouchable(true);
mPopup.setFocusable(true);
//背景透明,不能设置为null
mPopup.setBackgroundDrawable(new BitmapDrawable());
LinearLayout linearLayout_closeothers = (LinearLayout)mView.findViewById(R.id.linearLayout_closeothers);
LinearLayout linearLayout_closeright = (LinearLayout)mView.findViewById(R.id.linearLayout_closeright);
LinearLayout linearLayout_closeall = (LinearLayout)mView.findViewById(R.id.linearLayout_closeall);
linearLayout_closeall.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
hideMenu();
if(mOnMenuClickListener!=null)
mOnMenuClickListener.onMenuClick(MENU_ACTION_CLOSE_ALL, mMenuCurrentIndex);
}
});
linearLayout_closeothers.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
hideMenu();
if(mOnMenuClickListener!=null)
mOnMenuClickListener.onMenuClick(MENU_ACTION_CLOSE_OTHER, mMenuCurrentIndex);
}
});
linearLayout_closeright.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
hideMenu();
if(mOnMenuClickListener!=null)
mOnMenuClickListener.onMenuClick(MENU_ACTION_CLOSE_RIGHT, mMenuCurrentIndex);
}
});
}
public void hideMenu()
{
if(mPopup.isShowing())
mPopup.dismiss();
}
/**
* Returns the tab indicator view at the given index.
*
* @param index the zero-based index of the tab indicator view to return
* @return the tab indicator view at the given index
*/
public View getChildTabViewAt(int index) {
return getChildAt(index);
}
/**
* Returns the number of tab indicator views.
* @return the number of tab indicator views.
*/
public int getTabCount() {
int children = getChildCount();
return children;
}
/**
* 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 >= getTabCount()) {
return;
}
getChildTabViewAt(mSelectedTab).setSelected(false);
getChildTabViewAt(mSelectedTab).setBackgroundResource(R.drawable.tab_indicator);
mSelectedTab = index;
getChildTabViewAt(mSelectedTab).setSelected(true);
getChildTabViewAt(mSelectedTab).setBackgroundResource(R.drawable.tab_indicator_current);
if(mSelectedTab == 0)
{
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)getChildTabViewAt(mSelectedTab).getLayoutParams();
lp.leftMargin = 0;
getChildTabViewAt(mSelectedTab).setLayoutParams(lp);
}
//Log.d("TabWidget", "setCurrentTab:"+index);
}
/**
* 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) {
getChildTabViewAt(index).requestFocus();
}*/
}
@Override
public void addView(View child) {
/*if (child.getLayoutParams() == null) {
final LinearLayout.LayoutParams lp = new LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.FILL_PARENT, 1.0f);
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);
if(getTabCount() == 0)
{
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)child.getLayoutParams();
lp.leftMargin = 0;
child.setLayoutParams(lp);
}
super.addView(child);
//触发onFocusChange
child.setOnClickListener(mOnClickListener);
//右键菜单
child.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v)
{
int index = indexOfChild(v);
if(index < 0)
return false;
showTabMenu(v, index);
return false;
}
});
}
private void showTabMenu(View v, int index)
{
mMenuCurrentIndex = index;
mPopup.showAsDropDown(v, 0, -8);
}
public void setOnMenuClickListener(OnMenuClickListener l)
{
mOnMenuClickListener = l;
}
interface OnMenuClickListener
{
public void onMenuClick(int action, int index);
}
/**
* Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.
*/
void setTabSelectionListener(OnTabSelectionChanged listener) {
mSelectionChangedListener = listener;
}
private OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(View v)
{
int index = indexOfChild(v);
if(index < 0)
return;
//Log.d("TabWidget", "onFocusChange: "+mSelectedTab+"/"+index);
setCurrentTab(index);
mSelectionChangedListener.onTabSelectionChanged(index);
}
};
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
*/
void onTabSelectionChanged(int tabIndex);
}
protected void dispatchDraw(Canvas paramCanvas)
{
int count = getTabCount();
if(count<1 || mSelectedTab < 0)
return;
final long drawingTime = getDrawingTime();
View mView;
for(int i=count-1; i>=0; i--)
{
if(i != mSelectedTab)
{
mView = getChildAt(i);
if(mView != null)
{
drawChild(paramCanvas, mView, drawingTime);
}
}
}
//覆盖在其它tab上面,即是将它置于最前
mView = getChildAt(mSelectedTab);
if(mView != null)
drawChild(paramCanvas, mView, drawingTime);
}
public void removeViewAt(int tabId)
{
mSelectedTab = 0;
super.removeViewAt(tabId);
}
}