How to handle the back event in nested NavHostFragments? - android

I did take a look on the official website Nested Graph and searched related issues but have no luck on it.
When the nest graph and dynamic feature module comes up, I tried to combine "dynamic feature module", "Nested NavHostFragments" and "Nested Graph" into a separate module. But when I tried to handle the back button event, I have no idea on it.
I have the NavHostFragments in the "app" module and when the user navigation the account item on the bottom navigation view. It will prompt up a bottomsheetdialog, which contains a nested NavHostFragment and also its navigation graph. And those fragments are inside "account" module.
When I tried to navigation back by pressing back button in the account page, it does not get back the stacks inside the nested NavHostFragment. This setPrimaryNavigationFragment() function seems providing some clue for this issue but i have no luck on it.
That's the current behavior
MainActivity.kt (In "app" module)
class MainActivity : AppCompatActivity() {
private lateinit var toolbar: Toolbar
private lateinit var appBarConfiguration: AppBarConfiguration
private val navController: NavController by lazy {
findNavController(R.id.nav_host_fragment)
}
private val listener =
NavController.OnDestinationChangedListener { controller, destination, arguments ->
model.triggerDestination(destinationId = destination.id)
}
private val model: MainActivityViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_explore
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
model.notificationPageSelect.observe(this, EventObserver {
when (it) {
R.id.navigation_explore -> updateAppBarBg(R.drawable.explore_appbar_bg_gradient)
R.id.navigation_notifications -> updateAppBarBg(R.drawable.notification_appbar_bg_gradient)
}
})
}
private fun updateAppBarBg(appBg: Int) {
toolbar.setBackgroundResource(appBg)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.overflow_menu, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration)
}
override fun onResume() {
super.onResume()
navController.addOnDestinationChangedListener(listener)
}
override fun onPause() {
super.onPause()
navController.removeOnDestinationChangedListener(listener)
}
}
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"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="0dp"
android:layout_height="50dp"
android:background="#drawable/explore_appbar_bg_gradient"
android:theme="#style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
app:navGraph="#navigation/mobile_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:labelVisibilityMode="labeled"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:menu="#menu/bottom_nav_menu"
app:layout_anchorGravity="bottom|right|end"
android:layout_gravity="bottom|end"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
AccountListDialogFragment.kt (in "account" module)
class AccountListDialogFragment : BottomSheetDialogFragment() {
private lateinit var viewModel: SettingsViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_account, container, false)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(SettingsViewModel::class.java)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupFullExpand()
}
}
fragment_account.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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/account" />
</androidx.constraintlayout.widget.ConstraintLayout>

Related

Set a Fragment inside a Fragment

I have seen similar questions here, but none of them helps.
I have MainActivity and a few Fragments which works fine, but I want to set one fragment inside of another.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomMenu)
val hostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as NavHostFragment
val navigationController = hostFragment.navController
bottomNavigationView.setupWithNavController(navigationController)
setupActionBarWithNavController(navigationController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragmentContainer)
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
Parent Fragment:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_main, container, false)
incomeButton = view.findViewById(R.id.addIncomeButton)
expenseButton = view.findViewById(R.id.addExpenseButton)
val childFragment: Fragment = ChartFragment()
val transaction: FragmentTransaction = childFragmentManager.beginTransaction()
transaction.replace(R.id.childFragment, childFragment).commit()
return view
}
Child Fragment:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
return ComposeView(requireContext()).apply {
setContent {
Text(
text = "here is another important code",
fontSize = 28.sp
)
}
}
The layouts for Activity:
<?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=".MainActivity">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomMenu"
android:layout_width="match_parent"
android:layout_height="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:menu="#menu/bottom_menu" />
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="475dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottomMenu"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/nav_map" />
</androidx.constraintlayout.widget.ConstraintLayout>
The layouts for Fragment:
<?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=".fragments.MainFragment">
<Button
android:id="#+id/addIncomeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="21dp"
android:layout_marginBottom="21dp"
android:backgroundTint="#color/primary"
android:text="#string/addIncomeButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="#+id/addExpenseButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="21dp"
android:layout_marginBottom="10dp"
android:backgroundTint="#color/red"
android:text="#string/addExpenseButton"
app:layout_constraintBottom_toTopOf="#+id/addIncomeButton"
app:layout_constraintEnd_toEndOf="parent" />
<FrameLayout
android:id="#+id/forChart"
android:layout_width="match_parent"
android:layout_height="350dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The most of the same questions' solvations say to use childFragmentManager so do I but it doesn't work.
I get an error java.lang.IllegalArgumentException: No view found for id 0x7f08023f.
I guess I do not understand something, but I can't realize what.
Thank you!
Seems that you're mixing the ids of the container for the transaction - that's also what the error says. You're trying to put the ChartFragment into a container with R.id.childFragment id:
transaction.replace(R.id.childFragment, childFragment).commit()
And from what I see in the MainFragment layout, the container id is R.id.forChart. Try changing it to this:
transaction.replace(R.id.forChart, childFragment).commit()

kotlin java.lang.NullPointerException: null cannot be cast to non-null type androidx.navigation.fragment.NavHostFragment

I looked at past questions but i can't still solve my problem
I am getting this error : java.lang.NullPointerException: null cannot be cast to non-null type androidx.navigation.fragment.NavHostFragment
My MainActivity code is :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController =navHostFragment.navController
val navBottomView: BottomNavigationView = findViewById(R.id.bottomNavigation)
navBottomView.setupWithNavController(navController)
}
}
My HomeFragment code is this
class HomeFragment : Fragment() {
private var activity: MainActivity?= null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity = activity
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view : View = inflater.inflate(R.layout.fragment_home,container,false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
ActivityMain.xml code is here too :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#id/app_bar_layout" >
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graoh" />
</FrameLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<androidx.appcompat.widget.Toolbar
android:id="#+id/dashboard_toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#android:color/white">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
app:menu="#menu/bottom_nav_menu"
app:labelVisibilityMode="unlabeled"
android:layout_marginRight="15dp"/>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
I can't run my app. If some one can help me it will be perfect
The problem is in the MainActivity where you do not have setContentView(R.id.activity_main)
extra notes I have noticed
in your homeFragment you have:
activity = activity // which is self assign
and in your main activity xml you have a typo in the following line:
app:navGraph="#navigation/nav_graoh"
and you are missing the closing tag of relative layout

BottomNavigationView Isn't Showing on Emulator

I'm trying to setup a BottomNavigationView on my MainActivity, but it's only showing in my activity_main.xml and not the emulator. Should I be setting something up in my MainActivity.kt to make it visible on the emulator? Thanks!
// activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/nav_view"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
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" >
</com.google.android.material.bottomnavigation.BottomNavigationView>
</RelativeLayout>
// MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
// Screenshots
Update
I'm having troubles getting my app to run on a device. Is it because I'm setting something wrong in my OnCreate?
// MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(setOf(R.layout.fragment_news_feed, R.layout.fragment_friends, R.layout.fragment_messaging, R.layout.fragment_notifications, R.layout.fragment_menu))
setupActionBarWithNavController(navController, appBarConfiguration)
bottomNavigationView.setupWithNavController(navController)
}
Just try this. works for me.
setContentView(R.layout.activity_main);
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main);
}
}
you should set up your menu in the onCrate.
Example:
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.id_ your_bottomNavigationView)
val navController = findNavController(R.id.your_fragment)
val appBarConfiguration = AppBarConfiguration(setOf(R.id.your_fragment1, R.id.your_fragment2, R.id.your_fragment3, R.id.your_fragment4))
setupActionBarWithNavController(navController, appBarConfiguration)
bottomNavigationView.setupWithNavController(navController)
Call setContentView() in the onCreate Method.

MAPBOX: The map does not appear when I run the app with no errors (developing in Kotlin - for android - map in a fragment)

I am developing an app in Kotlin for android. I am adding Mapbox to this app.
In particular, I need to insert the Mapbox's map in FragmentHome.
The map needs to interact with other components, ad a navigation bar, and some buttons.
In the HostActivity I inserted
class HostActivity : AppCompatActivity() {
lateinit var googleSignInClient: GoogleSignInClient
private lateinit var navController: NavController
private val mAuth: FirebaseAuth = FirebaseAuth.getInstance()
private val db: FirebaseFirestore = FirebaseFirestore.getInstance()
private lateinit var drawerLayout: DrawerLayout
private lateinit var navViewBinding: DrawerHeaderLayoutBinding
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
val toolbar = customToolbar
setSupportActionBar(toolbar)
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
googleSignInClient = GoogleSignIn.getClient(this, gso)
drawerLayout = drawer_layout
navViewBinding = DrawerHeaderLayoutBinding.inflate(layoutInflater, navView, true)
val navHost =
supportFragmentManager.findFragmentById(R.id.navHostFragment) as NavHostFragment
navController = navHost.navController
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.main_graph)
navController.addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.onBoarding ||
destination.id == R.id.authFragment ||
destination.id == R.id.loginFragment ||
destination.id == R.id.signUpFragment
) {
toolbar.visibility = View.GONE
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
} else {
toolbar.visibility = View.VISIBLE
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
}
}
if (!Prefs.getInstance(this)!!.hasCompletedWalkthrough!!) {
if (mAuth.currentUser == null) {
graph.startDestination = R.id.authFragment
} else {
getUserData()
graph.startDestination = R.id.homeFragment
}
} else {
graph.startDestination = R.id.onBoarding
}
navController.graph = graph
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
navView.setupWithNavController(navController)
navView.setNavigationItemSelectedListener {
it.isChecked
drawerLayout.closeDrawers()
when (it.itemId) {
R.id.action_logout -> {
MyApplication.currentUser!!.active = false
FirestoreUtil.updateUser(MyApplication.currentUser!!) {
mAuth.signOut()
}
googleSignInClient.signOut()
MyApplication.currentUser = null
navController.navigate(R.id.action_logout)
}
}
true
}
}
private fun getUserData() {
val ref = db.collection("users").document(mAuth.currentUser!!.uid)
ref.get().addOnSuccessListener {
val userInfo = it.toObject(UserModel::class.java)
navViewBinding.user = userInfo
MyApplication.currentUser = userInfo
MyApplication.currentUser!!.active = true
FirestoreUtil.updateUser(MyApplication.currentUser!!) {
}
}.addOnFailureListener {
val intent = Intent(this, MyApplication::class.java)
startActivity(intent)
finish()
}
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController, drawerLayout)
}
}
and the XML graphic part related to the HostActivity is the following:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.instamobile.firebaseStarterKit.ui.activity.host.HostActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#id/navHostFragment"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/customToolbar"
style="#style/MyToolbarThemeSimple.Base"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/navHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/appBar"
app:navGraph="#navigation/main_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/drawer_header_layout"
app:itemIconTint="#color/colorPrimary"
app:menu="#menu/drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
In the HomeFragment I put only the map and a navigation bar, as you can see in the following code:
class HomeFragment : Fragment() {
private var mapView: MapView? = null
#Nullable
override fun onCreateView(
inflater: LayoutInflater,
#Nullable container: ViewGroup?,
#Nullable savedInstanceState: Bundle?
): View? {
Mapbox.getInstance(
context!!.applicationContext,
"******KEY******"
)
val view: View = inflater.inflate(R.layout.fragment_home, container, false)
mapView = view.findViewById<View>(R.id.mapView) as MapView
mapView!!.onCreate(savedInstanceState)
return view
}
override fun onStart() {
super.onStart()
mapView!!.onStart()
}
override fun onResume() {
super.onResume()
mapView!!.onResume()
}
override fun onPause() {
super.onPause()
mapView!!.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView!!.onSaveInstanceState(outState)
}
override fun onLowMemory() {
super.onLowMemory()
mapView!!.onLowMemory()
}
override fun onDestroyView() {
super.onDestroyView()
mapView!!.onDestroy()
}
}
Finally, the XML code related the HomeFragment graphic part is the following:
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.fragment.home.HomeFragment">
<com.mapbox.mapboxsdk.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:layout_gravity="bottom|right"
android:clickable="true"
android:focusable="true"
app:backgroundTint="#4CAF50"
app:srcCompat="#drawable/ic_navigation_white_24dp"
tools:ignore="ContentDescription,MissingConstraints,RtlHardcoded,VectorDrawableCompat" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginBottom="100dp"
android:layout_gravity="right|bottom"
android:clickable="true"
android:focusable="true"
app:backgroundTint="#4CAF50"
app:srcCompat="#drawable/ic_taxi"
tools:ignore="ContentDescription,DuplicateIds,MissingConstraints,RtlHardcoded,VectorDrawableCompat" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_gravity="top|left"
android:clickable="true"
android:focusable="true"
app:backgroundTint="#4CAF50"
app:srcCompat="#drawable/ic_search"
tools:ignore="ContentDescription,DuplicateIds,MissingConstraints,RtlHardcoded,VectorDrawableCompat" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginBottom="25dp"
android:layout_gravity="bottom|left"
android:clickable="true"
android:focusable="true"
app:backgroundTint="#4CAF50"
app:srcCompat="#drawable/ic_filter"
tools:ignore="ContentDescription,DuplicateIds,MissingConstraints,RtlHardcoded,VectorDrawableCompat" />
</com.mapbox.mapboxsdk.maps.MapView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mapView"
app:menu="#menu/bottom_navigation_menu"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The code run, with no errors, but the map does not appear.
Are we doing well?
We cannot find any error in the code. Could you?
Many thanks.
Best
I have the same problem.
I resolved it by the use of the call to getMapAsync.
You have to add this code before return view in HomeFragment.
mapView!!.getMapAsync { mapboxMap ->
mapboxMap.setStyle(Style.MAPBOX_STREETS) {
}

searchview.setonquerytextlistener() type mismatch in Navigation Fragment in Kotlin

I'm getting a "type mismatch required OnQueryTextListener!" error when trying to implement searchview in Kotlin in a Navigation Fragment. I've searched as many samples and stackoverflow questions as I could and everything says my code should be correct. Note that my searchview is PERSISTANT (not part of the menu), so I cannot do a menu.finditem.
Here is my HomeFragment code :
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
println("***************** Home Fragment *******************")
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
// task HERE
return false
}
override fun onQueryTextChange(newText: String): Boolean {
return false
}
})
}
and the layout code:
<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"
android:background="#color/materialBackgroundGrey">
<androidx.cardview.widget.CardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:iconifiedByDefault="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:queryBackground="#null">
<SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:queryHint="Search"
app:iconifiedByDefault="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.cardview.widget.CardView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#color/colorWhite"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/cardView"
app:layout_constraintBottom_toBottomOf="parent"
/>
There are two SearchView widgets:
android.widget.SearchView
androidx.appcompat.widget.SearchView
These fill the same role but are not compatible, and their nested interfaces, like OnQueryTextListener, are not compatible.
Make sure that you use the same one both in resources (such as your layout) and in any import statements. If you are using AppCompat, you probably want androidx.appcompat.widget.SearchView.

Categories

Resources