android fragmenttabhost 监听点击事件,Android FragmentTabHost分析

Android FragmentTabHost分析

Android

WHATFragmentTabHost extends TabHost

基本功能继承了TabHost,Content使用Fragment展示。实现底部、顶部Tab,其他区域展示内容的效果。

// ContentView

privateFrameLayoutmRealTabContent;

privateContextmContext;

privateFragmentManagermFragmentManager;

// ContentView的ID

privateintmContainerId;

privateTabHost.OnTabChangeListenermOnTabChangeListener;

// 上次切换的Tab信息

privateTabInfomLastTab;

privatebooleanmAttached;

WHY

实现了TabHost.TabContentFactoryFactory

staticclassDummyTabFactoryimplementsTabHost.TabContentFactory{

privatefinalContextmContext;

publicDummyTabFactory(Contextcontext){

mContext=context;

}

@Override

publicViewcreateTabContent(Stringtag){

// 这个貌似没有用到,真实的ContentView是mRealTabContent,其ID就是mContainerId

Viewv=newView(mContext);

v.setMinimumWidth(0);

v.setMinimumHeight(0);

returnv;

}

}

初始化

privatevoidinitFragmentTabHost(Contextcontext,AttributeSetattrs){

finalTypedArraya=context.obtainStyledAttributes(attrs,

newint[]{android.R.attr.inflatedId},0,0);

// 指定inflatedId

mContainerId=a.getResourceId(0,0);

a.recycle();

super.setOnTabChangedListener(this);

}

确保有TabWidget和ConentView

// 自动生成ViewTree,上面是TabWidget,下面是Content

privatevoidensureHierarchy(Contextcontext){

// If owner hasn't made its own view hierarchy, then as a convenience

// we will construct a standard one here.

if(findViewById(android.R.id.tabs)==null){

LinearLayoutll=newLinearLayout(context);

ll.setOrientation(LinearLayout.VERTICAL);

addView(ll,newFrameLayout.LayoutParams(

ViewGroup.LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.MATCH_PARENT));

TabWidgettw=newTabWidget(context);

tw.setId(android.R.id.tabs);

tw.setOrientation(TabWidget.HORIZONTAL);

ll.addView(tw,newLinearLayout.LayoutParams(

ViewGroup.LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT,0));

FrameLayoutfl=newFrameLayout(context);

fl.setId(android.R.id.tabcontent);

ll.addView(fl,newLinearLayout.LayoutParams(0,0,0));

mRealTabContent=fl=newFrameLayout(context);

mRealTabContent.setId(mContainerId);

ll.addView(fl,newLinearLayout.LayoutParams(

LinearLayout.LayoutParams.MATCH_PARENT,0,1));

}

}

// 确保必须有指定的mContainerId

privatevoidensureContent(){

if(mRealTabContent==null){

mRealTabContent=(FrameLayout)findViewById(mContainerId);

if(mRealTabContent==null){

thrownewIllegalStateException(

"No tab content FrameLayout found for id "+mContainerId);

}

}

}

如果布局中的FragmentTabHost有指定android:inflatedId则使用这个方法初始化,一般是使用布局设置的情况。setup(Context context, FragmentManager manager)

或者指定一个containerId,一般用在java代码中写布局的情况。setup(Context context, FragmentManager manager, int containerId)

切换Tab,通过FragmentManager的事物来管理的

publicvoidonTabChanged(StringtabId){

if(mAttached){

finalFragmentTransactionft=doTabChanged(tabId,null);

if(ft!=null){

ft.commit();

}

}

if(mOnTabChangeListener!=null){

mOnTabChangeListener.onTabChanged(tabId);

}

}

@Nullable

privateFragmentTransactiondoTabChanged(@NullableStringtag,

@NullableFragmentTransactionft){

finalTabInfonewTab=getTabInfoForTag(tag);

if(mLastTab!=newTab){

if(ft==null){

ft=mFragmentManager.beginTransaction();

}

if(mLastTab!=null){

if(mLastTab.fragment!=null){

ft.detach(mLastTab.fragment);

}

}

if(newTab!=null){

if(newTab.fragment==null){

newTab.fragment=Fragment.instantiate(mContext,

newTab.clss.getName(),newTab.args);

ft.add(mContainerId,newTab.fragment,newTab.tag);

}else{

ft.attach(newTab.fragment);

}

}

mLastTab=newTab;

}

returnft;

}

每次新旧的切换是使用detach和attach,所以会造成Fragment的生命周期(onCreatedView)重复执行,导致每次都会重新加载布局等问题。

解决方案有2个:

1. 重写doTabChanged方法,使用FragmentTransaction的show/hide来切换显示、隐藏。

2. 在Fragment的onCreateView中判断这个rootView是否已经存在,不存在才加载View。

HOW TO USE

布局中使用,基本上和TabHost一样,只是把TabHost控件换成了FragmentTabHost

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@android:id/tabcontent"

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1"/>

android:id="@android:id/tabs"

android:layout_width="match_parent"

android:layout_height="48dp"/>

在Java代码中设置

FragmentTabHosttabHost=(FragmentTabHost)findViewById(android.R.id.tabhost);

// 指定content id

// tabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);

// content id = xml 中设置的inflatedId

tabHost.setup(this,getSupportFragmentManager());

TabHost.TabSpectabSpec1=tabHost.newTabSpec("TabA").setIndicator("TabA");

TabHost.TabSpectabSpec2=tabHost.newTabSpec("TabB").setIndicator("TabB");

tabHost.addTab(tabSpec1,Tab1Fragment.class,null);

tabHost.addTab(tabSpec2,Tab2Fragment.class,null);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值