Android底部導(dǎo)航欄的三種風(fēng)格實(shí)現(xiàn)
一、效果圖展示

如果動(dòng)圖沒(méi)有動(dòng)的話(huà),也可以看下面這個(gè)靜態(tài)圖

以下挨個(gè)分析每個(gè)的實(shí)現(xiàn),這里只做簡(jiǎn)單的效果展示,大家可以基于目前代碼做二次開(kāi)發(fā)。
二、BottomNavigationView
這是 Google 給我們提供的一個(gè)專(zhuān)門(mén)用于底部導(dǎo)航的 View,你只需要在新建 Activity 的時(shí)候選擇 “Bottom Navigation Activity”,IDE 就會(huì)自動(dòng)使用 BottomNavigationView 幫你生成好相應(yīng)的代碼了。
1. 在 xml 中使用
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/navigation" />
這里面唯一要注意的就是 app:menu 屬性了,它指定了你的導(dǎo)航欄顯示的頁(yè)面菜單是怎樣的。
2. menu 的布局文件
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_home"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/title_home" />
<item
android:id="@+id/navigation_dashboard"
android:icon="@drawable/ic_dashboard_black_24dp"
android:title="@string/title_dashboard" />
<item
android:id="@+id/navigation_notifications"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/title_notifications" />
</menu>
3. 在 Activity 中調(diào)用
private TextView mTextMessage;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
mTextMessage.setText(R.string.title_home);
return true;
case R.id.navigation_dashboard:
mTextMessage.setText(R.string.title_dashboard);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.title_notifications);
return true;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style1);
mTextMessage = findViewById(R.id.message);
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
這里的演示 code 都是 IDE 自動(dòng)生成的,由于 BottomNavigationView 目前我還沒(méi)有在項(xiàng)目中實(shí)際使用過(guò),這里不做過(guò)多分析,使用起來(lái)不難,以上代碼已經(jīng)足以滿(mǎn)足我們的基本使用要求了。
三、RadioGroup + ViewPager
這是一種比較常見(jiàn)了的,下面 4 個(gè) tab 的導(dǎo)航按鈕,可以切換不同的頁(yè)面,這里頁(yè)面使用了 ViewPager + Fragment 的組合,實(shí)現(xiàn)了滑動(dòng)的頁(yè)面效果,也可以不使用 ViewPager,這個(gè)根據(jù)產(chǎn)品的定義來(lái)使用即可。
1. 布局文件
<?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=".style2.Style2Activity">
<android.support.v4.view.ViewPager
android:id="@+id/fragment_vp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/tabs_rg" />
<RadioGroup
android:id="@+id/tabs_rg"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:background="#dcdcdc"
android:orientation="horizontal">
<RadioButton
android:id="@+id/today_tab"
style="@style/Custom.TabRadioButton"
android:checked="true"
android:drawableTop="@drawable/tab_sign_selector"
android:text="今日" />
<RadioButton
android:id="@+id/record_tab"
style="@style/Custom.TabRadioButton"
android:drawableTop="@drawable/tab_record_selector"
android:text="記錄" />
<RadioButton
android:id="@+id/contact_tab"
style="@style/Custom.TabRadioButton"
android:drawableTop="@drawable/tab_contact_selector"
android:text="通訊錄" />
<RadioButton
android:id="@+id/settings_tab"
style="@style/Custom.TabRadioButton"
android:drawableTop="@drawable/tab_setting_selector"
android:text="設(shè)置" />
</RadioGroup>
</RelativeLayout>
2. Activity 類(lèi)
public class Style2Activity extends AppCompatActivity {
private ViewPager mViewPager;
private RadioGroup mTabRadioGroup;
private List<Fragment> mFragments;
private FragmentPagerAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style2);
initView();
}
private void initView() {
// find view
mViewPager = findViewById(R.id.fragment_vp);
mTabRadioGroup = findViewById(R.id.tabs_rg);
// init fragment
mFragments = new ArrayList<>(4);
mFragments.add(BlankFragment.newInstance("今日"));
mFragments.add(BlankFragment.newInstance("記錄"));
mFragments.add(BlankFragment.newInstance("通訊錄"));
mFragments.add(BlankFragment.newInstance("設(shè)置"));
// init view pager
mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), mFragments);
mViewPager.setAdapter(mAdapter);
// register listener
mViewPager.addOnPageChangeListener(mPageChangeListener);
mTabRadioGroup.setOnCheckedChangeListener(mOnCheckedChangeListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
mViewPager.removeOnPageChangeListener(mPageChangeListener);
}
private ViewPager.OnPageChangeListener mPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
RadioButton radioButton = (RadioButton) mTabRadioGroup.getChildAt(position);
radioButton.setChecked(true);
}
@Override
public void onPageScrollStateChanged(int state) {
}
};
private RadioGroup.OnCheckedChangeListener mOnCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < group.getChildCount(); i++) {
if (group.getChildAt(i).getId() == checkedId) {
mViewPager.setCurrentItem(i);
return;
}
}
}
};
private class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mList;
public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.mList = list;
}
@Override
public Fragment getItem(int position) {
return this.mList == null ? null : this.mList.get(position);
}
@Override
public int getCount() {
return this.mList == null ? 0 : this.mList.size();
}
}
}
這里唯一注意點(diǎn)的就是兩個(gè)監(jiān)聽(tīng)事件,要實(shí)現(xiàn)底部導(dǎo)航按鈕和頁(yè)面的聯(lián)動(dòng)。
四、帶頁(yè)面跳轉(zhuǎn)功能的底部導(dǎo)航
很多 APP 的底部導(dǎo)航欄中間有一個(gè)很大的按鈕,點(diǎn)擊后通常是打開(kāi)一個(gè)新的頁(yè)面,這里我們要實(shí)現(xiàn)的就是這種底部導(dǎo)航。
依舊是使用 RadioGroup 來(lái)做,只不過(guò)中間一個(gè) tab 我們先用一個(gè)空的 View 來(lái)占位,然后在這個(gè) View 的位置放置一個(gè)較大的按鈕來(lái)覆蓋住。
1. 布局文件
<?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=".style3.Style3Activity">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/tabs_rg" />
<RadioGroup
android:id="@+id/tabs_rg"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:background="#dcdcdc"
android:orientation="horizontal">
<RadioButton
android:id="@+id/today_tab"
style="@style/Custom.TabRadioButton"
android:checked="true"
android:drawableTop="@drawable/tab_sign_selector"
android:text="今日" />
<RadioButton
android:id="@+id/record_tab"
style="@style/Custom.TabRadioButton"
android:drawableTop="@drawable/tab_record_selector"
android:text="記錄" />
<View style="@style/Custom.TabRadioButton" />
<RadioButton
android:id="@+id/contact_tab"
style="@style/Custom.TabRadioButton"
android:drawableTop="@drawable/tab_contact_selector"
android:text="通訊錄" />
<RadioButton
android:id="@+id/settings_tab"
style="@style/Custom.TabRadioButton"
android:drawableTop="@drawable/tab_setting_selector"
android:text="設(shè)置" />
</RadioGroup>
<ImageView
android:id="@+id/sign_iv"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@android:color/transparent"
android:src="@mipmap/sign" />
</RelativeLayout>
2. Activity 類(lèi)
public class Style3Activity extends AppCompatActivity {
private RadioGroup mTabRadioGroup;
private SparseArray<Fragment> mFragmentSparseArray;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style3);
initView();
}
private void initView() {
mTabRadioGroup = findViewById(R.id.tabs_rg);
mFragmentSparseArray = new SparseArray<>();
mFragmentSparseArray.append(R.id.today_tab, BlankFragment.newInstance("今日"));
mFragmentSparseArray.append(R.id.record_tab, BlankFragment.newInstance("記錄"));
mFragmentSparseArray.append(R.id.contact_tab, BlankFragment.newInstance("通訊錄"));
mFragmentSparseArray.append(R.id.settings_tab, BlankFragment.newInstance("設(shè)置"));
mTabRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// 具體的fragment切換邏輯可以根據(jù)應(yīng)用調(diào)整,例如使用show()/hide()
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
mFragmentSparseArray.get(checkedId)).commit();
}
});
// 默認(rèn)顯示第一個(gè)
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container,
mFragmentSparseArray.get(R.id.today_tab)).commit();
findViewById(R.id.sign_iv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Style3Activity.this, SignActivity.class));
}
});
}
}
注意:
如果這里你也想使用 ViewPager 來(lái)展示 Fragment 的話(huà),一定要注意這里的 RadioGroup 中間有一個(gè)占位的 View,即兩者的監(jiān)聽(tīng)事件里,實(shí)現(xiàn)聯(lián)動(dòng)時(shí)要考慮多個(gè)這個(gè) View 的存在。
代碼地址: https://gitee.com/afei_/BottomTabbar
到此這篇關(guān)于Android底部導(dǎo)航欄的三種風(fēng)格實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Android底部導(dǎo)航欄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開(kāi)發(fā)注解排列組合出啟動(dòng)任務(wù)ksp
這篇文章主要為大家介紹了Android開(kāi)發(fā)注解排列組合出啟動(dòng)任務(wù)ksp示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Android實(shí)現(xiàn)Banner界面廣告圖片循環(huán)輪播(包括實(shí)現(xiàn)手動(dòng)滑動(dòng)循環(huán))
這篇文章主要介紹了Android實(shí)現(xiàn)Banner界面廣告圖片循環(huán)輪播(包括實(shí)現(xiàn)手動(dòng)滑動(dòng)循環(huán))的相關(guān)資料,需要的朋友可以參考下2016-02-02
Android安裝apk文件并適配Android 7.0詳解
這篇文章主要介紹了Android安裝apk文件并適配Android 7.0詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android自定義WheelView地區(qū)選擇三級(jí)聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android自定義WheelView地區(qū)選擇三級(jí)聯(lián)動(dòng)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
Android啟動(dòng)內(nèi)置APK和動(dòng)態(tài)發(fā)送接收自定義廣播實(shí)例詳解
這篇文章主要介紹了Android啟動(dòng)內(nèi)置APK和動(dòng)態(tài)發(fā)送接收自定義廣播實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android實(shí)現(xiàn)返回拍攝的圖片功能實(shí)例
這篇文章主要介紹了Android實(shí)現(xiàn)返回拍攝的圖片功能,以實(shí)例形式較為詳細(xì)的分析了Android返回拍攝圖片功能的具體步驟與實(shí)現(xiàn)方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
詳解Android Studio實(shí)現(xiàn)用戶(hù)登陸界面demo(xml實(shí)現(xiàn))
這篇文章主要介紹了詳解Android Studio實(shí)現(xiàn)用戶(hù)登陸界面demo,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05

