Android kotlin 实现底部导航栏(显示角标)与页面功能

一、实现效果

二、引入依赖

appbuild.gradle在添加以下代码

implementation 'com.google.android.material:material:1.4.0'

三、实现源码

● 非左右滑动页面与底部导航栏

1、Fragment

1、4个页面代码,创建4个即可,创建方法相同,以下只示例一个
示例:
Fragment1.kt

package com.demo.test.fragment

import com.demo.test.R

class Fragment1 : BaseFragment() {
    override fun layoutRes(): Int = R.layout.fragment1

    companion object {
        fun newInstance() = Fragment1()
    }
}

fragment1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="30dp"
        android:text="首页"/>
</LinearLayout>

4个页面代码要继承父类BaseFragment()BaseFragment.kt

package com.demo.test.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

open class BaseFragment : Fragment(){

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(layoutRes(), container, false)
    }

    open fun layoutRes() = 0
}

2、视图实现

FragmentActivity.kt

package com.demo.test

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.demo.test.common.ScrollToTop
import com.demo.test.fragment.Fragment1
import com.demo.test.fragment.Fragment2
import com.demo.test.fragment.Fragment3
import com.demo.test.fragment.Fragment4
import kotlinx.android.synthetic.main.fragment.bottomNavigationView
import kotlinx.android.synthetic.main.fragment.viewPager


//非左右滑动页面与底部导航栏
class FragmentActivity : AppCompatActivity() {

    private lateinit var fragments: Map<Int, Fragment>
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.fragment)
        viewPager.visibility = View.GONE
        fragments = mapOf(
            R.id.fragment1 to createFragment(Fragment1::class.java),
            R.id.fragment2 to createFragment(Fragment2::class.java),
            R.id.fragment3 to createFragment(Fragment3::class.java),
            R.id.fragment4 to createFragment(Fragment4::class.java)
        )

        bottomNavigationView.run {
            setOnNavigationItemSelectedListener { menuItem ->
                showFragment(menuItem.itemId)
                true
            }
            setOnNavigationItemReselectedListener { menuItem ->
                val fragment = fragments.entries.find {
                    it.key == menuItem.itemId
                }?.value
                if (fragment is ScrollToTop) {
                    fragment.scrollToTop()
                }
            }
        }

        showBadgeView(2, 99)

        if (savedInstanceState == null) {
            val initialItemId = R.id.fragment1
            bottomNavigationView.selectedItemId = initialItemId
            showFragment(initialItemId)
        }
    }

    private fun createFragment(clazz: Class<out Fragment>): Fragment {
        var fragment = supportFragmentManager.fragments.find { it.javaClass == clazz }
        if (fragment == null) {
            fragment = when (clazz) {
                Fragment1::class.java -> Fragment1.newInstance()
                Fragment2::class.java -> Fragment2.newInstance()
                Fragment3::class.java -> Fragment3.newInstance()
                Fragment4::class.java -> Fragment4.newInstance()
                else ->
                    throw IllegalArgumentException("argument ${clazz.simpleName} is illegal")
            }
        }
        return fragment
    }

    private fun showFragment(menuItemId: Int) {
        val currentFragment = supportFragmentManager.fragments.find {
            it.isVisible && it in fragments.values
        }
        val targetFragment = fragments.entries.find {
            it.key == menuItemId
        }?.value
        supportFragmentManager.beginTransaction().apply {
            currentFragment?.let {
                if (it.isVisible)
                    hide(it)
            }
            targetFragment?.let {
                if (it.isAdded)
                    show(it)
                else
                    add(R.id.fl, it)
            }
        }.commit()
    }

    /**
     * BottomNavigationView显示角标
     * @param viewIndex tab索引
     * @param showNumber 显示的数字,小于等于0是将不显示
     */
    private fun showBadgeView(viewIndex: Int, showNumber: Int) {
        bottomNavigationView.getOrCreateBadge(R.id.fragment3).apply {
//            backgroundColor = ContextCompat.getColor(this@FragmentActivity, R.color.red)
            badgeTextColor = ContextCompat.getColor(this@FragmentActivity, R.color.white)
            number = showNumber
        }

//        val menuItemId = bottomNavigationView.menu.getItem(viewIndex).itemId
//        val badge : BadgeDrawable= bottomNavigationView.getOrCreateBadge(menuItemId)
//        badge.number = showNumber
    }
}

fragment.kt,四个页面、底部带图标和文字的导航键

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/fl"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_gravity="bottom"
        android:background="@drawable/ripple_item_select"
        app:itemIconTint="@color/selector_bottom_navigation_item"
        app:itemTextColor="@color/selector_bottom_navigation_item"
        app:labelVisibilityMode="labeled"
        app:menu="@menu/menu_bottom_navigation" />
</LinearLayout>

ripple_item_select.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/colorRipple">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/bgColorPrimary" /><!--<color name="bgColorPrimary">#FFFFFF</color>-->
        </shape>
    </item>
</selector>

selector_bottom_navigation_item.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--  <color name="colorAccent">#D82637</color>  -->
    <item android:color="@color/colorAccent" android:state_checked="true" />
    <!--  <color name="textColorThird">#9297A2</color>  -->
    <item android:color="@color/textColorThird" android:state_checked="false" />
</selector>

使用menu属性定义底部条目:

  1. res文件下创建menu文件夹
  2. menu文件下创建条目的menu_bottom_navigation.xml
  3. 设置idicontitle等属性

在这里插入图片描述
四个icon图标是在在android studio系统中添加资源图标

AndroidManifest.xml中的application下的改主题:

android:theme="@style/AppTheme">

