`
xwangly
  • 浏览: 132268 次
  • 性别: Icon_minigender_1
  • 来自: 鄂州
社区版块
存档分类
最新评论

TabHost学习总结

阅读更多

需求:
Android自带的TabHost为橫向的,而且样式已经写死了,不能改变。
而我需要做一个纵向(垂直)的TabHost界面,达到如下效果:

垂直TabHost效果

使劲想套用API的TabHost,但是它里面的TabWidget的方向写死的,请看:

    
  private void initTabWidget() {
        setOrientation(LinearLayout.HORIZONTAL);


只好自已重写一个TabHost布局,代码如下:

package com.xwangly.tabhost;

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.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.View.OnKeyListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
//import android.widget.TabHost;
//import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.TabHost.OnTabChangeListener;

/*import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabContentFactory;*/
//import android.widget.TabHost.TabSpec;


public class MyTabHostLayout extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener{
	
    private LinearLayout mTabWidget;
    private FrameLayout mTabContent;
    private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
    
    protected int mCurrentTab = -1;
    private View mCurrentView = null;
    
    protected LocalActivityManager mLocalActivityManager = null;
    private OnTabChangeListener mOnTabChangeListener;
    private OnKeyListener mTabKeyListener;

	public MyTabHostLayout(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

    public MyTabHostLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        //initTabHost();
    }
	
	public void setCurrentTab(int index){
        if (index < 0 || index >= mTabSpecs.size()) {
            return;
        }

        if (index == mCurrentTab) {
            return;
        }

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

        
        final TabSpec spec = mTabSpecs.get(index);

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

        // set the tab
        //setCurrentTab(index);

        
        //mSelectedTab = index;
        mTabWidget.getChildAt(index).setSelected(true);
        //mStripMoved = true;

        // change the focus if applicable.
        if (oldTab != index) {
        	mTabWidget.getChildAt(index).requestFocus();
        }

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

        if (mCurrentView.getParent() == null) {
            mTabContent
                    .addView(
                            mCurrentView,
                            new ViewGroup.LayoutParams(
                                    ViewGroup.LayoutParams.MATCH_PARENT,
                                    ViewGroup.LayoutParams.MATCH_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();
	}

	private void invokeOnTabChangeListener() {
		// TODO Auto-generated method stub
		//mOnTabChangeListener.onTabChanged(mCurrentTab);
        if (mOnTabChangeListener != null) {
            mOnTabChangeListener.onTabChanged(getCurrentTabTag());
        }
	}



	private String getCurrentTabTag() {
		// TODO Auto-generated method stub
        if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
            return mTabSpecs.get(mCurrentTab).getTag();
        }
        return null;
	}



	public void setOnTabChangedListener(OnTabChangeListener l) {
		// TODO Auto-generated method stub
		mOnTabChangeListener = l;
	}
	
	public void setup() {
		// TODO Auto-generated method stub
		mTabWidget = (LinearLayout)findViewById(R.id.tabs);
        if (mTabWidget == null) {
            throw new RuntimeException(
                    "Your MyTabHostLayout must have a TabWidget that id :R.id.tabs");
        }
        
        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);
            }

        };
        
        mTabContent = (FrameLayout) findViewById(R.id.tabcontent);
        if (mTabContent == null) {
            throw new RuntimeException(
                    "Your MyTabHostLayout must have a FrameLayout that id:R.id.tabcontent");
        }
	}

	public void setup(LocalActivityManager activityGroup) {
		// TODO Auto-generated method stub
        setup();
        mLocalActivityManager = activityGroup;
	}

	public LinearLayout getTabWidget() {
		// TODO Auto-generated method stub
		return mTabWidget;
	}

	public TabSpec newTabSpec(String string) {
		// TODO Auto-generated method stub
		return new TabSpec(string);
	}


    
	private View.OnClickListener onTabSpecClickListener = new View.OnClickListener(){

		public void onClick(View v) {
			// TODO Auto-generated method stub
			Log.i("onTabSpecClickListener", ""+v.getClass());
			
			setCurrentTab(getTabIdByView(v));
		}
	};
	
	private int getTabIdByView(View v) {
		// TODO Auto-generated method stub
		for (int i = 0;i <mTabWidget.getChildCount();i++){
			if (v == mTabWidget.getChildAt(i)){
				Log.i("change tag", "click tag id:"+i);
				return i;
			}
		}
		return 0;
	}
		
	public void addTab(TabSpec tabSpec) {
		// TODO Auto-generated method stub
        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);
        tabIndicator.setOnClickListener(onTabSpecClickListener);

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

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

	public int getCurrentTab() {
		// TODO Auto-generated method stub
		return mCurrentTab;
	}
	

    
    @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);
        }
    }
    
    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 != null && (!mCurrentView.hasFocus() || mCurrentView.isFocused())) {
                mTabWidget.getChildAt(mCurrentTab).requestFocus();
            }
        }
    }
    
    
    /**
     * 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 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 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;
        }
    }
    

    /**
     * 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() {
            final Context context = getContext();
            LayoutInflater inflater =
                    (LayoutInflater) context.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);

            if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
                // Donut apps get old color scheme
                tabIndicator.setBackgroundResource(R.drawable.tab_indicator_v4);
                tv.setTextColor(context.getResources().getColorStateList(R.color.tab_indicator_text_v4));
            }
            
            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() {
            final Context context = getContext();
            LayoutInflater inflater =
                    (LayoutInflater) context.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.tabtitle);
            tv.setText(mLabel);

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

/*            if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
                // Donut apps get old color scheme
                tabIndicator.setBackgroundResource(R.drawable.tab_indicator_v4);
                tv.setTextColor(context.getResources().getColorStateList(R.color.tab_indicator_text_v4));
            }*/
            
            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.GONE);
        }
    }

    /**
     * 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;

            // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get
            // focus if none of their children have it. They need focus to be able to
            // display menu items.
            //
            // Replace this with something better when Bug 628886 is fixed...
            //
            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);
            }
        }
    }
    
    /**
     * 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);
    }
    
    /**
     * Interface definition for a callback to be invoked when tab changed
     */
    public interface OnTabChangeListener {
        void onTabChanged(String tabId);
    }

}


工程详见附件

 

分享到:
评论
2 楼 xiangdream 2012-04-17  
强 。。。。。。。
1 楼 oubaoxingfu 2012-03-15  
很不错,我有个问题不明白,每一个tab的背景颜色和字体在点击的时候会有变化,这个功能是在哪里实现的,请教,289982659@qq.com

相关推荐

    Android 嵌套TabHost示例

    通过分析这些文件,我们可以学习如何动态地创建和管理两个级别的TabHost,以及如何在不同标签间切换时更新内容。 总结来说,Android的嵌套TabHost是一种增强用户界面的方法,它允许开发者创建更复杂的导航结构,...

    TabHost使用总结

    在Android开发中,TabHost是一个非常重要的组件,用于创建具有多个选项卡的用户界面,每个选项卡都可以展示不同的...通过学习本资源提供的案例和文档,开发者可以更好地掌握TabHost的用法,从而提升应用的用户体验。

    android总结之TabHost

    这篇博客文章“android总结之TabHost”深入探讨了如何在Android应用中使用TabHost进行界面设计。TabHost提供了在同一个屏幕上展示多个功能区域的能力,使得用户可以方便地切换不同内容。 首先,我们需要理解TabHost...

    TabHost的各种实现方式

    总结,TabHost是Android开发中实现多Tab界面的经典组件,虽然在新版本的Android中,更多地推荐使用ViewPager和TabLayout的组合,但对于理解Android的历史和各种实现方式,TabHost仍然是不可或缺的一部分。通过学习和...

    tabhost的学习,简单的演示

    一直想仿一个微博的界面,最近写了个演示代码。 ... 从这个资源开始,资源分以后为0.当初上传资源其实为了换点积分,但是最近发现违背了初衷,我也好多次因为没有分,导致下不了东西。所以以后就尽力写一些免费的资源...

    仿新浪微博tabhost实现

    总结来说,仿新浪微博的TabHost实现涉及布局设计、TabHost初始化、自定义TabWidget样式以及处理每个标签页的逻辑。通过学习这个示例,开发者可以更好地掌握Android中的TabHost用法,从而创建出更加丰富和用户友好的...

    android tabhost --android UI 学习

    这篇博客“android tabhost --android UI 学习”很可能深入探讨了如何使用TabHost来构建一个多页面的应用程序布局。在Android开发中,TabHost通常结合TabWidget和FrameLayout一起使用,前者负责显示和管理标签,后者...

    Android TabHost 标签在屏幕左侧样例

    通过学习和理解这个样例,开发者可以灵活地根据应用需求调整TabHost的位置和样式,提升用户体验。 总结来说,自定义Android TabHost的标签位置是一项涉及布局参数调整和样式定制的工作。通过理解TabHost的工作原理...

    Android TabHost 实例源码

    总结,Android TabHost是构建多视图应用程序的强大工具,它允许用户在一个界面上轻松切换不同功能。通过学习和实践,开发者可以掌握如何配置和定制TabHost,从而提升应用的用户体验。在提供的源码实例中,你可以找到...

    Android源码——TabHost内嵌ActivityGroup界面管理源码_new_17.7z

    总结来说,虽然现代Android开发倾向于使用Fragment替代ActivityGroup,但理解TabHost和ActivityGroup的历史以及它们的工作方式对于深入学习Android系统和历史演进非常重要。通过对"Android TabHost内嵌ActivityGroup...

    Android高级应用源码-ViewPager和Tabhost结合,可滑动的tabhost.zip

    总结来说,这个压缩包提供的源码是关于如何在Android应用中使用ViewPager和TabHost实现可滑动的标签页,这对于开发复杂的多视图应用程序非常有用。通过学习和理解这个示例,开发者可以提升自己在Android UI设计和...

    自定义TabWidget的TabHost

    总结一下,自定义TabWidget的TabHost涉及到的关键点有:设置TabHost和TabWidget的布局,初始化TabHost,创建并添加选项卡,以及可能的外观定制。通过这些步骤,开发者可以创建出符合应用需求的个性化选项卡界面,...

    仿新浪微博TabHost菜单

    总结,"仿新浪微博TabHost菜单"的实现涉及Android的布局管理、Intent机制、自定义视图以及事件监听等多个方面。开发者需要熟练掌握这些基础知识,才能创建出富有个性和用户体验良好的App界面。通过这个特效集锦系列...

    租房-TabHost控件使用

    总结一下,这个DEMO展示了如何使用`TabHost`创建一个带有底部选项卡的界面,包括设置布局、初始化`TabHost`、创建`TabSpec`以及处理标签切换事件。尽管`TabHost`在现代Android开发中已不常用,但它仍然是Android开发...

    Tabhost 练习

    总结来说,`TabHost` 是 Android 开发早期常用于实现多标签页界面的组件,虽然现在有更多现代化的替代方案,但理解其工作原理对于开发者而言仍然有价值。通过 "Tabhost 练习" 这样的项目,你可以巩固基础知识,并...

    Tabhost应用

    总结一下,`TabHost`是Android中创建多标签界面的工具,通过`TabWidget`和`FrameLayout`来实现标签的显示和内容的切换。虽然现在有更多现代化的选择,但掌握`TabHost`的基本用法对理解Android界面设计仍然非常重要。...

    TabHost切换动画及基本原理

    总结来说,`TabHost`是一个用于构建多标签界面的组件,而`TabHostWithAnim`资源着重展示了如何添加切换动画,提升用户体验。通过学习这部分内容,开发者不仅可以掌握`TabHost`的基本用法,还能了解到如何利用动画...

    ViewPager和Tabhost结合,可滑动的tabhost.zip

    总结来说,这个压缩包提供的源码示例可以帮助开发者理解如何将`ViewPager`的滑动功能和`TabHost`的标签导航相结合,实现一个既美观又实用的Android应用界面。通过研究源码,可以学习到如何自定义`PagerAdapter`、...

    两种特殊Tabhost实现

    总结来说,本文介绍了如何在Android中实现两种特殊的TabHost,包括模仿网易新闻底部导航栏的FragmentTabHost实现以及自定义TabWidget的方法。通过这些知识,开发者可以创造出更具交互性和视觉吸引力的Android应用。

Global site tag (gtag.js) - Google Analytics