FrameLayout+碎片实现底部导航
一、效果展示(若觉得画面太大,可单击后观看)
二、底部导航栏布局
1、 新建bottom.xml文件
2、设置布局:
3、代码:
<?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="58dp"
android:background="@android:color/background_light"
android:gravity="center">
<LinearLayout
android:id="@+id/id_tab_home"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_home_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:clickable="false"
android:src="@mipmap/tab_home_normal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="首页" />
</LinearLayout>
<LinearLayout
android:id="@+id/id_tab_video"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_video_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:clickable="false"
android:src="@mipmap/tab_video_normal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="视频" />
</LinearLayout>
<LinearLayout
android:id="@+id/id_tab_social"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_social_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:clickable="false"
android:src="@mipmap/tab_social_normal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="社交" />
</LinearLayout>
<LinearLayout
android:id="@+id/id_tab_mine"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_mine_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:clickable="false"
android:src="@mipmap/tab_mine_normal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="我的" />
</LinearLayout>
<LinearLayout
android:id="@+id/id_tab_setting"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="@+id/id_tab_settings_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:clickable="false"
android:src="@mipmap/settings_norm" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="设置" />
</LinearLayout>
</LinearLayout>
三、准备导航碎片
1、创建5个碎片,分别为Home、Video、Mine、Social、Settings
2、分别修改Home.java、Video.java、Mine.java、Social.java、Settings.java文件
(1)Home.java
public class Home extends Fragment {
public Home() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.activity_home, container, false);
}
}
(2)Video.java
public class Video extends Fragment {
public Video()
{
//需要一个空的公共构造函数,作为实例的一个创建
}
//当Fragment创建视图时调用onCreateView()生命周期方法
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
//LayoutInflater的作用类似于findViewById(),不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;
// 而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。
// 具体作用:1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
// 2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素
{
// 用碎片填充布局
return inflater.inflate(R.layout.activity_video, container, false);
}
}
(3)Mine.java
public class Mine extends Fragment {
public Mine() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.activity_mine, container, false);
}
}
(4)Social.java
public class Social extends Fragment
{
public Social()
{
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
return inflater.inflate(R.layout.activity_social, container, false);
}
}
(5)Settings.java
public class Settings extends Fragment {
public Settings()
{
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.activity_settings, container, false);
}
}
3、分别修改activity_home.xml、activity_video.xml、activity_mine.xml、 activity_social.xml、activity_settings.xml文件
(1)activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:background="@drawable/home"
tools:context=".Home">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="160dp"
android:layout_marginLeft="50dp"
android:textSize="50sp"
android:textStyle="italic"
android:textColor="@color/plum"
android:text="欢迎来到首页" />
</FrameLayout>
(2)activity_video.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:background="@drawable/vedio"
tools:context=".Video">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="40sp"
android:textStyle="italic"
android:textColor="@color/blue"
android:text="观看兔兔视频" />
</FrameLayout>
(3)activity_mine.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:background="@drawable/mine"
tools:context=".Mine">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="180dp"
android:layout_marginLeft="60dp"
android:textSize="30sp"
android:textStyle="italic"
android:textColor="@color/plum"
android:text="这是属于自己的空间哦" />
</FrameLayout>
(4)activity_social.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:background="@drawable/social"
tools:context=".Social">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:layout_marginLeft="60dp"
android:textSize="30sp"
android:textStyle="italic"
android:textColor="@color/teal_200"
android:text="来认识更多朋友吧" />
</FrameLayout>
(5)activity_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".Settings">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/settings"
android:orientation="vertical">
<Button
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginLeft="45dp"
android:layout_marginTop="110dp"
android:background="@drawable/shape_round"
android:hint="隐私设置"
android:textColorHint="@color/plum"
android:textSize="20sp" />
<Button
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginTop="100dp"
android:background="@drawable/shape_round"
android:hint="通用设置"
android:textColorHint="@color/plum"
android:textSize="20sp" />
<Button
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginTop="100dp"
android:background="@drawable/shape_round"
android:hint="用户设置"
android:textColorHint="@color/plum"
android:textSize="20sp" />
</LinearLayout>
</FrameLayout>
四、修改MainActivity.java
1、声明变量
public class MainActivity extends AppCompatActivity
{
//装载Fragment的集合
private List<Fragment> mFragments;
//5个Tab对应的布局
private LinearLayout mTabHome;
private LinearLayout mTabVideo;
private LinearLayout mTabSocial;
private LinearLayout mTabMine;
private LinearLayout mTabSetting;
//5个Tab对应的ImageButton
private ImageButton mImgHome;
private ImageButton mImgVideo;
private ImageButton mImgSocial;
private ImageButton mImgMine;
private ImageButton mImgSettings;
…………
}
2、初始化onCreate()方法,并设置首次运行时显示的碎片
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews(); //初始化控件
initEvents(); //初始化事件
initFragments(); //初始化数据
//initFirstRun(0); 第一次运行初始化界面,显示第一个碎片,本案例中注释此行代码,先显示main页面,不直 //接显示碎片,点击导航栏才显示
}
3、初始化碎片列表,设置initFragments ()方法
//初始化碎片集,每个底部导航按钮对应一个碎片
private void initFragments()
{
mFragments = new ArrayList<>();
//将5个Fragment加入集合中
mFragments.add(new Home());
mFragments.add(new Video());
mFragments.add(new Social());
mFragments.add(new Mine());
mFragments.add(new Settings());
}
4、设置initViews()方法, 初始化控件引用
/*初始化控件*/
private void initViews()
{
FrameLayout frag_layout = (FrameLayout) findViewById(R.id.frag_layout);
mTabHome = (LinearLayout) findViewById(R.id.id_tab_home);
mTabVideo = (LinearLayout) findViewById(R.id.id_tab_video);
mTabSocial = (LinearLayout) findViewById(R.id.id_tab_social);
mTabMine = (LinearLayout) findViewById(R.id.id_tab_mine);
mTabSettings = (LinearLayout) findViewById(R.id.id_tab_settings);
mImgHome = (ImageButton) findViewById(R.id.id_tab_home_img);
mImgVideo = (ImageButton) findViewById(R.id.id_tab_video_img);
mImgSocial = (ImageButton) findViewById(R.id.id_tab_social_img);
mImgMine = (ImageButton) findViewById(R.id.id_tab_mine_img);
mImgSettings = (ImageButton) findViewById(R.id.id_tab_settings_img);
}
5、设置initEvents()方法, 初始化事件
(1)为底部导航的每组控件设置监听事件,包括设置ImageButton,以及与当前单击的Tab对应的碎片。
/*设置四个底部导航键的的点击事件*/
private void initEvents()
{
mTabHome.setOnClickListener(onClickListener);
mTabVideo.setOnClickListener(onClickListener);
mTabSocial.setOnClickListener(onClickListener);
mTabMine.setOnClickListener(onClickListener);
mTabSettings.setOnClickListener(onClickListener);
}
(2)定义onClickListener 事件并实现onClick()
View.OnClickListener onClickListener = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//先将四个ImageButton置为默认色
resetImgs();
//然后根据点击的Tab切换不同的碎片,并设置对应的ImageButton为pressed时的图片
switch (v.getId())
{
case R.id.id_tab_home:
selectTab(0);
break;
case R.id.id_tab_video:
selectTab(1);
break;
case R.id.id_tab_social:
selectTab(2);
break;
case R.id.id_tab_mine:
selectTab(3);
break;
case R.id.id_tab_settings:
selectTab(4);
break;
}
}
};
(3)将四个ImageButton设置为默认色
private void resetImgs()
{
mImgHome.setImageResource(R.mipmap.tab_home_normal);
mImgVideo.setImageResource(R.mipmap.tab_video_normal);
mImgSocial.setImageResource(R.mipmap.tab_social_normal);
mImgMine.setImageResource(R.mipmap.tab_mine_normal);
mImgSettings.setImageResource(R.mipmap.settings_norm);
}
(4)实现selectTab()方法,对选中的Tab着重显示,并调用方法设置当前应显示的碎片
/*选中第i个碎片*/
private void selectTab(int i)
{
//设置当前点击的Tab所对应的碎片
setCurrentFragment(i);
//根据点击的Tab设置对应的ImageButton为pressed时的图片
switch (i)
{
case 0:
mImgHome.setImageResource(R.mipmap.tab_home_pressed);
break;
case 1:
mImgVideo.setImageResource(R.mipmap.tab_video_pressed);
break;
case 2:
mImgSocial.setImageResource(R.mipmap.tab_social_pressed);
break;
case 3:
mImgMine.setImageResource(R.mipmap.tab_mine_pressed);
break;
case 4:
mImgSettings.setImageResource(R.mipmap.settings_press);
break;
}
}
(5)显示当前点击的Tab所对应的碎片
private void setCurrentFragment(int i)
{
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction trans = fm.beginTransaction();
trans.replace(R.id.frag_layout,mFragments.get(i));
trans.commit();
}
6、实现initFirstRun ()方法, 程序初次运行时显示第一个碎片,调用initFirstRun(0)
/* 在FrameLayout中显示第i个碎片*/
private void initFirstRun(int i)
{
resetImgs();//重置所有Tab
selectTab(i);//显示第i个碎片
}
7、完整的MainActivity代码
package com.example.myapplication6;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity
{
//装载Fragment的集合
private List<Fragment> mFragments;
//5个Tab对应的布局
private LinearLayout mTabHome;
private LinearLayout mTabVideo;
private LinearLayout mTabSocial;
private LinearLayout mTabMine;
private LinearLayout mTabSettings;
//5个Tab对应的ImageButton
private ImageButton mImgHome;
private ImageButton mImgVideo;
private ImageButton mImgSocial;
private ImageButton mImgMine;
private ImageButton mImgSettings;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews(); //初始化控件
initEvents(); //初始化事件
initFragments(); //初始化数据
//第一次运行初始化界面,显示第一个碎片
//initFirstRun(0);
}
/*初始化控件*/
private void initViews()
{
FrameLayout frag_layout = (FrameLayout) findViewById(R.id.frag_layout);
mTabHome = (LinearLayout) findViewById(R.id.id_tab_home);
mTabVideo = (LinearLayout) findViewById(R.id.id_tab_video);
mTabSocial = (LinearLayout) findViewById(R.id.id_tab_social);
mTabMine = (LinearLayout) findViewById(R.id.id_tab_mine);
mTabSettings = (LinearLayout) findViewById(R.id.id_tab_settings);
mImgHome = (ImageButton) findViewById(R.id.id_tab_home_img);
mImgVideo = (ImageButton) findViewById(R.id.id_tab_video_img);
mImgSocial = (ImageButton) findViewById(R.id.id_tab_social_img);
mImgMine = (ImageButton) findViewById(R.id.id_tab_mine_img);
mImgSettings = (ImageButton) findViewById(R.id.id_tab_settings_img);
}
/*设置四个底部导航键的的点击事件*/
private void initEvents()
{
mTabHome.setOnClickListener(onClickListener);
mTabVideo.setOnClickListener(onClickListener);
mTabSocial.setOnClickListener(onClickListener);
mTabMine.setOnClickListener(onClickListener);
mTabSettings.setOnClickListener(onClickListener);
}
View.OnClickListener onClickListener = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//先将四个ImageButton置为默认色
resetImgs();
//然后根据点击的Tab切换不同的碎片,并设置对应的ImageButton为pressed时的图片
switch (v.getId())
{
case R.id.id_tab_home:
selectTab(0);
break;
case R.id.id_tab_video:
selectTab(1);
break;
case R.id.id_tab_social:
selectTab(2);
break;
case R.id.id_tab_mine:
selectTab(3);
break;
case R.id.id_tab_settings:
selectTab(4);
break;
}
}
};
/*将四个ImageButton设置为默认色*/
private void resetImgs()
{
mImgHome.setImageResource(R.mipmap.tab_home_normal);
mImgVideo.setImageResource(R.mipmap.tab_video_normal);
mImgSocial.setImageResource(R.mipmap.tab_social_normal);
mImgMine.setImageResource(R.mipmap.tab_mine_normal);
mImgSettings.setImageResource(R.mipmap.settings_norm);
}
/*选中第i个碎片*/
private void selectTab(int i)
{
//设置当前点击的Tab所对应的碎片
setCurrentFragment(i);
//根据点击的Tab设置对应的ImageButton为pressed时的图片
switch (i)
{
case 0:
mImgHome.setImageResource(R.mipmap.tab_home_pressed);
break;
case 1:
mImgVideo.setImageResource(R.mipmap.tab_video_pressed);
break;
case 2:
mImgSocial.setImageResource(R.mipmap.tab_social_pressed);
break;
case 3:
mImgMine.setImageResource(R.mipmap.tab_mine_pressed);
break;
case 4:
mImgSettings.setImageResource(R.mipmap.settings_press);
break;
}
}
/*显示当前点击的Tab所对应的碎片*/
private void setCurrentFragment(int i)
{
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction trans = fm.beginTransaction();
trans.replace(R.id.frag_layout,mFragments.get(i));
trans.commit();
}
//初始化碎片集,每个底部导航按钮对应一个碎片
private void initFragments()
{
mFragments = new ArrayList<>();
//将5个Fragment加入集合中
mFragments.add(new Home());
mFragments.add(new Video());
mFragments.add(new Social());
mFragments.add(new Mine());
mFragments.add(new Settings());
}
/* 在FrameLayout中显示第i个碎片*/
private void initFirstRun(int i)
{
resetImgs();//重置所有Tab
selectTab(i);//显示第i个碎片
}
}
五、修改activity_main.xml和APP名字
1、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"
android:background="@color/pink3"
tools:context=".MainActivity">
<!--根据底部Tab动态加载某个碎片的容器-->
<FrameLayout
android:id="@+id/frag_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<!-- 底部导航布局-->
<include layout="@layout/bottom"/>
</LinearLayout>
2、应用名称
<resources>
<string name="app_name">小粉书</string>
</resources>
六、相关问题
1、单击某个底部导航选项后,项目执行了哪些代码?即如何更新页面(碎片)及底部导航显示?
(以Home为例)
/*显示当前点击的Tab所对应的碎片*/
private void setCurrentFragment(int i)
{
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction trans = fm.beginTransaction();
trans.replace(R.id.frag_layout,mFragments.get(i));
trans.commit();
}
/* 在FrameLayout中显示第i个碎片*/
private void initFirstRun(int i)
{
resetImgs();//重置所有Tab
selectTab(i);//显示第i个碎片
}
/*设置四个底部导航键的的点击事件*/
private void initEvents()
{
mTabHome.setOnClickListener(onClickListener);
}
public class Home extends Fragment {
public Home() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.activity_home, container, false);
}
}