Reputation: 743
I have two fragments and I want to create interaction between them using backward button in action bar. Ideally, I would like the state of previous fragment was saved. I could find information for only activities.
For fragments I found this
private fun setupBackButton() {
if (activity is AppCompatActivity) {
(activity as AppCompatActivity?)?.supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
}
But it only displays back button, nothing happens by clicking.
EDIT
In the first fragment I call the second like:
val fragment = UserContentFragment()
fragment.setUser(item.user)
if (fragmentManager != null) {
fragmentManager!!
.beginTransaction()
.replace(R.id.main_layout, fragment)
.addToBackStack(null)
.commit()
}
This is my UserContentFragment
second fragment:
class UserContentFragment : Fragment() {
private lateinit var user: SearchUser
fun setUser(user: SearchUser) {
this.user = user
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val root = inflater.inflate(R.layout.fragment_user_content, container, false)
val userImage = root.findViewById(R.id.user_img) as ImageView
if (context != null) {
Glide.with(context!!)
.load(user.profile_pic_url)
.circleCrop()
.into(userImage)
}
val userName: TextView = root.findViewById(R.id.user_name)
userName.text = user.full_name
val toolbar: Toolbar = root.findViewById(R.id.toolbar)
toolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
setupBackButton()
return root
}
private fun setupBackButton() {
if (activity is AppCompatActivity) {
(activity as AppCompatActivity?)?.supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
}
}
And this its .xml file:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBlack">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/user_title"
android:layout_width="match_parent"
android:layout_height="100dp">
<ImageView
android:id="@+id/user_img"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/user_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="16dp"
android:textColor="@color/colorWhite"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/user_img"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
Upvotes: 4
Views: 16737
Reputation: 1
It's a late answer but I hope it will help someone.
I did it in Kotlin and the way I managed to make it work is:
In the MainActivity
I overrode the onSupportNavigateUp
:
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_activity_main)
return navController.navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
And declared the AppBarConfiguration
outside the onCreate()
Upvotes: 0
Reputation: 51
Zain's Second Option
is very good, but I'll show a different way for the part made in onCreate
, with usage of DataBinding
:
ActivityMainBinding.inflate(layoutInflater).run {
setContentView(root)
setSupportActionBar(toolbar)
(supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment)
as NavHostFragment).navController.let { navController ->
val appBarConfiguration = AppBarConfiguration(navController.graph)
toolbar.setupWithNavController(navController, appBarConfiguration)
}
}
Upvotes: 0
Reputation: 71
In Kotlin Fragment with Navigation.
First, you add setHasOptionsMenu(true)
in onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
Then override the onOptionsItemSelected
and when R.id.home
you can control BACK Button
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.getItemId()) {
android.R.id.home ->
findNavController().navigate(R.id.action_FragmentTwo_to_FragmentOne)
}
return true
}
Upvotes: 4
Reputation: 51
class StartActivity : FragmentActivity() {
/**
* The pager widget, which handles animation and allows swiping horizontally to access previous
* and next wizard steps.
*/
private lateinit var mPager: ViewPager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.start_activity)
val loginButton = findViewById<Button>(R.id.login_button)
loginButton.setOnClickListener {
this.didTapLoginButton()
}
}
private fun didTapLoginButton() {
val i = Intent(this, LoginActivity::class.java)
startActivity(i)
}
}
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.login_activity)
//actionbar
val actionbar = supportActionBar
//set actionbar title
actionbar!!.title = "New Activity"
//set back button
actionbar.setDisplayHomeAsUpEnabled(true)
actionbar.setDisplayHomeAsUpEnabled(true)
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
// it is important function, you need to write this function in which class/activity you want to show back arrow
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return super.onOptionsItemSelected(item)
}
}
Upvotes: 1
Reputation: 40840
In order to have a response when you hit the Home/up Button, here are a couple of options to solve this:
In the fragments that you show up the Home/UP button, override onOptionsItemSelected()
method and call the activity's onBackPressed()
for home button id
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle presses on the action bar menu items
when (item.itemId) {
android.R.id.home -> {
activity?.onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
Instead of showing the Home/Up button on the ActionBar
using below, and you've to set the boolean value for each fragment that you need to show up the home button using the method below:
private fun setupBackButton() {
if (activity is AppCompatActivity) {
(activity as AppCompatActivity?)?.supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
}
You can instead setup the ActionBar
with AppBarConfiguration
in onCreate()
method of the activity as below:
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
val host: NavHostFragment = supportFragmentManager
.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return
val navController = host.navController
appBarConfiguration = AppBarConfiguration(
setOf(R.id.second_fragment, R.id.third_fragment)) // IDs of fragments you want without the ActionBar home/up button
setupActionBarWithNavController(navController, appBarConfiguration)
}
By doing this, the up button will show up in all fragments, but R.id.second_fragment, R.id.third_fragment
and you no longer need to set the setDisplayHomeAsUpEnabled()
to each individual fragment to show up the home/up button. But still you need to override onOptionsItemSelected
as mentioned above.
Which is neater than the first option. First, you've to implement the above side node to allow the NavController
auto controls/configure the ActionBar
.
So, the past side note is a mandatory part of this option.
Then override onSupportNavigateUp()
in the activity which allows NavigationUI
to support proper ActionBar
up navigation.
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}
And then override onOptionsItemSelected()
in activity to make Have Navigation UI Handle the OptionsMenu/ActionBar item selection
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
|| super.onOptionsItemSelected(item)
}
I would say that option 2 is neater than 1, because you write all the code in one place (activity) without touching fragments, and also it automatically configure all the fragments, no need to manually setDisplayHomeAsUpEnabled()
or activity.onBackPressed()
for individual fragments that you want the Home/Up button to show up.
Upvotes: 6
Reputation: 1109
Add this in the NavigationClickListener.
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
Upvotes: 0
Reputation: 818
You need to attach a click listener to the toolbar like :
toolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
Upvotes: 1