一、实现效果
二、思路分析
三、实现方式1(ViewPager方式)
1.代码结构
2.代码文件
2.1 顶部 activity_top.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#ffffff"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:layout_height="45dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="微信"
android:textColor="#1B940A"
android:textSize="16dp" />
</RelativeLayout>
2.2 底部 activity_bottom.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:padding="5dp"
>
<LinearLayout
android:id="@+id/ll_home"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/img_home"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/home" />
<TextView
android:id="@+id/txt_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/txt_nav_home"
android:textSize="12dp"
android:textColor="#888888"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_news"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/img_news"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/news_index" />
<TextView
android:id="@+id/txt_news"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/txt_nav_news"
android:textSize="12dp"
android:textColor="#888888"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_friend"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/img_friend"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/news_add" />
<TextView
android:id="@+id/txt_friend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/txt_nav_friend"
android:textSize="12dp"
android:textColor="#888888"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_user"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/img_user"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/phone" />
<TextView
android:id="@+id/txt_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/txt_nav_user"
android:textSize="12dp"
android:textColor="#888888"
/>
</LinearLayout>
</LinearLayout>
2.3 主视图 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<!--这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)-->
<include layout="@layout/activity_top" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#ffffff"
tools:ignore="MissingConstraints"></androidx.viewpager.widget.ViewPager>
<include layout="@layout/activity_bottom" />
</LinearLayout>
这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)
2.4 分页视图 page_home.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=".ui.HomeActivity">
<TextView
android:id="@+id/txt_home_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="我是01"
android:textColor="#1B940A"
android:textSize="30dp" />
</RelativeLayout>
2.5 ContentAdapter.java:ViewPager需配合一个Adapter使用,所以需先自定义一个Adapter。
package com.rc.bottombar;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import androidx.viewpager.widget.PagerAdapter;
public class ContentAdapter extends PagerAdapter {
private List<View> views;
public ContentAdapter(List<View> views) {
this.views = views;
}
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = views.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(views.get(position));
}
}
2.6 MainActivity.java
package com.rc.bottombar;
import androidx.viewpager.widget.ViewPager;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.rc.bottombar.ui.HomeActivity;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity implements View.OnClickListener, ViewPager.OnPageChangeListener {
private TextView txt_title;
// 底部菜单4个Linearlayout
private LinearLayout ll_home;
private LinearLayout ll_address;
private LinearLayout ll_friend;
private LinearLayout ll_setting;
// 底部菜单4个ImageView
private ImageView img_home;
private ImageView img_news;
private ImageView img_friend;
private ImageView img_user;
// 底部菜单4个菜单标题
private TextView txt_home;
private TextView txt_news;
private TextView txt_friend;
private TextView txt_user;
// 中间内容区域
private ViewPager viewPager;
// ViewPager适配器ContentAdapter
private ContentAdapter adapter;
private List<View> views;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();// 初始化控件
initEvent();// 设置按钮监听
txt_title.setText(R.string.txt_nav_home);
txt_home.setTextColor(0xff1B940A);
}
private void initEvent() {
ll_home.setOnClickListener(this);
ll_address.setOnClickListener(this);
ll_friend.setOnClickListener(this);
ll_setting.setOnClickListener(this);
viewPager.setOnPageChangeListener(this);
}
private void initView() {
txt_title = findViewById(R.id.title);
// 底部菜单4个Linearlayout
ll_home = findViewById(R.id.ll_home);
ll_address = findViewById(R.id.ll_news);
ll_friend = findViewById(R.id.ll_friend);
ll_setting = findViewById(R.id.ll_user);
// 底部菜单4个ImageView
img_home = findViewById(R.id.img_home);
img_news = findViewById(R.id.img_news);
img_friend = findViewById(R.id.img_friend);
img_user = findViewById(R.id.img_user);
// 底部菜单4个菜单标题
txt_home = findViewById(R.id.txt_home);
txt_news = findViewById(R.id.txt_news);
txt_friend = findViewById(R.id.txt_friend);
txt_user = findViewById(R.id.txt_user);
// 中间内容区域ViewPager
viewPager = findViewById(R.id.vp_content);
// 适配器
View page_home = View.inflate(MainActivity.this, R.layout.page_home, null);
View page_news = View.inflate(MainActivity.this, R.layout.page_news, null);
View page_friend = View.inflate(MainActivity.this, R.layout.page_friend, null);
View page_user = View.inflate(MainActivity.this, R.layout.page_user, null);
views = new ArrayList<View>();
views.add(page_home);
views.add(page_news);
views.add(page_friend);
views.add(page_user);
adapter = new ContentAdapter(views);
viewPager.setAdapter(adapter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_home:
restartBotton();
txt_title.setText(R.string.txt_nav_home);
txt_home.setTextColor(0xff1B940A);
viewPager.setCurrentItem(0);
break;
case R.id.ll_news:
restartBotton();
txt_title.setText(R.string.txt_nav_news);
txt_news.setTextColor(0xff1B940A);
viewPager.setCurrentItem(1);
break;
case R.id.ll_friend:
restartBotton();
txt_title.setText(R.string.txt_nav_friend);
txt_friend.setTextColor(0xff1B940A);
viewPager.setCurrentItem(2);
break;
case R.id.ll_user:
restartBotton();
txt_title.setText(R.string.txt_nav_user);
txt_user.setTextColor(0xff1B940A);
viewPager.setCurrentItem(3);
break;
default:
break;
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
restartBotton();
switch (position) {
case 0:
txt_title.setText(R.string.txt_nav_home);
txt_home.setTextColor(0xff1B940A);
break;
case 1:
txt_title.setText(R.string.txt_nav_news);
txt_news.setTextColor(0xff1B940A);
break;
case 2:
txt_title.setText(R.string.txt_nav_friend);
txt_friend.setTextColor(0xff1B940A);
break;
case 3:
txt_title.setText(R.string.txt_nav_user);
txt_user.setTextColor(0xff1B940A);
break;
default:
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
//重置链接样式
private void restartBotton() {
txt_home.setTextColor(Color.parseColor("#888888"));
txt_news.setTextColor(Color.parseColor("#888888"));
txt_friend.setTextColor(Color.parseColor("#888888"));
txt_user.setTextColor(Color.parseColor("#888888"));
}
}
注意事项:
1.需实现视图点击事件和ViewPager切换事件,implements View.OnClickListener, ViewPager.OnPageChangeListener。
2.initEvent()方法中给控件绑定事件后,下面的Listener才捕捉得到。
3.上面代码只切换选中菜单文字的效果,选中图片也是可以切换的,暂忽略。
四、实现方式2(Fragment方式)
1.布局文件基本没变化,只是把主界面的ViewPager改成了FramLayout,其他文件保持一致,就不贴出来了。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<!--这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,
中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。
(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)-->
<include layout="@layout/activity_top" />
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:background="#ffffff"
android:layout_height="0dp"
android:layout_weight="1" >
</FrameLayout>
<include layout="@layout/activity_bottom" />
</LinearLayout>
2.新增4个Fragment类,结构如下图:
以HomeFragment.java 为例,其他类似。
package com.rc.bottombar.ui;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.rc.bottombar.R;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HomeFragment extends Fragment {
View view;
TextView title;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.page_home, container, false);
title = view.findViewById(R.id.txt_home_title);
title.setText("我是" + getResources().getString(R.string.txt_nav_home));
return view;
}
public void Load() {
//title.setText("当前时间:\n" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
3.MainActivity.java
package com.rc.bottombar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.rc.bottombar.ui.FriendFragment;
import com.rc.bottombar.ui.HomeFragment;
import com.rc.bottombar.ui.NewsFragment;
import com.rc.bottombar.ui.UserFragment;
public class MainActivity extends Activity implements View.OnClickListener {
private TextView txt_title;
// 底部菜单4个Linearlayout
private LinearLayout ll_home;
private LinearLayout ll_address;
private LinearLayout ll_friend;
private LinearLayout ll_setting;
// 底部菜单4个ImageView
private ImageView img_home;
private ImageView img_news;
private ImageView img_friend;
private ImageView img_user;
// 底部菜单4个菜单标题
private TextView txt_home;
private TextView txt_news;
private TextView txt_friend;
private TextView txt_user;
// 4个Fragment
private HomeFragment homeFragment;
private Fragment newsFragment;
private Fragment friendFragment;
private Fragment userFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();// 初始化控件
initEvent();// 设置按钮监听
// 初始化并设置当前Fragment
initFragment(0);
}
private void initEvent() {
ll_home.setOnClickListener(this);
ll_address.setOnClickListener(this);
ll_friend.setOnClickListener(this);
ll_setting.setOnClickListener(this);
}
private void initView() {
txt_title = findViewById(R.id.title);
// 底部菜单4个Linearlayout
ll_home = findViewById(R.id.ll_home);
ll_address = findViewById(R.id.ll_news);
ll_friend = findViewById(R.id.ll_friend);
ll_setting = findViewById(R.id.ll_user);
// 底部菜单4个ImageView
img_home = findViewById(R.id.img_home);
img_news = findViewById(R.id.img_news);
img_friend = findViewById(R.id.img_friend);
img_user = findViewById(R.id.img_user);
// 底部菜单4个菜单标题
txt_home = findViewById(R.id.txt_home);
txt_news = findViewById(R.id.txt_news);
txt_friend = findViewById(R.id.txt_friend);
txt_user = findViewById(R.id.txt_user);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_home:
restartBotton();
txt_title.setText(R.string.txt_nav_home);
txt_home.setTextColor(0xff1B940A);
initFragment(0);
break;
case R.id.ll_news:
restartBotton();
txt_title.setText(R.string.txt_nav_news);
txt_news.setTextColor(0xff1B940A);
initFragment(1);
break;
case R.id.ll_friend:
restartBotton();
txt_title.setText(R.string.txt_nav_friend);
txt_friend.setTextColor(0xff1B940A);
initFragment(2);
break;
case R.id.ll_user:
restartBotton();
txt_title.setText(R.string.txt_nav_user);
txt_user.setTextColor(0xff1B940A);
initFragment(3);
break;
default:
break;
}
}
private void initFragment(int index) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
hideFragment(transaction);
switch (index) {
case 0:
if (homeFragment == null) {
homeFragment = new HomeFragment();
transaction.add(R.id.fl_content, homeFragment);
} else {
homeFragment.Load();//加载数据
transaction.show(homeFragment);
}
break;
case 1:
if (newsFragment == null) {
newsFragment = new NewsFragment();
transaction.add(R.id.fl_content, newsFragment);
} else {
transaction.show(newsFragment);
}
break;
case 2:
if (friendFragment == null) {
friendFragment = new FriendFragment();
transaction.add(R.id.fl_content, friendFragment);
} else {
transaction.show(friendFragment);
}
break;
case 3:
if (userFragment == null) {
userFragment = new UserFragment();
transaction.add(R.id.fl_content, userFragment);
} else {
transaction.show(userFragment);
}
break;
default:
break;
}
transaction.commit();
}
//隐藏Fragment
private void hideFragment(android.app.FragmentTransaction transaction) {
if (homeFragment != null) {
transaction.hide(homeFragment);
}
if (newsFragment != null) {
transaction.hide(newsFragment);
}
if (friendFragment != null) {
transaction.hide(friendFragment);
}
if (userFragment != null) {
transaction.hide(userFragment);
}
}
//重置链接样式
private void restartBotton() {
txt_home.setTextColor(Color.parseColor("#888888"));
txt_news.setTextColor(Color.parseColor("#888888"));
txt_friend.setTextColor(Color.parseColor("#888888"));
txt_user.setTextColor(Color.parseColor("#888888"));
}
}
五、小结
方式1:基于ViewPager实现的内容:
优点:
1、界面可以滑动,美观,流畅。
缺点:
1、当界面里有一些需要用手势来实现的内容会起冲突,比如我们ListView里的侧滑删除。
2、由于采用的是ViewPager,所以页面内容实现代码会严重依赖于MainActivity,代码太过冗余,不便于后期维护。
方式2:基于Fragment实现的内容:
优点:
1、Fragment文件单独存在,各自页面的内容各自去实现完成,有自己的生命周期,便于后期维护。
2、对于需要手势操作的一些内容不会起冲突。
缺点:
1、界面不可滑动,比较死板。
参考内容: