user18145931
user18145931

Reputation:

How to change action bar navigation onClick listener from fragment

I have a toolbar in activity with a fragment container

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/tlUsersActivity"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/white"
        />

I run these lines to control the backpressed button

    setSupportActionBar(binding?.tlUsersActivity)
    if (supportActionBar != null) {
        when (intent.getStringExtra(MainActivityAdmin.FRAGMENT_TYPE)) {
            "View Users" -> {
                supportActionBar?.title = viewUsersText
}

    "Edit Users" -> {
        supportActionBar?.title = editUsersText
    }
}
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        binding?.tlUsersActivity?.setNavigationOnClickListener { onBackPressed() }

I want to change this action from inside the fragment, I want to replace it with a function that replaces fragments. I've tried this but it didn't work

    val actionBar = view?.findViewById<Toolbar>(R.id.tlUsersActivity)
    actionBar?.setNavigationOnClickListener {
        replaceFragment(FragmentEditUsers())
    }

Upvotes: 0

Views: 968

Answers (1)

Hayk Mkrtchyan
Hayk Mkrtchyan

Reputation: 3265

Directly working with Activity from the fragment is not a good practice, it will become a nest of bugs in the future)) The first option is SharedViewModel which you can share between your activity and fragment. But maybe you don't want it if you have simple functionality and you don't want to involve ViewModel here. The second option, which usually was used before Fragment Result API and SharedViewModel were callbacks. The third one which I prefer and it's way cleaner is Fragment Result API. You can find more information here - FragmentResultAPI & SharedViewModel. Using it you can communicate between activity-to-fragment, vice-versa, and fragment-to-fragment.

You need a Gradle dependency to use it:

implementation "androidx.fragment:fragment-ktx:1.4.1"

In the activity, you have to set a FragmentResultListener. It takes as a parameter the request key, lifecycle, and FragmentResultListener interface which is a SAM interface (has only 1 function). You can deep-dive here if you want.

const val REQUEST_KEY = "101"
const val BUNDLE_KEY = "B101"

// Activity code
supportFragmentManager.setFragmentResultListener(REQUEST_KEY, this) { requestKey, bundle ->
        if (requestKey == REQUEST_KEY) {
            // Here you can call the functions you desire
            Toast.makeText(this, bundle.getString(BUNDLE_KEY), Toast.LENGTH_SHORT).show()
        }
    }

Now let's have a look at the fragment side. I have one button and after clicking I trigger the result listener in the activity:

// Fragment code
val btnTriggerActivity = view.findViewById<Button>(R.id.btn_trigger_activity)
btnTriggerActivity.setOnClickListener {
    // This code will trigger the function in activity.
    // The activity will show the toast
    setFragmentResult(REQUEST_KEY, bundleOf(
        BUNDLE_KEY to "Hello from the other side :)"
    ))
}

That's it. Here's also an image from the developer's page which shows the communication of fragment-to-fragment using FragmentResultApi.

Upvotes: 1

Related Questions