TextView+Fragment实现底部导航栏

前言:项目第二版刚上线没多久,产品又对需求进行了大改动,以前用的是左滑菜单,现在又要换成底部导航栏,于是今天又苦逼加班了.花了几个小时实现了一个底部导航栏的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);



posted @ 2015-09-08 22:38  安辉  阅读(810)  评论(0编辑  收藏  举报