文章目录
- 前言
- 一、实现思路
- 二、代码实现流程
- ①修改theme:
- ②在color文件中添加颜色:
- ③添加图标文件
- ④添加选中时布局的背景
- ⑤修改布局文件
- ⑥按钮效果图:
- ⑦修改`MainActivity`中的代码
- ⑦创建各个界面的Fragment
- ⑧运行结果:
- 三、 总结
前言
本篇文章为本人在大一时候写的一篇笔记,因此请大家轻喷(因为有部分代码并没有考虑代码规范性,其中的代码的使用也比较愚笨😭,而且当时也没学Kotlin,所以使用的Java),本篇文章主要面向想要应付安卓大作业,需要一个比较好看的底部导航栏的安卓小白🙂。
一、实现思路
实现方法非常简单粗暴(至少在我看来),观察可以发现我们要设计的底部按钮主要由文本(TextView
)、图标(ImageView
)和背景的椭圆(shape
)这三个元素构成,这三个部分比较简单。点击逻辑其实也很简单,只要当点击按钮最外层的空间时对应设置当前按钮为选中状态,其余按钮为未选中状态,把对应的图标设置一下,因为我们要实现只有选中的按钮才会显示文本(TextView
),因此在点击按钮时要设置其他未选中按钮的文本为不可见。动画则是设置ScaleAnimation
,设置动画的锚点等等来实现点击时的动画。
二、代码实现流程
①修改theme:
首先修改theme文件中的代码(深色模式中的也要改):
<style name="Theme.NavigationView" parent="Theme.MaterialComponents.DayNight.NoActionBar">
②在color文件中添加颜色:
后面四个颜色是上面的那四个颜色的
A%
改为20得到的
<color name="home">#1194AA</color>
<color name="like">#C9379D</color>
<color name="notification">#AE7E0F</color>
<color name="profile">#5B37B7</color>
<color name="home_20">#331194AA</color>
<color name="like_20">#33C9379D</color>
<color name="notification_20">#33AE7E0F</color>
<color name="profile_20">#335B37B7</color>
③添加图标文件
图标文件分为两部分,一部分是未选中的图标,一个是选中后的图标,文件结构如下
选中状态的图标只需要修改path
中的fileColor
为之前添加的颜色即可
④添加选中时布局的背景
在drawable文件中添加三个按钮被选中时布局的背景:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid android:color="@color/home_20"/>
<corners android:radius="100dp"/>
</shape>
设置背景后的情况
⑤修改布局文件
<?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:layout_height="match_parent"
tools:context=".MainActivity"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="4"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"
android:elevation="10dp"
android:gravity="center"
android:layout_alignParentBottom="true"
android:background="@color/white"
>
<LinearLayout
android:background="@drawable/round_back_home_100"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:gravity="center"
android:layout_weight="1"
>
<ImageView
android:layout_width="20dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/home_selected"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="home"
android:layout_marginStart="10dp"
android:textStyle="bold"
android:textColor="@color/home"
android:textSize="16sp"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
⑥按钮效果图:
这样我们就实现了其中一个按钮,之后将按钮的代码赋值粘贴后,修改布局的backgroud,设置TextView的text、visibility和textColor,ImageView的src后如下:
<?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:layout_height="match_parent"
android:background="@color/home"
tools:context=".MainActivity"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="4"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"
android:elevation="10dp"
android:gravity="center"
android:layout_alignParentBottom="true"
android:background="@color/white"
>
<LinearLayout
android:id="@+id/homeLayout"
android:background="@drawable/round_back_home_100"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:gravity="center"
android:layout_weight="1"
>
<ImageView
android:id="@+id/home_im"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/home_selected" />
<TextView
android:id="@+id/home_tx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="home"
android:textColor="@color/home"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="@+id/likeLayout"
android:background="@android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:gravity="center"
android:layout_weight="1"
>
<ImageView
android:id="@+id/like_im"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/like" />
<TextView
android:id="@+id/like_tx"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="like"
android:layout_marginStart="10dp"
android:textStyle="bold"
android:textColor="@color/home"
android:textSize="16sp"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/notificationLayout"
android:background="@android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:gravity="center"
android:layout_weight="1"
>
<ImageView
android:id="@+id/nitification_im"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/notification" />
<TextView
android:id="@+id/notification_tx"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="notification"
android:layout_marginStart="10dp"
android:textStyle="bold"
android:textColor="@color/home"
android:textSize="16sp"
/>
</LinearLayout>
<!-- 布局的宽度根据权值平局分配-->
<LinearLayout
android:id="@+id/profileLayout"
android:background="@android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:gravity="center"
android:layout_weight="1"
>
<ImageView
android:id="@+id/profile_im"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/profile" />
<TextView
android:id="@+id/profile_tx"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="profile"
android:layout_marginStart="10dp"
android:textStyle="bold"
android:textColor="@color/profile"
android:textSize="16sp"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
这样我们就实现了一个基本的底部导航栏界面,接下来要解决的是动画的问题。
⑦修改MainActivity
中的代码
实现流程:
- 初始化布局和控件: 首先绑定控件和布局,这里只是随便写的代码(当时只是想着实现,还没考虑规范性问题),所以代码规范性勿喷😭。
- 设置初始状态: 初始化
selectedTab
变量,用于记录当前选中的导航项,默认值为1(即 home 导航项)。 - 点击事件监听: 为每个
LinearLayout
设置点击事件监听器,当某个导航项被点击时:- 检查是否被选中: 首先检查
selectedTab
是否等于该导航项的序号,如果是,表示该导航项已经被选中,无需做任何操作;否则继续执行后续步骤。 - 设置其他按钮为未选中状态: 隐藏其他导航项的文本(通过设置
TextView
的Visibility
为GONE
),将其他导航项的图标恢复为未选中状态(通过设置ImageView
的图片资源),将其他导航项的背景颜色恢复为默认颜色。 - 设置当前按钮为选中状态: 显示当前导航项的文本(通过设置
TextView
的Visibility
为VISIBLE
),将当前导航项的图标设置为选中状态(通过设置ImageView
的图片资源),将当前导航项的背景颜色设置为选中的颜色。 - 添加动画: 创建
ScaleAnimation
对象,设置动画的起始和结束缩放比例,动画的持续时间和动画的填充方式,然后将动画应用到当前导航项的LinearLayout
上。每个导航项的动画都从0.8f
缩放到1.0f
,且动画的锚点不同,分别为RELATIVE_TO_SELF
的0.0f
或1.0f
。 - 更新选中项: 最后,将
selectedTab
更新为当前导航项的序号。
- 检查是否被选中: 首先检查
/**
* 主界面
*
* @className: MainActivity
* @author: Voyager
* @description: 主界面
* @date: 2023/5/20
**/
public class MainActivity extends AppCompatActivity {
/**
* 被选中的底部按钮的序号,默认值为1
*/
private int selectedTab =1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final LinearLayout homeLayout=findViewById(R.id.homeLayout);
final LinearLayout likeLayout=findViewById(R.id.likeLayout);
final LinearLayout notificationLayout=findViewById(R.id.notificationLayout);
final LinearLayout profileLayout=findViewById(R.id.profileLayout);
final ImageView homeImage =findViewById(R.id.home_im);
final ImageView likeImage =findViewById(R.id.like_im);
final ImageView notificationImage =findViewById(R.id.notification_im);
final ImageView profileImage =findViewById(R.id.profile_im);
final TextView homeText=findViewById(R.id.home_tx);
final TextView likeText=findViewById(R.id.like_tx);
final TextView notificationText=findViewById(R.id.notification_tx);
final TextView profileText=findViewById(R.id.profile_tx);
homeLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=1){
//设置其他按钮为未选中状态
likeText.setVisibility(View.GONE);
notificationText.setVisibility(View.GONE);
profileText.setVisibility(View.GONE);
likeImage.setImageResource(R.drawable.like);
notificationImage.setImageResource(R.drawable.notification);
profileImage.setImageResource(R.drawable.profile);
likeLayout.setBackgroundColor(getResources().getColor(R.color.white));
notificationLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置home按钮的选中状态
homeText.setVisibility(View.VISIBLE);
homeImage.setImageResource(R.drawable.home_selected);
homeLayout.setBackgroundResource(R.drawable.round_back_home_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,0.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
homeLayout.startAnimation(scaleAnimation);
selectedTab=1;
}
});
likeLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=2){
//设置其他按钮为未选中状态
homeText.setVisibility(View.GONE);
notificationText.setVisibility(View.GONE);
profileText.setVisibility(View.GONE);
homeImage.setImageResource(R.drawable.home);
notificationImage.setImageResource(R.drawable.notification);
profileImage.setImageResource(R.drawable.profile);
homeLayout.setBackgroundColor(getResources().getColor(R.color.white));
notificationLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置like按钮的选中状态
likeText.setVisibility(View.VISIBLE);
likeImage.setImageResource(R.drawable.like_selected);
likeLayout.setBackgroundResource(R.drawable.round_back_like_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
likeLayout.startAnimation(scaleAnimation);
selectedTab=2;
}
});
notificationLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=3){
//设置其他按钮为未选中状态
homeText.setVisibility(View.GONE);
likeText.setVisibility(View.GONE);
profileText.setVisibility(View.GONE);
homeImage.setImageResource(R.drawable.home);
likeImage.setImageResource(R.drawable.like);
profileImage.setImageResource(R.drawable.profile);
homeLayout.setBackgroundColor(getResources().getColor(R.color.white));
likeLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置notification按钮的选中状态
notificationText.setVisibility(View.VISIBLE);
notificationImage.setImageResource(R.drawable.notification_selected);
notificationLayout.setBackgroundResource(R.drawable.round_back_notification_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
notificationLayout.startAnimation(scaleAnimation);
selectedTab=3;
}
});
profileLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=4){
//设置其他按钮为未选中状态
homeText.setVisibility(View.GONE);
notificationText.setVisibility(View.GONE);
likeText.setVisibility(View.GONE);
homeImage.setImageResource(R.drawable.home);
notificationImage.setImageResource(R.drawable.notification);
likeImage.setImageResource(R.drawable.like);
homeLayout.setBackgroundColor(getResources().getColor(R.color.white));
notificationLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置profile按钮的选中状态
profileText.setVisibility(View.VISIBLE);
profileImage.setImageResource(R.drawable.profile_selected);
profileLayout.setBackgroundResource(R.drawable.round_back_profile_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
profileLayout.startAnimation(scaleAnimation);
selectedTab=4;
}
});
}
}
⑦创建各个界面的Fragment
结构如下:
布局文件:
<?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="@color/home"
tools:context=".HomeFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="主页"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@color/black"
/>
</FrameLayout>
并在activity_main.xml
文件中添加Fragment的容器
修改MainActivity
中的代码,添加Fragment的切换:
public class MainActivity extends AppCompatActivity {
/**
* 被选中的底部按钮的序号,默认值为1
*/
private int selectedTab =1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final LinearLayout homeLayout=findViewById(R.id.homeLayout);
final LinearLayout likeLayout=findViewById(R.id.likeLayout);
final LinearLayout notificationLayout=findViewById(R.id.notificationLayout);
final LinearLayout profileLayout=findViewById(R.id.profileLayout);
final ImageView homeImage =findViewById(R.id.home_im);
final ImageView likeImage =findViewById(R.id.like_im);
final ImageView notificationImage =findViewById(R.id.notification_im);
final ImageView profileImage =findViewById(R.id.profile_im);
final TextView homeText=findViewById(R.id.home_tx);
final TextView likeText=findViewById(R.id.like_tx);
final TextView notificationText=findViewById(R.id.notification_tx);
final TextView profileText=findViewById(R.id.profile_tx);
//设置默认界面为HomeFragment
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.fragment_container,HomeFragment.class,null)
.commit();
homeLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=1){
//设置界面为HomeFragment
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.fragment_container,HomeFragment.class,null)
.commit();
//设置其他按钮为未选中状态
likeText.setVisibility(View.GONE);
notificationText.setVisibility(View.GONE);
profileText.setVisibility(View.GONE);
likeImage.setImageResource(R.drawable.like);
notificationImage.setImageResource(R.drawable.notification);
profileImage.setImageResource(R.drawable.profile);
likeLayout.setBackgroundColor(getResources().getColor(R.color.white));
notificationLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置home按钮的选中状态
homeText.setVisibility(View.VISIBLE);
homeImage.setImageResource(R.drawable.home_selected);
homeLayout.setBackgroundResource(R.drawable.round_back_home_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,0.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
homeLayout.startAnimation(scaleAnimation);
selectedTab=1;
}
});
likeLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=2){
//设置界面为LikeFragment
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.fragment_container,LikeFragment.class,null)
.commit();
//设置其他按钮为未选中状态
homeText.setVisibility(View.GONE);
notificationText.setVisibility(View.GONE);
profileText.setVisibility(View.GONE);
homeImage.setImageResource(R.drawable.home);
notificationImage.setImageResource(R.drawable.notification);
profileImage.setImageResource(R.drawable.profile);
homeLayout.setBackgroundColor(getResources().getColor(R.color.white));
notificationLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置like按钮的选中状态
likeText.setVisibility(View.VISIBLE);
likeImage.setImageResource(R.drawable.like_selected);
likeLayout.setBackgroundResource(R.drawable.round_back_like_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
likeLayout.startAnimation(scaleAnimation);
selectedTab=2;
}
});
notificationLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=3){
//设置界面为NotificationFragment
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.fragment_container,NotificationFragment.class,null)
.commit();
//设置其他按钮为未选中状态
homeText.setVisibility(View.GONE);
likeText.setVisibility(View.GONE);
profileText.setVisibility(View.GONE);
homeImage.setImageResource(R.drawable.home);
likeImage.setImageResource(R.drawable.like);
profileImage.setImageResource(R.drawable.profile);
homeLayout.setBackgroundColor(getResources().getColor(R.color.white));
likeLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置notification按钮的选中状态
notificationText.setVisibility(View.VISIBLE);
notificationImage.setImageResource(R.drawable.notification_selected);
notificationLayout.setBackgroundResource(R.drawable.round_back_notification_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
notificationLayout.startAnimation(scaleAnimation);
selectedTab=3;
}
});
profileLayout.setOnClickListener(v -> {
//检查是否被选中
if (selectedTab!=4){
//设置界面为ProfileFragment
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.fragment_container,ProfileFragment.class,null)
.commit();
//设置其他按钮为未选中状态
homeText.setVisibility(View.GONE);
notificationText.setVisibility(View.GONE);
likeText.setVisibility(View.GONE);
homeImage.setImageResource(R.drawable.home);
notificationImage.setImageResource(R.drawable.notification);
likeImage.setImageResource(R.drawable.like);
homeLayout.setBackgroundColor(getResources().getColor(R.color.white));
notificationLayout.setBackgroundColor(getResources().getColor(R.color.white));
profileLayout.setBackgroundColor(getResources().getColor(R.color.white));
//设置profile按钮的选中状态
profileText.setVisibility(View.VISIBLE);
profileImage.setImageResource(R.drawable.profile_selected);
profileLayout.setBackgroundResource(R.drawable.round_back_profile_100);
//添加动画
ScaleAnimation scaleAnimation=new ScaleAnimation(0.8f,1.0f,1f,1f,Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f);
scaleAnimation.setDuration(200);
scaleAnimation.setFillAfter(true);
profileLayout.startAnimation(scaleAnimation);
selectedTab=4;
}
});
}
}
⑧运行结果:
三、 总结
本篇文章提供了一个实现自定义底部导航栏的示例,能够帮助想要水过安卓大作业实现一个较为优美的底部导航界面,希望对大家有所帮助😘。