Search code examples
androidkotlinandroid-fragmentsandroid-jetpack

Navigation won't render fragments


Ive recently started programming in android studio for a school project, and i cant seem to get this bottom navigation working. I've watched multiple video's on how to make a navigation using fragments. The problem is that everytime i try to navigate to a fragment it will make the icon go selected, but it won't render the fragment itself

Menu items
<item android:id="@+id/mainActivity" android:enabled="true" android:icon="@drawable/receipt" android:title=""/> <item android:id="@+id/firstFragment" android:enabled="true" android:icon="@drawable/search" android:title="" />


Main activity

    val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView);
    val navController = findNavController(R.id.fragment)

    bottomNavigationView.setupWithNavController(navController)


Main activity XML

<com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:itemIconTint="@color/black"
        app:itemTextColor="@color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:menu="@menu/menu"/>


    <fragment
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginEnd="411dp"
        android:layout_marginRight="411dp"
        android:layout_marginBottom="731dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/bottomNavigationView"
        app:navGraph="@navigation/my_nav"/> 

Navigation

<activity
    android:id="@+id/mainActivity"
    android:name="nl.bunus.bunusmobileapp.MainActivity"
    android:label="activity_main"
    tools:layout="@layout/activity_main" />
<fragment
    android:id="@+id/firstFragment"
    android:name="nl.bunus.bunusmobileapp.firstFragment"
    android:label="fragment_first"
    tools:layout="@layout/fragment_first" />

Solution

  • Problem

    You provide too less important code, but that's why I rebuild your target. And indeed there are some errors occuring. Mostly with dependencies and gradle versions. I think it would be best for all that I provide the whole code as snippets and at the end as project file download.

    Solution

    GRADLE & DEPENDENCIES

    Because of the gradle is important I want to point out that more closly. Your build.gradle("projectname"):

    buildscript {
        ext.kotlin_version = '1.3.61'
        repositories {
            google()
            mavenCentral()
        }
        dependencies {
            classpath "com.android.tools.build:gradle:7.0.0"
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    

    And also your build.gradle(module) with dependencies:

    plugins {
        id 'com.android.application'
        id 'kotlin-android'
        id 'kotlin-android-extensions'
    }
    
    android {
        compileSdk 32
    
        defaultConfig {
            applicationId "com.example.kotlinapplication"
            minSdk 30
            targetSdk 32
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        kotlinOptions {
            jvmTarget = '1.8'
        }
    }
    
    dependencies {
    
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.core:core-ktx:1.3.2'
        implementation 'androidx.appcompat:appcompat:1.4.0'
        implementation 'com.google.android.material:material:1.4.0'
        implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
        testImplementation 'junit:junit:4.+'
        androidTestImplementation 'androidx.test.ext:junit:1.1.3'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
        implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    }
    

    ACTIVITY

    Let's start with the MainActivity.kt that contains the BottomNavigationView with the loadFragment() method.

    Important: Don't forget the binding import shown below!:

    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            title=resources.getString(R.string.fragment1)
            loadFragment(FirstFragment())
            navigationView.setOnNavigationItemSelectedListener {
                when(it.itemId){
                    R.id.navigation_appoint-> {
                        title=resources.getString(R.string.fragment1)
                        loadFragment(FirstFragment())
                        return@setOnNavigationItemSelectedListener true
                    }
    
                    R.id.navigation_new_appoint-> {
                        title=resources.getString(R.string.second_menu)
                        loadFragment(SecondFragment())
                        return@setOnNavigationItemSelectedListener true
                    }
    
                    R.id.navigation_settings-> {
                        title=resources.getString(R.string.third_menu)
                        loadFragment(ThirdFragment())
                        return@setOnNavigationItemSelectedListener true
                    }
                }
                false
            }
        }
    
        private fun loadFragment(fragment: Fragment) {
            val transaction = supportFragmentManager.beginTransaction()
            transaction.replace(R.id.container, fragment)
            transaction.addToBackStack(null)
            transaction.commit()
        }
    }
    

    And it's layout activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        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"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        tools:context=".MainActivity">
    
        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    
        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/navigationView"
            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/bottom_navigation" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    FRAGMENT

    Now we have the Activity done there are 3 Fragment left. For simplicity I just post FirstFragment.kt and it's layout fragment_first.xml. You need to do the same for SecondFragment and ThirdFragment of course.

    class FirstFragment : Fragment() {
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            return inflater.inflate(R.layout.fragment_first, container, false)
        }
    }
    

    Matching layout:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#FF9800">
    
        <TextView android:layout_width="match_parent"
                  android:layout_centerInParent="true"
                  android:textAlignment="center"
                  android:textSize="18sp"
                  android:text="@string/first_menu"
                  android:layout_height="wrap_content"/>
    </RelativeLayout>
    

    MENU

    Now we are going to create a menu called bottom_navigation.xml in res/menu like this:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item
            android:id="@+id/navigation_appoint"
            android:icon="@drawable/ic_menu_black_24dp"
            android:title="@string/fragment1"/>
    
        <item
            android:id="@+id/navigation_new_appoint"
            android:icon="@drawable/ic_menu_black_24dp"
            android:title="@string/fragment2"/>
    
        <item
            android:id="@+id/navigation_settings"
            android:icon="@drawable/ic_menu_black_24dp"
            android:title="@string/fragment3"/>
    
    </menu>
    

    STRINGS AND ICON

    We need to define the strings for the TextView in strings.xml:

    <resources>
        <string name="app_name">KotlinApplication</string>
        <string name="fragment1">Fragment 1</string>
        <string name="fragment2">Fragment 2</string>
        <string name="fragment3">Fragment 3</string>
    
        <string name="first_menu">First Fragment</string>
        <string name="second_menu">Second Fragment</string>
        <string name="third_menu">Third Fragment</string>
    </resources>
    

    And also don't forget to add the icon (here I only used one for all fragments) in res/drawable called ic_menu_black_24dp.


    Download Project

    You can download the full project here (Hoster: Workupload)


    Result

    Finally we have one BottomNavigationView that navigates 3 Fragments through its items.

    BottomNavigationView with 3 Fragments