Android-实现顶部+底部双导航界面功能

最近想弄一个双导航功能,查看了许多资料,总算是实现了功能,这边就算是给自己几个笔记吧!

先来看看效果

那么就开始实现了!

底部导航栏我选择用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>

这是每个底部按钮的布局设置的xml文件

显示效果。

再来是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类是用来设置导航栏的数据和图片切换时候的资源

以下是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>

设置顶部导航栏和显示view

之后吧导航栏的每个项的布局

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>

其中设置selector文件来控制点击和未点击的状态

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;
	}

}

HTabDb.java

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里面并且实现了切换功能

最后把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>

总结:

算是一个笔记记录吧!一段时间没更新了,由于刚毕业断了一个时间,走走停停留下一些自己的记录,就怕自己以后要写忘了。

下载地址:点击打开链接

时间: 2024-07-30 21:56:40

Android-实现顶部+底部双导航界面功能的相关文章

Android典型界面设计-访网易新闻实现双导航tab切换

一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客Android典型界面设计2(FragmentTabHost+Fragment实现底部tab切换)基础之上和Android典型界面设计1(ViewPage+Fragment实现区域顶部tab滑动切换)整合应用实现.查看两篇博客请点击:http://www.cnblogs.com/jerehedu/p

Android典型界面设计(3)——访网易新闻实现双导航tab切换

一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客Android典型界面设计2(FragmentTabHost+Fragment实现底部tab切换)基础之上和Android典型界面设计1(ViewPage+Fragment实现区域顶部tab滑动切换)整合应用实现.查看两篇博客请点击:http://www.cnblogs.com/jerehedu/p

Android典型界面设计(7) ——DrawerLayout+Fragement+ViewPager+PagerTabStrip实现双导航

一.问题描述 在Android典型界面设计(3)的我们实现了双导航效果,即外层底部导航和内部区域的头部导航,如网易新闻等很多应用采用了这种导航,但Google提供DrawerLayout可实现抽屉式导航,建议使用DrawerLayout代替底部导航,下面我们就使用官方提供的DrawerLayout+Fragement+ViewPager+PagerTabStrip实现下图效果: 二.本例相关技术 1. DrawerLayout 抽屉式导航 2. Fragment管理 3. ViewPager和P

Android仿小米商城底部导航栏之二(BottomNavigationBar、ViewPager和Fragment的联动使用)

简介 在前文<Android仿小米商城底部导航栏(基于BottomNavigationBar)>我们使用BottomNavigationBar控件模仿实现了小米商城底部导航栏效果.接下来更进一步的,我们将通过BottomNavigationBar控件和ViewPager空间的联动使用来实现主界面的滑动导航. 导航是移动应用最重要的方面之一,对用户体验是良好还是糟糕起着至关重要的作用.好的导航可以让一款应用更加易用并且让用户快速上手.相反,糟糕的应用导航很容易让人讨厌,并遭到用户的抛弃.为了打造

Android 利用ViewPager实现底部圆点导航左右滑动效果以及Fragment页面切换

上一篇博文我们介绍了利用ViewPager和Fragment实现顶部滑块左右滑动效果,具体参考(http://blog.csdn.net/a123demi/article/details/39480385). 而本篇博文将实例讲解利用ViewPager实现底部圆点导航左右滑动效果,以及被滑动界面实现监听事件,同时通过Fragment实现页面的切换. 对于该效果的实现,需要实现以下几个问题: 1. 底部圆点加载和实现方法? 2. 怎样实现左右滑动效果? 3. 被滑动页面,怎样实现监听事件? 4.

Android 底部TabActivity(3)——ActivityGroup|顶部底部均有Tab标签之二

上一篇使用过时的ActivityGroup简单实现了顶部底部均有Tab标签的效果,是页面底部只有文字的样式,今天想完善一下效果,底部实现文字加图标的样式. 本文属于半成品,本来想着放弃的,想着先放博客吧,好歹也是一种思路,以后作参考用!追求完美效果的可以忽略本篇,我会在后续文章中实现更优的效果! 先看下效果图 首先是主页面MainActivity.java,这种方式其实不是真正意义上的Tab,只是实现了这样的效果.底部用了GridView实现三个切换开关,放到页面底部. package sun.

Android开发之Navigationdrawer导航抽屉功能的实现(源代码分享)

导航抽屉(navigationdrawer)是一个从屏幕左边滑入的面板,用于显示应用的主要导航项目.用户可以通过在屏幕左边缘滑入或者触摸操作栏的应用图标打开导航抽屉.导航抽屉覆盖在内容之上,但不覆盖操作栏.当导航抽屉完全打开后,操作栏的标题需要更换为应用的名称,而不是显示当前视图的名称,并且关闭所有和当前视图相关的操作按钮.操作栏的"更多操作"菜单按钮不需要关闭,以保证用户可以随时访问"设置"和"帮助".下面我们就来实现导航抽屉的功能. Layo

Android 手机卫士--导航界面2

本文地址:http://www.cnblogs.com/wuyudong/p/5947504.html,转载请注明出处. 在之前的文章中,实现了导航界面1布局编写与相关的逻辑代码,如下图所示: 点击“下一页” public class Setup1Activity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

Xamarin.Forms 3.1.0+版本 Android 原生支持底部导航栏啦

Xamarin.Forms 3.1.0+版本 Android 原生支持底部导航栏啦 Xamarin.Forms 3.1.0以上版本终于支持Android底部导航栏啦,可以不用第三方的支持库了. https://developer.xamarin.com/releases/xamarin-forms/xamarin-forms-3.1/3.1.0/ C#代码: On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom); Xaml代码: