前言:项目第二版刚上线没多久,产品又对需求进行了大改动,以前用的是左滑菜单,现在又要换成底部导航栏,于是今天又苦逼加班了.花了几个小时实现了一个底部导航栏的demo,然后总结一下.写一篇博客.供自己以后参考.也可以给没有做过的朋友进行参考.以后大家有类似的功能就可以在我的demo上就行修改.

一.先上效果图:   本来是打算用FragmentTabHost实现的,但是中间那个按钮有点麻烦,想到我们项目好几个产品经理,并且经常改需求,于是最后决定  用 TextView+Fragment去实现.

二.查看代码实现.代码是我们最好的老师.

主界面布局文件  activity_main.xml   外层一个FrameLayout+ImageView+LinearLayout     TextView选中跟未选中时 图片和颜色 切换都用布局去实现.

1).FrameLayout  用于显示fragment

2).ImageView  显示底部最中间那个图标

3).LinearLayout  显示底部四个图标   我这里用weight分成了5份,第三个控件啥都没有就用View控件占了一个位置

<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" > <FrameLayout
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/view_line"/> <View
android:id="@+id/view_line"
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="#DCDBDB"
android:layout_above="@+id/rl_bottom"/> <LinearLayout
android:id="@+id/rl_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:background="#F2F2F2"
android:orientation="horizontal" > <TextView
android:id="@+id/tv_main"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:drawableTop="@drawable/tab_item_main_img_selector"
android:drawablePadding="@dimen/main_tab_item_image_and_text"
android:focusable="true"
android:gravity="center"
android:text="@string/main"
android:textColor="@drawable/tabitem_txt_sel" /> <TextView
android:id="@+id/tv_dynamic"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:drawableTop="@drawable/tab_item_dynamic_img_selector"
android:drawablePadding="@dimen/main_tab_item_image_and_text"
android:focusable="true"
android:gravity="center"
android:text="@string/dynamic"
android:textColor="@drawable/tabitem_txt_sel" /> <View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" /> <TextView
android:id="@+id/tv_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:drawableTop="@drawable/tab_item_message_img_selector"
android:drawablePadding="@dimen/main_tab_item_image_and_text"
android:focusable="true"
android:gravity="center"
android:text="@string/message"
android:textColor="@drawable/tabitem_txt_sel" /> <TextView
android:id="@+id/tv_person"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:drawableTop="@drawable/tab_item_person_img_selector"
android:drawablePadding="@dimen/main_tab_item_image_and_text"
android:focusable="true"
android:gravity="center"
android:text="@string/person"
android:textColor="@drawable/tabitem_txt_sel"/>
</LinearLayout> <ImageView
android:id="@+id/iv_make"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:paddingBottom="10dp"
android:src="@drawable/icon_tab_make_select"/> </RelativeLayout>

图片选择器   tab_item_main_img_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Non focused states -->
<item android:drawable="@drawable/icon_tab_main_normal" android:state_focused="false" android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="@drawable/icon_tab_main_select" android:state_focused="false" android:state_pressed="false" android:state_selected="true"/>
<!-- Focused states -->
<item android:drawable="@drawable/icon_tab_main_select" android:state_focused="true" android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="@drawable/icon_tab_main_select" android:state_focused="true" android:state_pressed="false" android:state_selected="true"/>
<!-- Pressed -->
<item android:drawable="@drawable/icon_tab_main_select" android:state_pressed="true" android:state_selected="true"/>
<item android:drawable="@drawable/icon_tab_main_select" android:state_pressed="true"/>
</selector>

文字颜色选择器   tabitem_txt_sel.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Non focused states -->
<item android:state_focused="false" android:state_pressed="false" android:state_selected="false" android:color="@color/main_tab_item_text_normal"/>
<item android:state_focused="false" android:state_pressed="false" android:state_selected="true" android:color="@color/main_tab_item_text_select"/> <!-- Focused states -->
<item android:state_focused="true" android:state_pressed="false" android:state_selected="false" android:color="@color/main_tab_item_text_select"/>
<item android:state_focused="true" android:state_pressed="false" android:state_selected="true" android:color="@color/main_tab_item_text_select"/> <!-- Pressed -->
<item android:state_pressed="true" android:state_selected="true" android:color="@color/main_tab_item_text_select"/>
<item android:state_pressed="true" android:color="@color/main_tab_item_text_select"/> </selector>

MainActivity.java   对fragment的切换,底部图标颜色的切换.我也不详细介绍了.代码里面我都有写注释.

/**
* 对fragment的切换,底部图标颜色的切换
* @author ansen
* @create time 2015-09-08
*/
public class MainActivity extends FragmentActivity {
//要切换显示的四个Fragment
private MainFragment mainFragment;
private DynamicFragment dynamicFragment;
private MessageFragment messageFragment;
private PersonFragment personFragment; private int currentId = R.id.tv_main;// 当前选中id,默认是主页 private TextView tvMain, tvDynamic, tvMessage, tvPerson;//底部四个TextView @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); tvMain = (TextView) findViewById(R.id.tv_main);
tvMain.setSelected(true);//首页默认选中
tvDynamic = (TextView) findViewById(R.id.tv_dynamic);
tvMessage = (TextView) findViewById(R.id.tv_message);
tvPerson = (TextView) findViewById(R.id.tv_person); /**
* 默认加载首页
*/
mainFragment = new MainFragment();
getSupportFragmentManager().beginTransaction().add(R.id.main_container, mainFragment).commit(); tvMain.setOnClickListener(tabClickListener);
tvDynamic.setOnClickListener(tabClickListener);
tvMessage.setOnClickListener(tabClickListener);
tvPerson.setOnClickListener(tabClickListener);
findViewById(R.id.iv_make).setOnClickListener(onClickListener);
} private OnClickListener onClickListener=new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_make:
Intent intent=new Intent(MainActivity.this, MakeActivity.class);
startActivity(intent);
break;
}
}
}; private OnClickListener tabClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() != currentId) {//如果当前选中跟上次选中的一样,不需要处理
changeSelect(v.getId());//改变图标跟文字颜色的选中
changeFragment(v.getId());//fragment的切换
currentId = v.getId();//设置选中id
}
}
}; /**
* 改变fragment的显示
*
* @param resId
*/
private void changeFragment(int resId) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();//开启一个Fragment事务 hideFragments(transaction);//隐藏所有fragment
if(resId==R.id.tv_main){//主页
if(mainFragment==null){//如果为空先添加进来.不为空直接显示
mainFragment = new MainFragment();
transaction.add(R.id.main_container,mainFragment);
}else {
transaction.show(mainFragment);
}
}else if(resId==R.id.tv_dynamic){//动态
if(dynamicFragment==null){
dynamicFragment = new DynamicFragment();
transaction.add(R.id.main_container,dynamicFragment);
}else {
transaction.show(dynamicFragment);
}
}else if(resId==R.id.tv_message){//消息中心
if(messageFragment==null){
messageFragment = new MessageFragment();
transaction.add(R.id.main_container,messageFragment);
}else {
transaction.show(messageFragment);
}
}else if(resId==R.id.tv_person){//我
if(personFragment==null){
personFragment = new PersonFragment();
transaction.add(R.id.main_container,personFragment);
}else {
transaction.show(personFragment);
}
}
transaction.commit();//一定要记得提交事务
} /**
* 显示之前隐藏所有fragment
* @param transaction
*/
private void hideFragments(FragmentTransaction transaction){
if (mainFragment != null)//不为空才隐藏,如果不判断第一次会有空指针异常
transaction.hide(mainFragment);
if (dynamicFragment != null)
transaction.hide(dynamicFragment);
if (messageFragment != null)
transaction.hide(messageFragment);
if (personFragment != null)
transaction.hide(personFragment);
} /**
* 改变TextView选中颜色
* @param resId
*/
private void changeSelect(int resId) {
tvMain.setSelected(false);
tvDynamic.setSelected(false);
tvMessage.setSelected(false);
tvPerson.setSelected(false); switch (resId) {
case R.id.tv_main:
tvMain.setSelected(true);
break;
case R.id.tv_dynamic:
tvDynamic.setSelected(true);
break;
case R.id.tv_message:
tvMessage.setSelected(true);
break;
case R.id.tv_person:
tvPerson.setSelected(true);
break;
}
}
}

MainFragment.java  首页有三个页面(关注,推荐,动态),我用到了ViewPager滑动,增加了滑动指示状态.并且给标题栏的三个TextView设置了点击效果.

/**
* 首页
* @author Ansen
* @create time 2015-09-08
*/
public class MainFragment extends Fragment {
private ViewPager vPager;
private List<Fragment> list = new ArrayList<Fragment>();
private MessageGroupFragmentAdapter adapter; private ImageView ivShapeCircle;
private TextView tvFollow,tvRecommend,tvLocation; private int offset=0;//偏移量216 我这边只是举例说明,不同手机值不一样
private int currentIndex=1; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, null); /**
* 初始化三个Fragment 并且填充到ViewPager
*/
vPager = (ViewPager) rootView.findViewById(R.id.viewpager_home);
DynamicFragment dynamicFragment = new DynamicFragment();
MessageFragment messageFragment = new MessageFragment();
PersonFragment personFragment = new PersonFragment();
list.add(dynamicFragment);
list.add(messageFragment);
list.add(personFragment);
adapter = new MessageGroupFragmentAdapter(getActivity().getSupportFragmentManager(), list);
vPager.setAdapter(adapter);
vPager.setOffscreenPageLimit(2);
vPager.setCurrentItem(1);
vPager.setOnPageChangeListener(pageChangeListener); ivShapeCircle = (ImageView) rootView.findViewById(R.id.iv_shape_circle); tvFollow=(TextView) rootView.findViewById(R.id.tv_follow);
tvRecommend=(TextView) rootView.findViewById(R.id.tv_recommend);
tvRecommend.setSelected(true);//推荐默认选中
tvLocation=(TextView) rootView.findViewById(R.id.tv_location); /**
* 标题栏三个按钮设置点击效果
*/
tvFollow.setOnClickListener(clickListener);
tvRecommend.setOnClickListener(clickListener);
tvLocation.setOnClickListener(clickListener); initCursorPosition();
return rootView;
} private OnClickListener clickListener=new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_follow:
//当我们设置setCurrentItem的时候就会触发viewpager的OnPageChangeListener借口,
//所以我们不需要去改变标题栏字体啥的
vPager.setCurrentItem(0);
break;
case R.id.tv_recommend:
vPager.setCurrentItem(1);
break;
case R.id.tv_location:
vPager.setCurrentItem(2);
break;
}
}
}; private void initCursorPosition() {
DisplayMetrics metric = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels;
Matrix matrix = new Matrix(); //标题栏我用weight设置权重 分成5份
//(width / 5) * 2 这里表示标题栏两个控件的宽度
//(width / 10) 标题栏一个控件的2分之一
//7 约等于原点宽度的一半
matrix.postTranslate((width / 5) * 2 + (width / 10)-7,0);//图片平移
ivShapeCircle.setImageMatrix(matrix); //一个控件的宽度 我的手机宽度是1080/5=216 不同的手机宽度会不一样哦
offset=(width / 5);
} /**
* ViewPager滑动监听,用位移动画实现指示器效果
*
* TranslateAnimation 强调一个地方,无论你移动了多少次,现在停留在哪里,你的起始位置从未变化过.
* 例如:我这个demo里面 推荐移动到了同城,指示器也停留到了同城下面,但是指示器在屏幕上的位置还是推荐下面.
*/
private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {
@Override
public void onPageSelected(int index) {
changeTextColor(index);
translateAnimation(index);
} @Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
} @Override
public void onPageScrollStateChanged(int arg0) {
}
}; /**
* 改变标题栏字体颜色
* @param index
*/
private void changeTextColor(int index){
tvFollow.setSelected(false);
tvRecommend.setSelected(false);
tvLocation.setSelected(false); switch (index) {
case 0:
tvFollow.setSelected(true);
break;
case 1:
tvRecommend.setSelected(true);
break;
case 2:
tvLocation.setSelected(true);
break;
}
} /**
* 移动标题栏点点点...
* @param index
*/
private void translateAnimation(int index){
TranslateAnimation animation = null;
switch(index){
case 0:
if(currentIndex==1){//从推荐移动到关注 X坐标向左移动216
animation=new TranslateAnimation(0,-offset,0,0);
}else if (currentIndex == 2) {//从同城移动到关注 X坐标向左移动216*2 记住起始x坐标是同城那里
animation = new TranslateAnimation(offset, -offset, 0, 0);
}
break;
case 1:
if(currentIndex==0){//从关注移动到推荐 X坐标向右移动216
animation=new TranslateAnimation(-offset,0,0,0);
}else if(currentIndex==2){//从同城移动到推荐 X坐标向左移动216
animation=new TranslateAnimation(offset, 0,0,0);
}
break;
case 2:
if (currentIndex == 0) {//从关注移动到同城 X坐标向右移动216*2 记住起始x坐标是关注那里
animation = new TranslateAnimation(-offset, offset, 0, 0);
} else if(currentIndex==1){//从推荐移动到同城 X坐标向右移动216
animation=new TranslateAnimation(0,offset,0,0);
}
break;
}
animation.setFillAfter(true);
animation.setDuration(300);
ivShapeCircle.startAnimation(animation); currentIndex=index;
}
}

