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