您的位置:首页 > 其它

FragmentTabHost实现底部导航菜单

2015-12-27 23:32 573 查看
闲话少说直接说正题,最近一直在做底部导航菜单的编写,尝试了各种办法(自定义控件等),实现了底部导航菜单之后与fragment结合的时候又遇到很多问题,还要写方法去showFragment和hideFragment,这个过程虽说不难但是很繁琐,加大了代码量。

底部导航菜单实现的方法 ,介绍实现的三种方法(从最初的到现在最新的方法)

先看实现效果,效果中看到导航两行文字 是因为图片是用的自带文字的icon ,实际使用中根据需求确定





本文主要介绍FragmentTabHost+Fragment的实现方式:分三步实现

findViewById

setup()

addTab

下边给出官方事例

/**
* This demonstrates how you can implement switching between the tabs of a
* TabHost through fragments, using FragmentTabHost.
*/
public class FragmentTabs extends FragmentActivity {
private FragmentTabHost mTabHost;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.fragment_tabs);
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
FragmentStackSupport.CountingFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
LoaderCursorSupport.CursorLoaderListFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
LoaderCustomSupport.AppListFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
}
}


this can also be used inside of a fragment through fragment nesting:

import com.example.android.supportv4.R;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentTabsFragmentSupport extends Fragment {
private FragmentTabHost mTabHost;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mTabHost = new FragmentTabHost(getActivity());
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1);

mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
FragmentStackSupport.CountingFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
LoaderCursorSupport.CursorLoaderListFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
LoaderCustomSupport.AppListFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);

return mTabHost;
}

@Override
public void onDestroyView() {
super.onDestroyView();
mTabHost = null;
}
}


以上是官方给了在activity和fragment的实现方法,但实现中我们对其封装处理。

下边给出我们的使用方法

/**
* 初始换tabhost
*/
private void initTab() {
//把需要用到的title    icon    fragment封装到tabbean对象
Tab home = new Tab(R.string.home, R.drawable.home_btn_selector, HomeFragment.class);
Tab find = new Tab(R.string.find, R.drawable.faxian_btn_selector, FindFragment.class);
Tab cart = new Tab(R.string.cart, R.drawable.cart_btn_selector, CartFragment.class);
Tab category = new Tab(R.string.category, R.drawable.category_btn_selector, CategoryFragment.class);
Tab mine = new Tab(R.string.mine, R.drawable.mine_btn_selector, MineFragment.class);
tabs.add(home);
tabs.add(find);
tabs.add(cart);
tabs.add(category);
tabs.add(mine);

mInflater = LayoutInflater.from(this);
//获取FragmentTabHost对象
mTabHost = (FragmentTabHost) findViewById(R.id.tabhost);
//设置setup方法
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
//取消默认的Tab间的竖线显示
mTabHost.getTabWidget().setShowDividers(LinearLayout.SHOW_DIVIDER_NONE);
//设置默认选中第一个
mTabHost.setCurrentTab(0);

//循环把自定义的tab添加上去
for (Tab tab : tabs) {
TabHost.TabSpec tabSpec = mTabHost.newTabSpec(getString(tab.getTitle()));
tabSpec.setIndicator(buildIndicator(tab));
mTabHost.addTab(tabSpec, tab.getFragment(), null);
}

}

/**
* 构建Indicator
* @param tab
* @return
*/
private View buildIndicator(Tab tab) {
View view = mInflater.inflate(R.layout.tab_item, null);
ImageView icon = (ImageView) view.findViewById(R.id.icon_iv);
TextView title = (TextView) view.findViewById(R.id.title_tv);

icon.setBackgroundResource(tab.getIcon());
title.setText(tab.getTitle());

return view;
}


Tab文件

public class Tab {
private int title;
private int icon;
private Class fragment;

public Tab(int title, int icon, Class fragment) {
this.title = title;
this.icon = icon;
this.fragment = fragment;
}
}


布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

//这是我们替换fragment的真正布局
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp">

</FrameLayout>
<android.support.v4.app.FragmentTabHost
android:id="@+id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content">
//官方建议加一个这个布局文件 虽然用不到(那就按照官方这样写)
<FrameLayout
android:id="@+id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp">

</FrameLayout>
</android.support.v4.app.FragmentTabHost>
</LinearLayout>


导航字体颜色选择器,选中时候显示

注意:这个文件要建在res资源文件下的color文件里

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:color="#eb4f38" android:state_selected="true"/>
<item android:color="#eb4f38" android:state_active="true"/>
<item android:color="#a9b7b7" android:state_selected="false"/>
<item android:color="#a9b7b7" android:state_active="false"/>

</selector>


图片选择器的文件

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/main_bottom_tab_home_normal" android:state_selected="true" />
<item android:drawable="@mipmap/main_bottom_tab_home_normal" android:state_pressed="true" />
<item android:drawable="@mipmap/main_bottom_tab_home_normal" android:state_checked="true" />
<item android:drawable="@mipmap/main_bottom_tab_home_focus" />
</selector>


tab_item布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#888888"
android:orientation="vertical"
android:padding="2dp">

<ImageView
android:id="@+id/icon_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />

<TextView
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
//调取自定义的字体颜色选择器
android:textColor="@color/selector_tab_text"
android:textSize="10sp" />
</LinearLayout>


这样实现后会发现,每次tab间的切换fragment都会重新调用onCreateView方法重绘UI.

解决方法,在fragment onCreateView 里缓存View.

private View rootView;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

if (rootView == null) {
rootView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_home, container, false);
}
// 缓存的rootView需要判断是否已经被加过parent,如果有parent需要从parent删除,
// 要不然会发生这个rootview已经有parent的错误。
ViewGroup parent = ((ViewGroup) rootView.getParent());
if (parent != null) {
parent.removeView(rootView);
}
return rootView;
}


demo源码下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: