Android BottomNavigationView with fragments
The following is an example for using BottomNavigationView alone with Fragments in Android. On each button click on the BottomNavigationView, the old fragment in the framelayout will be replaced by a new fragment.
navigation.xml, the menu for the bottom navigation bar.
activity_main.xml, the layout for the main activity, containing a framelayout for housing the fragments and a BottomNavigationView.
dashboard.xml, the layout file for the dashboard fragment. The layout files for favorites, home, notifications and settings are the same but with different text string in the TextView.
strings.xml, String resource file.
Button Navi Fragment Home Dashboard Notifications Favorites Settings
BaseActivity.kt, the base activity with activity life cycle callbacks for logging the callback calls.
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
abstract class BaseActivity : AppCompatActivity() {
abstract val TAG : String
abstract val LAYOUT_ID : Int
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate")
setContentView(LAYOUT_ID)
}
override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestart")
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
}
}
ABaseFrag.kl, the base fragment with fragment life cycle callbacks for logging callback calls.
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
abstract class ABaseFrag : Fragment() {
abstract val TAG : String
abstract val LAYOUT_ID : Int
override fun onAttach(context: Context?) {
super.onAttach(context)
Log.d(TAG, "onAttach")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
Log.d(TAG, "onCreateView")
return inflater.inflate(LAYOUT_ID, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d(TAG, "onViewCreated")
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Log.d(TAG, "onActivityCreated")
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop")
}
override fun onDestroyView() {
super.onDestroyView()
Log.d(TAG, "onDestroyView")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
}
override fun onDetach() {
super.onDetach()
Log.d(TAG, "onDetach")
}
}
MainActivity.kt, the main activity for initializing the fragments and bottom navigation bar.
import android.os.Bundle
import android.support.design.widget.BottomNavigationView
import android.util.Log
import com.example.buttonnavifragment.fragments.*
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : BaseActivity() {
override val TAG = MainActivity::class.java.simpleName
override val LAYOUT_ID = R.layout.activity_main
val FRAG_HOME = "home_frag"
val FRAG_DASHBOARD = "dashboard_frag"
val FRAG_NOTIFICATIONS = "notifications_frag"
val FRAG_FAVORITES = "favorites_frag"
val FRAG_SETTINGS = "settings_frag"
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
loadFragByTag(FRAG_HOME)
return@OnNavigationItemSelectedListener true
}
R.id.navigation_dashboard -> {
loadFragByTag(FRAG_DASHBOARD)
return@OnNavigationItemSelectedListener true
}
R.id.navigation_notifications -> {
loadFragByTag(FRAG_NOTIFICATIONS)
return@OnNavigationItemSelectedListener true
}
R.id.navigation_favorites -> {
loadFragByTag(FRAG_FAVORITES)
return@OnNavigationItemSelectedListener true
}
R.id.navigation_settings -> {
loadFragByTag(FRAG_SETTINGS)
return@OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
BottomNavigationViewHelper.disableShiftMode(navigation)
loadFragByTag(FRAG_HOME)
}
private fun loadFragByTag(tag : String) {
var frag = supportFragmentManager.findFragmentByTag(tag)
if (frag == null) {
Log.d(TAG, "$tag not found, creating a new one.")
when (tag) {
FRAG_HOME -> {
frag = HomeFrag()
}
FRAG_DASHBOARD -> {
frag = DashboardFrag()
}
FRAG_NOTIFICATIONS -> {
frag = NotificationsFrag()
}
FRAG_FAVORITES -> {
frag = FavoritesFrag()
}
FRAG_SETTINGS -> {
frag = SettingsFrag()
}
}
} else {
Log.d(TAG, "$tag found.")
}
supportFragmentManager
.beginTransaction()
.replace(R.id.fl_main, frag, tag)
.commit()
}
}
HomeFrag.kt, the home fragment for showing home contents.
import com.example.buttonnavifragment.R
class HomeFrag : ABaseFrag() {
override val TAG = HomeFrag::class.java.simpleName
override val LAYOUT_ID = R.layout.fragment_home
}
BottomNavigationViewHelper.kt, a bottom navigation helper object for disabling the default shift behavior.
import android.support.design.internal.BottomNavigationItemView
import android.support.design.internal.BottomNavigationMenuView
import android.support.design.widget.BottomNavigationView
import android.util.Log
// https://stackoverflow.com/questions/40176244/how-to-disable-bottomnavigationview-shift-mode
object BottomNavigationViewHelper {
fun disableShiftMode(view: BottomNavigationView) {
val menuView = view.getChildAt(0) as BottomNavigationMenuView
try {
val shiftingMode = menuView.javaClass.getDeclaredField("mShiftingMode")
shiftingMode.isAccessible = true
shiftingMode.setBoolean(menuView, false)
shiftingMode.isAccessible = false
for (i in 0 until menuView.childCount) {
val item = menuView.getChildAt(i) as BottomNavigationItemView
item.setShiftingMode(false)
// set once again checked value, so view will be updated
item.setChecked(item.itemData.isChecked)
}
} catch (e: NoSuchFieldException) {
Log.e("BNVHelper", "Unable to get shift mode field", e)
} catch (e: IllegalAccessException) {
Log.e("BNVHelper", "Unable to change value of shift mode", e)
}
}
}
Search within Codexpedia
Search the entire web