首页显示的MainFragment.java的布局文件  fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:id="@+id/ll_title"
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="#00ceaa"
android:orientation="vertical" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal" > <View
android:id="@+id/view_empty"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" /> <TextView
android:id="@+id/tv_follow"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="5dp"
android:text="关注"
android:gravity="center_horizontal"
android:textColor="@drawable/main_title_txt_sel"
android:textSize="20sp" /> <TextView
android:id="@+id/tv_recommend"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="5dp"
android:text="推荐"
android:gravity="center_horizontal"
android:textColor="@drawable/main_title_txt_sel"
android:textSize="20sp" /> <TextView
android:id="@+id/tv_location"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="5dp"
android:text="同城"
android:gravity="center_horizontal"
android:textColor="@drawable/main_title_txt_sel"
android:textSize="20sp" /> <View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout> <ImageView
android:id="@+id/iv_shape_circle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:scaleType="matrix"
android:src="@drawable/shape_circle" />
</LinearLayout> <android.support.v4.view.ViewPager
android:id="@+id/viewpager_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/ll_title" /> </RelativeLayout>

MessageGroupFragmentAdapter.java    ViewPager的适配器.

public class MessageGroupFragmentAdapter extends FragmentStatePagerAdapter {
private List<Fragment>list;
public MessageGroupFragmentAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.list = list;
} public MessageGroupFragmentAdapter(FragmentManager fm) {
super(fm);
} @Override
public Fragment getItem(int arg0) {
return list.get(arg0);
} @Override
public int getCount() {
return list.size();
}
}

这个demo的核心代码就在这里了,其他几个Fragment的代码跟布局文件我就不贴出来了....有需要的可以去下载我的源码.....又到了10点半了....回家.....

点击下载源码

相关文章:EventBus实现activity跟fragment交互数据

后记:如果你运行之后首页会出现空白的情况,viewpager滑动也会出现问题了,那是MainFragment类初始化viewpager的adpater有问题.

修改后代码如下,大概在MainFragment中125行:

adapter = new MessageGroupFragmentAdapter(getChildFragmentManager(), list);

TextView+Fragment实现底部导航栏的更多相关文章

  1. [置顶] xamarin android Fragment实现底部导航栏

    前段时间写了篇关于Fragment的文章,介绍了基础的概念,用静态和动态的方式加载Fragment  Xamarin Android Fragment的两种加载方式.下面的这个例子介绍xamarin ...

  2. Android学习笔记- Fragment实例 底部导航栏的实现

    1.要实现的效果图以及工程目录结构: 先看看效果图吧: 接着看看我们的工程的目录结构: 2.实现流程: Step 1:写下底部选项的一些资源文件 我们从图上可以看到,我们底部的每一项点击的时候都有不同 ...

  3. 使用BottomNavigationView+ViewPager+Fragment的底部导航栏

    2019独角兽企业重金招聘Python工程师标准>>> 使用BottomNavigationView做底部工具栏,使用ViewPager做页面切换,使用Fragment完成每个页面的 ...

  4. 使用fragment添加底部导航栏

    切记:fragment一定要放在framlayout中,不然不会被替换完全(就是切换之后原来的fagment可能还会存在) main.xml <LinearLayout xmlns:androi ...

  5. 二、Fragment+RadioButton实现底部导航栏

    在App中经常看到这样的tab底部导航栏   那么这种效果是如何实现,实现的方式有很多种,最常见的就是使用Fragment+RadioButton去实现.下面我们来写一个例子 首先我们先在activi ...

  6. AndroidStudio制作底部导航栏以及用Fragment实现切换功能

    前言 大家好,给大家带来AndroidStudio制作底部导航栏以及用Fragment实现切换功能的概述,希望你们喜欢 学习目标 AndroidStudio制作底部导航栏以及用Fragment实现切换 ...

  7. Android商城开发系列(三)——使用Fragment+RadioButton实现商城底部导航栏

    在商城第一篇的开篇当中,我们看到商城的效果图里面有一个底部导航栏效果,如下图所示: 今天我们就来实现商城底部导航栏,最终效果图如下所示:   那么这种效果是如何实现,实现的方式有很多种,最常见的就是使 ...

  8. Android_ViewPager+Fragment实现页面滑动和底部导航栏

    1.Xml中底部导航栏由一个RadioGroup组成,其上是ViewPager. <?xml version="1.0" encoding="utf-8" ...

  9. Android底部导航栏——FrameLayout + RadioGroup

    原创文章,转载请注明出处http://www.cnblogs.com/baipengzhan/p/6285881.html Android底部导航栏有多种实现方式,本文详细介绍FrameLayout ...

随机推荐

  1. 输出日志实例改成用Spring的AOP来实现

    1.采用Interception Around通知的形式实现 Interception Around通知会在Join Point的前后执行,实现Interception Around通知的类需要实现接 ...

  2. Webform Application传值 ViewState

    Application:所有的会话共享一个Application空间,任何一个人改变Application的内容,其他人都会发现被改变了.Application中的内容不会被自动释放 存放位置:服务端 ...

  3. pythonchallenge 解谜 Level 5

    第五关的确很坑爹... 不过,根据之前的思路,我想着是把信息放在了 “源码” 中. 翻了下源码.有用的东西在以下部分. <html><head> <title>pe ...

  4. .Net客户端监听ZooKeeper节点数据变化

    一个很简单的例子,用途是监听zookeeper中某个节点数据的变化,具体请参见代码中的注释 using System; using System.Collections.Generic; using ...

  5. ABP理论学习之NHibernate集成

    返回总目录 本篇目录 Nuget包 配置 实体映射 仓储 仓储基类 实现仓储 自定义仓储方法 阅读其他 ABP可以使用任何ORM框架工作,并且已经内置了NHibernate集成.这篇文章会解释如何在A ...

  6. 程序猿尤其是.NET程序员所需要注意的网站资源

    我觉得一个程序员 需要 对 技术 和 行业 两方面同时具有极大热情和注意力才能让自己在一个新的台阶. 有些程序员就是对技术有着极大的热情但是行业完全不注意,这样我感觉只能成为一个专家,并不能让自己真正 ...

  7. Python模拟HttpRequest的方法总结

    Python可以说是爬网的利器,本文主要介绍了一些python来模拟http请求的一些方法和技巧. Python处理请求的类库有两个,urllib,urllib2. 这两个类库并不是一个类库的两个不同 ...

  8. AD域内DNS服务器如何解析公网域名

    原创地址:http://www.cnblogs.com/jfzhu/p/4022999.html 转载请注明出处 AD域内需要有DNS服务器,用于解析域内的计算机名,但是域内的计算如何解析公网的域名呢 ...

  9. angularjs 2.0 快速开始

    前言 angularjs2.0 如果发布,公司的项目会基于2.0开发,在1.0的时候就踩了好多坑,趁这2.0还没正式发布,赶紧踩下坑. 这篇文章是参考angularjs2.0 官方文档写的,开发环境需 ...

  10. Atitti 存储引擎支持的国内点与特性attilax总结

    Atitti 存储引擎支持的国内点与特性attilax总结 存储引擎处理的事情: · 并发性:某些应用程序比其他应用程序具有很多的颗粒级锁定要求(如行级锁定). · 事务支持:并非所有的应用程序都需要 ...