Android 原生 RadioGroup+ViewPage/安卓自带原生控件BottomNavigation 实现传统软件主页面切换
文章目录
一、RadioGroup+ViewPage 实现
主要借用了RadioGroup单选的特性。而不需要考虑使用其他控件时如何实现单选状态。
1.新建项目
2.编写主页的XML
根部局建议使用相对布局(RelativeLayout)
编写RadioRroup标签,对RadioGroup不熟悉的可以自行面向CSDN编程
新增 RadioGroup 标签,在标签内新增你所需要对应数量的RadioButton。
一个 RadioButton 标签对应一个页面
我们这里创建了4个
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="65dp"
android:orientation="horizontal">
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="主页"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="分类"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="发现"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="我的"/>
</RadioGroup>
</RelativeLayout>
如下所示:
但是这看上去的效果并不是我们想要的,多出来一个圆圈,这是radiogroup默认自带的标注是否选中的标志,因此我们想要去掉它。再将RadioGroup对齐底部,为了美观,我们需要将文字居中,并将文字上的图片加上。
在此基础我们稍加修改:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="65dp"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="主页"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/ic_baseline_home_24" />
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="分类"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/ic_baseline_home_24"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="发现"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/ic_baseline_home_24"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="我的"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/ic_baseline_home_24"/>
</RadioGroup>
</RelativeLayout>
其中
android:button="@null"
为取消radioButton的按钮。
我们可以看到处理后的效果:
这样看起来的效果就不错了,如果嫌图片太靠上,我们可以在RadioButton上尝试使用:
android:paddingTop="12dp"
使图片靠下一些。
3.为底部导航编写selector文件
当然。我们看到的含有下导航的软件都是点击后即改变文字和图标的颜色,且先前点击项的文字和图片自动变成灰色。
因此我们在此前已经有一个绿色图标基础上,再新增一个灰色图标到 res 下的 drawable 文件夹。
(右击 drawable文件夹 ,new ,Vector Asset 可以选择系统提供的图标库添加,当然你也可以用自己的图片)
新增完成之后我们获得 ic_baseline_home_24_none.xml 文件。
其中 ic_baseline_home_24_none 对应的灰色图标
而 ic_baseline_home_24 对应绿色图标
我们有两个不同颜色的图标之后,开始编写selector文件
再次drawable下新建一个selector文件:
如下编写:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_baseline_home_24" android:state_checked="true"/>
<item android:drawable="@drawable/ic_baseline_home_24_none" android:state_checked="false"/>
</selector>
drawable表示你展示的drawable文件,state_checked表示当控件处于此状态时触发的条件。
上面的意思是 控件当被勾选时,drawable文件将会被更改为drawable/ic_baseline_home_24这个文件,反之为@drawable/ic_baseline_home_24_none。
此时我们的图片状态的selector就编写好了,除了图片的状态切换,我们还需要文字颜色的切换。
依旧是在drawable文件下新建一个selector,命名为:selector_bottom_text.xml
内容如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/green" android:state_checked="true"/>
<item android:color="@color/gray" android:state_checked="false"/>
</selector>
如果你的@color/green 报红 ,请自行在 res/values/color当中加入:
<color name="green">#0CD427</color>
<color name="gray">#9C9C9C</color>
颜色可以你自己自定义。
最终我们在xml当中引用:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="65dp"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="主页"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"
android:paddingTop="12dp"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="分类"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="发现"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"/>
<RadioButton
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="我的"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"/>
</RadioGroup>
</RelativeLayout>
我们将RadioButton 当中的DrawableTop属性改成了新建的selector_bottom_home,并且新增了 android:textColor 属性,将其属性设置为另一个selector文件 selector_bottom_text。
我们可以看最终效果:
非常不错。
当然如果你较为细心的话可能会发现一个问题,我们第一次进软件时,我们刚刚做好的这个导航栏的 主页 并没有变成绿色。按道理来说,用户是进入软件即为主页的,主页需要默认勾选上。我们可以给控件设置id并且编写代码控制默认选中第一项:
package com.abbas.vpdemo0320;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class MainActivity extends AppCompatActivity {
private RadioGroup rg;
private RadioButton rb1;
private RadioButton rb2;
private RadioButton rb3;
private RadioButton rb4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rg = (RadioGroup) findViewById(R.id.rg);
rb1 = (RadioButton) findViewById(R.id.rb1);
rb2 = (RadioButton) findViewById(R.id.rb2);
rb3 = (RadioButton) findViewById(R.id.rb3);
rb4 = (RadioButton) findViewById(R.id.rb4);
rg.check(R.id.rb1);
}
}
那么到此为止,我们的底部导航栏就做好了。接下来是ViewPage了。
在xml当中增加ViewPage标签并处于我们刚刚做的bottomNavigation之上:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp"
android:layout_above="@+id/rg"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RadioGroup
android:id="@+id/rg"
android:layout_width="match_parent"
android:layout_height="65dp"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<RadioButton
android:id="@+id/rb1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="主页"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"
android:paddingTop="12dp"/>
<RadioButton
android:id="@+id/rb2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="分类"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"
android:paddingTop="12dp"/>
<RadioButton
android:id="@+id/rb3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="发现"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"
android:paddingTop="12dp"/>
<RadioButton
android:id="@+id/rb4"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="我的"
android:button="@null"
android:gravity="center"
android:drawableTop="@drawable/selector_bottom_home"
android:textColor="@drawable/selector_bottom_text"
android:paddingTop="12dp"/>
</RadioGroup>
</RelativeLayout>
我们可以看到ViewPage置于我们做好的BottomNavigation之上了
4.java部分
接下来开始编写java代码,为简化操作,我只新建一个fragment。实际上应该是几个页面即对应几个fragment。
1.第一步新建一个空的fragment
2.第二步新建ViewPage的适配器类
然后挂一边,不管它。再次新建一个ViewPage的适配器类,继承FragmentPagerAdapter(还可以继承其他类,自行面向CSDN编程)。代码如下:
package com.abbas.vpdemo0320;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.List;
/**
* @author abbas
* @description: TODO
* @date 2022/3/20 12:30
*/
public class MyVpAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyVpAdapter(@NonNull FragmentManager fm,List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
3.第三步 为主页的ViewPage设置适配器
返回 MainActivity ,增加一个fragment泛型存储主页四个碎片,新增四个碎片增加到这个泛型当中。再新增 MyVpAdapter 对象,将四个碎片数据传递给这个对象。最后ViewPage设置这个适配器即可。
package com.abbas.vpdemo0320;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RadioGroup rg;
private RadioButton rb1;
private RadioButton rb2;
private RadioButton rb3;
private RadioButton rb4;
private ViewPager vp;
private MyVpAdapter myVpAdapter;
private List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vp = (ViewPager) findViewById(R.id.vp);
rg = (RadioGroup) findViewById(R.id.rg);
rb1 = (RadioButton) findViewById(R.id.rb1);
rb2 = (RadioButton) findViewById(R.id.rb2);
rb3 = (RadioButton) findViewById(R.id.rb3);
rb4 = (RadioButton) findViewById(R.id.rb4);
for (int i = 0; i < 4; i++) {
fragments.add(new BlankFragment());
}
myVpAdapter = new MyVpAdapter(getSupportFragmentManager(),fragments);
vp.setAdapter(myVpAdapter);
rg.check(R.id.rb1);
}
}
此刻我们的主页基本成型:
4.第四步 为底部导航与ViewPage进行关联联动
但是在ViewPage滑动时,底部导航栏不会对应勾选相应的项目,我们需要将他们关联起来,那么,完整的代码如下:
package com.abbas.vpdemo0320;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RadioGroup rg;
private RadioButton rb1;
private RadioButton rb2;
private RadioButton rb3;
private RadioButton rb4;
private ViewPager vp;
private MyVpAdapter myVpAdapter;
private List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vp = (ViewPager) findViewById(R.id.vp);
rg = (RadioGroup) findViewById(R.id.rg);
rb1 = (RadioButton) findViewById(R.id.rb1);
rb2 = (RadioButton) findViewById(R.id.rb2);
rb3 = (RadioButton) findViewById(R.id.rb3);
rb4 = (RadioButton) findViewById(R.id.rb4);
for (int i = 0; i < 4; i++) {
fragments.add(new BlankFragment());
}
myVpAdapter = new MyVpAdapter(getSupportFragmentManager(),fragments);
vp.setAdapter(myVpAdapter);
rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId){
case R.id.rb1:
vp.setCurrentItem(0);
break;
case R.id.rb2:
vp.setCurrentItem(1);
break;
case R.id.rb3:
vp.setCurrentItem(2);
break;
case R.id.rb4:
vp.setCurrentItem(3);
break;
default:break;
}
}
});
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
rg.check(rg.getChildAt(position).getId());
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
rg.check(R.id.rb1);
}
}
最终效果如图:
二、安卓原生底部导航栏控件 BottomNavigation 的使用
安卓提供了一个原生控件BottomNavigation作为底部导航栏,安卓开发者可以直接使用。
1.编写xml文件
这里我们写了一个最基本的xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity2">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp"
android:layout_above="@+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigation"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
大体效果:
我们能看到基本的骨架很快就出来了,因为底部导航栏还没有增加文字图标等信息,所以显示为空。相较于我们前面我们自己写的底部导航,官方的这个文字图标信息并不是写在当前xml当中的,我们需要在res文件夹下新建一个menu文件夹并且编写另一种xml文件。如果你有接触过标题栏右上角的menu菜单,我相信你对此应该很熟悉。
2.编写menu.xml文件
首先在res下新建一个名为menu的文件夹
新建完成之后,我们右键这个menu文件夹,new 选项,我们能很轻易的看见有一个 Menu Resource File 选项。点击这个选项,新建一个此类文件。我们将其命名为 bottom_menu。
从右上角的Design选项切换到Split,我们能看到这个xml的根部局为 menu 。接下来开始编写这个xml文件:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/home"
android:icon="@drawable/ic_baseline_home_24_none"
android:title="主页"
app:showAsAction="always"/>
<item android:id="@+id/found"
android:icon="@drawable/ic_baseline_home_24_none"
android:title="主页"
app:showAsAction="always"/>
<item android:id="@+id/friend"
android:icon="@drawable/ic_baseline_home_24_none"
android:title="主页"
app:showAsAction="always"/>
<item android:id="@+id/mine"
android:icon="@drawable/ic_baseline_home_24_none"
android:title="主页"
app:showAsAction="always"/>
</menu>
其中,四个 item 标签对应 BottomNavigation 四个底部标签。我们加上了图标以及文字信息。
返回activity视图的xml当中,将它添加上去:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity2">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp"
android:layout_above="@+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigation"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_menu"/>
</RelativeLayout>
当中我们仅添加了一个 app:menu
属性,并将它的属性指向刚刚创建的menu文件。
此刻我们已经可以在预览上看到效果:
你能看到,在我们之前自定义的导航栏的时候,我们花费很多时间去创建selector文件来为单个控件切换实现颜色变换效果。而现在我们仅仅是定义了一个menu文件,使用的icon也都是灰色的,但是 BottomNavigation 这个控件已经帮我们自动实现了颜色的变换效果。
3.图标颜色自定义
但是现在又有一个问题,这个紫色并不是我们想要的。
我们可以这样实现颜色的自定义:
res文件夹下 新建一个名为 color 文件夹。右击此文件夹,new,可以看到有一个 Color Resource File 选项。我们新建一个此类型文件,命名名为 selector_bottom_color 。
如下编写:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/green" android:state_checked="true"/>
<item android:color="@color/black" android:state_checked="false"/>
</selector>
看上去和我们此前定义过的selector文件类似。再次回到xml视图,我们新增一些属性:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity2">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp"
android:layout_above="@+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigation"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_menu"
app:itemIconTint="@color/selector_bottom_icon"
app:itemTextColor="@color/selector_bottom_icon"/>
</RelativeLayout>
我们新增了 app:itemIconTint
与 app:itemTextColor
属性。属性值都指向刚刚我们的那个color文件。此刻我们的xml视图已经编写完成了。我们可以看看效果:
你可能会注意到一个问题,在选中某个选项的时候,它的底部导航文字才会显示。如果想要底部文字一直显示出来。我们可以加入这个属性即可:
app:labelVisibilityMode="labeled"
4.在代码中与ViewPage进行联动
BottomNavigation 的点击事件监听为:setOnNavigationItemSelectedListener
注意:setOnNavigationItemSelectedListener 需要返回一个 布尔 类型的结果来确定是否点击成功。它默认返回了false,需要你手动改成 true
完全代码如下:
package com.abbas.vpdemo0320;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import android.view.MenuItem;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity2 extends AppCompatActivity {
private ViewPager vp;
private BottomNavigationView bottomNavigation;
private List<Fragment> fragments = new ArrayList<>();
private MyVpAdapter myVpAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
vp = (ViewPager) findViewById(R.id.vp);
bottomNavigation = (BottomNavigationView) findViewById(R.id.bottomNavigation);
for (int i = 0; i < 4; i++) {
fragments.add(new BlankFragment());
}
myVpAdapter = new MyVpAdapter(getSupportFragmentManager(),fragments);
vp.setAdapter(myVpAdapter);
bottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.home:
vp.setCurrentItem(0);
break;
case R.id.found:
vp.setCurrentItem(1);
break;
case R.id.friend:
vp.setCurrentItem(2);
break;
case R.id.mine:
vp.setCurrentItem(4);
break;
}
return true;
}
});
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position){
case 0:
bottomNavigation.setSelectedItemId(R.id.home);
break;
case 1:
bottomNavigation.setSelectedItemId(R.id.found);
break;
case 2:
bottomNavigation.setSelectedItemId(R.id.friend);
break;
case 3:
bottomNavigation.setSelectedItemId(R.id.mine);
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
最终效果如下:
所有内容已到此完毕,感谢你的阅读。