最近想弄一个双导航功能,查看了许多资料,总算是实现了功能,这边就算是给自己几个笔记吧!
先来看看效果
那么就开始实现了!
底部导航栏我选择用FragmentTabHost+Fragment来实现,这个方法我觉得挺好用的,代码量也不多
首先是开始的activity_main.xml
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="${relativePackage}.${activityClass}" >
- <FrameLayout
- android:id="@+id/main_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_above="@+id/main_tab"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true" >
- </FrameLayout>
- <view
- android:id="@+id/main_tab"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- class="android.support.v4.app.FragmentTabHost" />
- </RelativeLayout>
其中我是直接拉的view所以是形成的FragmentTabHost
也可以直接在xml文件里面写
<Android.support.v4.view.FragmentTabHost >
</android.support.v4.view.FragmentTabHost>
这xml文件就一个view加一个tab view用来显示碎片,tab用来放置底部按钮的数量
再来是tab_foot.xml
- <?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="match_parent"
- android:background="#F6F6F6"
- android:gravity="center"
- android:orientation="vertical" >
- <ImageView
- android:id="@+id/foot_iv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/home1" />
- <TextView
- android:id="@+id/foot_tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:text="首页"
- android:textColor="@color/tab_color" />
- </LinearLayout>
显示效果。
再来是MainActivity的代码
- package com.gjn.mynavigation;
- import android.os.Bundle;
- import android.support.v4.app.FragmentActivity;
- import android.support.v4.app.FragmentTabHost;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.Window;
- import android.widget.ImageView;
- import android.widget.TabWidget;
- import android.widget.TextView;
- import android.widget.TabHost.OnTabChangeListener;
- import android.widget.TabHost.TabSpec;
- public class MainActivity extends FragmentActivity implements OnTabChangeListener {
- private FragmentTabHost mTabHost;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.activity_main);
- //初始化FragmentTabHost
- initHost();
- //初始化底部导航栏
- initTab();
- //默认选中
- mTabHost.onTabChanged(TabDb.getTabsTxt()[0]);
- }
- private void initTab() {
- String[] tabs = TabDb.getTabsTxt();
- for (int i = 0; i < tabs.length; i++) {
- //新建TabSpec
- TabSpec tabSpec = mTabHost.newTabSpec(TabDb.getTabsTxt()[i]);
- //设置view
- View view = LayoutInflater.from(this).inflate(R.layout.tabs_foot, null);
- ((TextView) view.findViewById(R.id.foot_tv)).setText(TabDb.getTabsTxt()[i]);
- ((ImageView) view.findViewById(R.id.foot_iv)).setImageResource(TabDb.getTabsImg()[i]);
- tabSpec.setIndicator(view);
- //加入TabSpec
- mTabHost.addTab(tabSpec,TabDb.getFramgent()[i],null);
- }
- }
- /***
- * 初始化Host
- */
- private void initHost() {
- mTabHost = (FragmentTabHost) findViewById(R.id.main_tab);
- //调用setup方法 设置view
- mTabHost.setup(this, getSupportFragmentManager(),R.id.main_view);
- //去除分割线
- mTabHost.getTabWidget().setDividerDrawable(null);
- //监听事件
- mTabHost.setOnTabChangedListener(this);
- }
- @Override
- public void onTabChanged(String arg0) {
- //从分割线中获得多少个切换界面
- TabWidget tabw = mTabHost.getTabWidget();
- for (int i = 0; i < tabw.getChildCount(); i++) {
- View v = tabw.getChildAt(i);
- TextView tv = (TextView) v.findViewById(R.id.foot_tv);
- ImageView iv = (ImageView) v.findViewById(R.id.foot_iv);
- //修改当前的界面按钮颜色图片
- if (i == mTabHost.getCurrentTab()) {
- tv.setTextColor(getResources().getColor(R.color.tab_light_color));
- iv.setImageResource(TabDb.getTabsImgLight()[i]);
- }else{
- tv.setTextColor(getResources().getColor(R.color.tab_color));
- iv.setImageResource(TabDb.getTabsImg()[i]);
- }
- }
- }
- }
以下是TabDb类
- package com.gjn.mynavigation;
- public class TabDb {
- /***
- * 获得底部所有项
- */
- public static String[] getTabsTxt() {
- String[] tabs = {"首页","交易","地点","我的"};
- return tabs;
- }
- /***
- * 获得所有碎片
- */
- public static Class[] getFramgent(){
- Class[] cls = {OneFm.class,TwoFm.class,ThreeFm.class,FourFm.class};
- return cls ;
- }
- /***
- * 获得所有点击前的图片
- */
- public static int[] getTabsImg(){
- int[] img = {R.drawable.home1,R.drawable.glod1,R.drawable.xc1,R.drawable.user1};
- return img ;
- }
- /***
- * 获得所有点击后的图片
- */
- public static int[] getTabsImgLight(){
- int[] img = {R.drawable.home2,R.drawable.glod2,R.drawable.xc2,R.drawable.user2};
- return img ;
- }
- }
现在来实现顶部导航栏,看了许多最后使用了RadioGroup+ViewPager来实现
首先是为第一个碎片设计一个xml布局
fm_one.xml
- <?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="match_parent"
- android:orientation="vertical" >
- <HorizontalScrollView
- android:id="@+id/one_hv"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="none" >
- <RadioGroup
- android:id="@+id/one_rg"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
- </RadioGroup>
- </HorizontalScrollView>
- <view
- android:id="@+id/one_view"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- class="android.support.v4.view.ViewPager" />
- </LinearLayout>
之后吧导航栏的每个项的布局
tab_rb.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/tab_rb_selector"
- android:button="@null"
- android:paddingBottom="10dp"
- android:paddingLeft="15dp"
- android:paddingRight="15dp"
- android:paddingTop="10dp"
- android:text="今日" >
- </RadioButton>
tab_rb_selector.xml
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <!-- 点击 -->
- <item android:state_checked="true">
- <layer-list >
- <item >
- <shape android:shape="rectangle">
- <stroke android:width="5dp" android:color="@color/tab_light_color"/>
- </shape>
- </item>
- <item android:bottom="5dp">
- <shape android:shape="rectangle">
- <solid android:color="#fff"/>
- </shape>
- </item>
- </layer-list>
- </item>
- <!-- 默认 -->
- <item >
- <shape >
- <solid android:color="#fafafa"/>
- </shape>
- </item>
- </selector>
最后来实现OneFm类
- package com.gjn.mynavigation;
- import java.util.ArrayList;
- import java.util.List;
- import android.os.Bundle;
- import android.support.annotation.Nullable;
- import android.support.v4.app.Fragment;
- import android.support.v4.view.ViewPager;
- import android.support.v4.view.ViewPager.OnPageChangeListener;
- import android.util.DisplayMetrics;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.HorizontalScrollView;
- import android.widget.RadioButton;
- import android.widget.RadioGroup;
- import android.widget.RadioGroup.LayoutParams;
- import android.widget.RadioGroup.OnCheckedChangeListener;
- public class OneFm extends Fragment implements OnPageChangeListener {
- private View view;
- private RadioGroup rg_;
- private ViewPager vp_;
- private HorizontalScrollView hv_;
- private List<Fragment> newsList = new ArrayList<Fragment>();
- private OneFmAdapter adapter;
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- if (view == null) {
- //初始化view
- view = inflater.inflate(R.layout.fm_one, container,false);
- rg_ = (RadioGroup) view.findViewById(R.id.one_rg);
- vp_ = (ViewPager) view.findViewById(R.id.one_view);
- hv_ = (HorizontalScrollView) view.findViewById(R.id.one_hv);
- //设置RadioGroup点击事件
- rg_.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int id) {
- vp_.setCurrentItem(id);
- }
- });
- //初始化顶部导航栏
- initTab(inflater);
- //初始化viewpager
- initView();
- }
- /*
- * 底部导航栏切换后 由于没有销毁顶部设置导致如果没有重新设置view
- * 导致底部切换后切回顶部页面数据会消失等bug
- * 以下设置每次重新创建view即可
- */
- ViewGroup parent = (ViewGroup) view.getParent();
- if (parent != null) {
- parent.removeView(view);
- }
- return view;
- }
- /***
- * 初始化viewpager
- */
- private void initView() {
- List<HTab> hTabs = HTabDb.getSelected();
- for (int i = 0; i < hTabs.size(); i++) {
- OneFm1 fm1 = new OneFm1();
- Bundle bundle = new Bundle();
- bundle.putString("name", hTabs.get(i).getName());
- fm1.setArguments(bundle);
- newsList.add(fm1);
- }
- //设置viewpager适配器
- adapter = new OneFmAdapter(getActivity().getSupportFragmentManager(),newsList);
- vp_.setAdapter(adapter);
- //两个viewpager切换不重新加载
- vp_.setOffscreenPageLimit(2);
- //设置默认
- vp_.setCurrentItem(0);
- //设置viewpager监听事件
- vp_.setOnPageChangeListener(this);
- }
- /***
- * 初始化头部导航栏
- * @param inflater
- */
- private void initTab(LayoutInflater inflater) {
- List<HTab> hTabs = HTabDb.getSelected();
- for (int i = 0; i < hTabs.size(); i++) {
- //设置头部项布局初始化数据
- RadioButton rbButton = (RadioButton) inflater.inflate(R.layout.tab_rb, null);
- rbButton.setId(i);
- rbButton.setText(hTabs.get(i).getName());
- LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- //加入RadioGroup
- rg_.addView(rbButton,params);
- }
- //默认点击
- rg_.check(0);
- }
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
- @Override
- public void onPageSelected(int id) {
- setTab(id);
- }
- /***
- * 页面跳转切换头部偏移设置
- * @param id
- */
- private void setTab(int id) {
- RadioButton rbButton = (RadioButton) rg_.getChildAt(id);
- //设置标题被点击
- rbButton.setChecked(true);
- //偏移设置
- int left = rbButton.getLeft();
- int width = rbButton.getMeasuredWidth();
- DisplayMetrics metrics = new DisplayMetrics();
- getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
- int screenWidth = metrics.widthPixels;
- //移动距离= 左边的位置 + button宽度的一半 - 屏幕宽度的一半
- int len = left + width / 2 - screenWidth / 2;
- //移动
- hv_.smoothScrollTo(len, 0);
- }
- }
数据类
HTab.Java
- package com.gjn.mynavigation;
- /***
- * 头部Tab属性
- *
- */
- public class HTab {
- private String name;
- public HTab(String name) {
- super();
- this.setName(name);
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- package com.gjn.mynavigation;
- import java.util.ArrayList;
- import java.util.List;
- public class HTabDb {
- private static final List<HTab> Selected = new ArrayList<HTab>();
- static{
- Selected.add(new HTab("今日"));
- Selected.add(new HTab("头条"));
- Selected.add(new HTab("娱乐"));
- Selected.add(new HTab("财经"));
- Selected.add(new HTab("军事"));
- Selected.add(new HTab("科技"));
- Selected.add(new HTab("时尚"));
- Selected.add(new HTab("体育"));
- }
- /***
- * 获得头部tab的所有项
- */
- public static List<HTab> getSelected() {
- return Selected;
- }
- }
OneFm1.java
- package com.gjn.mynavigation;
- import android.os.Bundle;
- import android.support.annotation.Nullable;
- import android.support.v4.app.Fragment;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.TextView;
- public class OneFm1 extends Fragment {
- private String name;
- @Override
- public void setArguments(Bundle args) {
- name = args.getString("name");
- }
- @Override
- public View onCreateView(LayoutInflater inflater,
- @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment, container,false);
- ((TextView) view.findViewById(R.id.fm_text)).setText(name);
- return view;
- }
- }
最后把fragment.xml贴下,就是每个碎片最默认的显示页面罢了
- <?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="match_parent"
- android:gravity="center"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/fm_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Large Text"
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </LinearLayout>