styles.xml中改主题:
在这里插入图片描述
ScrollToTop.kt

package com.demo.test.common

/**
 * Created by xiaojianjun on 2019-11-15.
 */
interface ScrollToTop {
    fun scrollToTop()
}

● 左右滑动页面与底部导航栏

1、页面适配器

MyPagerAdapter.kt

package com.demo.test.pager

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter

class MyPagerAdapter(fm: FragmentManager, private val fragmentList:MutableList<Fragment>) : FragmentStatePagerAdapter(fm) {

    override fun getCount(): Int {
        return fragmentList.size
    }

    override fun getItem(position: Int): Fragment {
        return fragmentList[position]
    }
}

2、视图实现

FragmentAndPageSlideActivity.kt

package com.demo.test

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import com.demo.test.pager.MyPagerAdapter
import com.demo.test.fragment.Fragment2
import com.demo.test.fragment.Fragment3
import com.demo.test.fragment.Fragment4
import com.demo.test.fragment.Fragment1
import kotlinx.android.synthetic.main.fragment.*

//左右滑动页面与底部导航栏
class FragmentAndPageSlideActivity : AppCompatActivity() {

    private var fragmentList: MutableList<Fragment> = ArrayList()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.fragment)
        fl.visibility = View.GONE
        initData()
        val adapter = MyPagerAdapter(supportFragmentManager, fragmentList)
        viewPager.adapter = adapter
        //页面更改监听
        viewPager.setOnPageChangeListener(object : OnPageChangeListener {
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {

            }

            override fun onPageSelected(position: Int) {
                when (position) {
                    0 -> bottomNavigationView.selectedItemId = R.id.fragment1
                    1 -> bottomNavigationView.selectedItemId = R.id.fragment2
                    2 -> bottomNavigationView.selectedItemId = R.id.fragment3
                    3 -> bottomNavigationView.selectedItemId = R.id.fragment4
                }
            }

            override fun onPageScrollStateChanged(state: Int) {

            }
        })
        //图标选择监听
        bottomNavigationView.setOnNavigationItemSelectedListener {
            when (it.itemId) {
                R.id.fragment1 -> viewPager.currentItem = 0
                R.id.fragment2 -> viewPager.currentItem = 1
                R.id.fragment3 -> viewPager.currentItem = 2
                R.id.fragment4 -> viewPager.currentItem = 3
            }
            return@setOnNavigationItemSelectedListener true
        }
    }

    private fun initData() {
        val fragment1 = Fragment1.newInstance()
        fragmentList.add(fragment1)
        val fragment2 = Fragment2.newInstance()
        fragmentList.add(fragment2)
        val fragment3 = Fragment3.newInstance()
        fragmentList.add(fragment3)
        val fragment4 = Fragment4.newInstance()
        fragmentList.add(fragment4)
    }
}

主页视图

MainActivity.kt

package com.demo.test

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //非左右滑动页面与底部导航栏
        button1.setOnClickListener {
            val intent = Intent(this@MainActivity, FragmentActivity::class.java)
            startActivity(intent)
        }

        //左右滑动页面与底部导航栏
        button2.setOnClickListener {
            val intent = Intent(this@MainActivity, FragmentAndPageSlideActivity::class.java)
            startActivity(intent)
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="非左右滑动页面与底部导航栏"
        android:textColor="@color/black"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="左右滑动页面与底部导航栏"
        android:textColor="@color/black"/>
</LinearLayout>

______________________________________________

一、在底部导航栏中的居中Icon无title

如下图:
在这里插入图片描述

修改代码:

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout
    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">

    <TextView
        android:id="@+id/tvHeaderTitle"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/white"
        android:elevation="2dp"
        android:fontFamily="sans-serif-black"
        android:gravity="center"
        android:text="@string/main_mine"
        android:textColor="@color/purple"
        android:textSize="@dimen/dp_18"
        app:layout_constraintTop_toTopOf="parent"/>

        <FrameLayout
            android:id="@+id/fl"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintLeft_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tvHeaderTitle"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:elevation="8dp"
        app:itemIconSize="29dp"
        app:itemIconTint="@color/selector_bottom_navigation_item"
        app:itemRippleColor="@color/yellow"
        app:itemTextColor="@color/selector_bottom_navigation_item"
        app:labelVisibilityMode="labeled"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/menu_bottom_navigation"/>

    <ImageView
        android:id="@+id/navigation_center_image"
        android:layout_width="29dp"
        android:layout_height="29dp"
        android:layout_gravity="center"
        android:elevation="10dp"
        android:src="@drawable/ic_add"
        app:layout_constraintBottom_toBottomOf="@id/bottomNavigationView"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@id/bottomNavigationView" />

</androidx.constraintlayout.widget.ConstraintLayout>

menu_bottom_navigation.xml,如下图:
在这里插入图片描述

二、BottomNavigationView常用属性

  • app:itemIconTint:指定底部导航栏元素图标的着色方式,默认元素选中是iocn颜色为@color/colorPrimary
  • app:itemTextColor:指定底部导航栏元素文字的着色方式
  • app:menu:使用Menu的形式为底部导航栏指定元素
  • app:itemIconSize:图标大小,默认24dp

  • app:labelVisibilityMode:文字的显示模式
    • labeled:保持所有文字便签显示
    • unlabeled:只显示图标
    • selected:在选中的时候显示文字标签,有动画效果
    • auto:在1-3个按钮时使用labeled,大于3个按钮使用selected

  • app:itemRippleColor:点击后的水波纹颜色
  • app:elevation:控件顶部的阴影
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彬sir哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值