简体   繁体   中英

Bottom Navigation Bar Floating Button with action covering the whole screen - how to do this?

I have an Android application with Bottom Navigation Bar. In the Main Activity I have a floating button and when I press it, I would like to open a Fragment (or another activity?) that will cover the whole screen (the Bottom NavBar and other content will be below my new opened fragment) . I would like to add that this newly opened fragment will be used for adding some item and when the user fills all fileds like name, weight etc. and click "add", the fragment should be closed and we should see our bottom nav bar with its' fragments.

Could you provide the solution to my problem? I would be grateful for some code enabling to do this!

Here are the most important parts of my code:

activity_main.xml:

<?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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="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_nav_menu" />

    <fragment
        android:id="@+id/nav_host_fragment_activity_main"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0"
        app:navGraph="@navigation/mobile_navigation" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/buttonAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="84dp"
        android:contentDescription="@string/add_button"
        android:src="@drawable/ic_add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt:

package com.example.myapp

import android.os.Bundle
import android.view.View
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.myapp.databinding.ActivityMainBinding
import com.example.myapp.ui.AddProductFragment
import com.google.android.material.snackbar.Snackbar

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val navView: BottomNavigationView = binding.navView

        val navController = findNavController(R.id.nav_host_fragment_activity_main)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(setOf(
                R.id.navigation_expiring, R.id.navigation_storages, R.id.navigation_notifications))
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)

        // floating button:
        val buttonAdd: View = findViewById(R.id.buttonAdd)
        buttonAdd.setOnClickListener {
            //navigate(R.id.action_login_to_registration)
            //view.findNavController().navigate(R.id.actionAddProduct)
            supportFragmentManager
                .beginTransaction().add(R.id.nav_host_fragment_activity_main, AddProductFragment())
                .commit()
        }
    }
}

fragment_storages.xml: (other fragments I already have are almost the same)

<?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"
    tools:context=".ui.storages.StoragesFragment">

    <TextView
        android:id="@+id/text_dashboard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:textAlignment="center"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

StoragesFragment.kt: (other fragments I already have are almost the same)

package com.example.myapp.ui.storages

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.example.myapp.databinding.FragmentStoragesBinding

class StoragesFragment : Fragment() {

    private var _binding: FragmentStoragesBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {
        val dashboardViewModel =
                ViewModelProvider(this).get(StoragesViewModel::class.java)

        _binding = FragmentStoragesBinding.inflate(inflater, container, false)
        val root: View = binding.root

        val textView: TextView = binding.textDashboard
        dashboardViewModel.text.observe(viewLifecycleOwner) {
            textView.text = it
        }
        return root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

fragment_add_product.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"
    tools:context=".ui.AddProductFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Add Product Fragment" />

</androidx.constraintlayout.widget.ConstraintLayout>

AddProductFragment.kt:

package com.example.myapp.ui

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.myapp.R

class AddProductFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_add_product, container, false)
    }
}

bottom_nav_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_expiring"
        android:icon="@drawable/ic_expiring"
        android:title="@string/title_expiring" />

    <item
        android:id="@+id/navigation_storages"
        android:icon="@drawable/ic_storages"
        android:title="@string/title_storages" />

    <item
        android:id="@+id/navigation_notifications"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_notifications" />

</menu>

mobile_navigation.xml:

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/mobile_navigation"
    app:startDestination="@+id/navigation_expiring">

    <fragment
        android:id="@+id/navigation_expiring"
        android:name="com.example.myapp.ui.expiring.ExpiringFragment"
        android:label="@string/title_expiring"
        tools:layout="@layout/fragment_expiring" >
    </fragment>

    <fragment
        android:id="@+id/navigation_storages"
        android:name="com.example.myapp.ui.storages.StoragesFragment"
        android:label="@string/title_storages"
        tools:layout="@layout/fragment_storages" />

    <fragment
        android:id="@+id/navigation_notifications"
        android:name="com.example.myapp.ui.notifications.NotificationsFragment"
        android:label="@string/title_notifications"
        tools:layout="@layout/fragment_notifications" />

    <fragment
        android:id="@+id/navigation_add_product"
        android:name="com.example.myapp.ui.AddProductFragment"
        android:label="Add product"
        tools:layout="@layout/fragment_notifications" />

</navigation>

Instead of navigating to the fragment, try to start another Activity after clicking "Add" floating action button. Your new Activity will not have bottom navigation bar as you expected.

I have a solution. It worked for me. First, you just write this code in your activity where BottomNavigationView is located.

MainActivity.xml

 binding.fab.setOnClickListener(object : View.OnClickListener {
        override fun onClick(view: View) {
            binding.bottomNavigationView.selectedItemId = R.id.nav_cards
            navController.navigate(R.id.nav_cards)
        }
    })
    binding.bottomNavigationView.setOnItemSelectedListener {
        when (it.itemId) {
            R.id.nav_home -> {
                navController.navigate(R.id.nav_home)
                true
            }
            R.id.nav_book -> {
                navController.navigate(R.id.nav_book)
                true
            }
            R.id.nav_bookmark -> {
                navController.navigate(R.id.nav_bookmark)
                true
            }
            R.id.nav_settings -> {
                navController.navigate(R.id.nav_settings)
                true
            }
            else -> false
        }
    }

After that, you should use onBackPressed function. Otherwise, you may appear another problem which belongs to collecting backStacks.

  override fun onBackPressed() {
    if (binding.bottomNavigationView.selectedItemId == R.id.nav_home) {
        binding.bottomNavigationView.selectedItemId = R.id.nav_home
        super.onBackPressed()
        finish()
    } else {
        binding.bottomNavigationView.selectedItemId = R.id.nav_home
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM