Skip to content

Instantly share code, notes, and snippets.

@LukeNeedham
Last active November 24, 2020 21:45
Show Gist options
  • Save LukeNeedham/83f0bdaa8d56d03d11f727967eb327f2 to your computer and use it in GitHub Desktop.
Save LukeNeedham/83f0bdaa8d56d03d11f727967eb327f2 to your computer and use it in GitHub Desktop.
A solution to allow use of `targetFragment` in conjunction with the Android Jetpack Navigation Component
import android.util.Log
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import androidx.fragment.app.FragmentManager
/** Performs [work] on the [Fragment.getTargetFragment] of type [TargetFragmentType] */
inline fun <reified TargetFragmentType> Fragment.withCallback(work: TargetFragmentType.() -> Unit) {
val typedTarget = targetFragment as? TargetFragmentType
if (typedTarget == null) {
Log.e(
"AutoTargetFragment",
"Target Fragment is not of expected type ${TargetFragmentType::class.qualifiedName}"
)
return
}
typedTarget.work()
}
/**
* Automatically sets the target fragment of newly created fragments to the previous fragment.
* This therefore allows you to use 'targetFragment' in conjunction with the
* Jetpack Navigation Component, for example.
*
* You usually want to call this function on your Activity top-level FragmentManager.
*/
fun FragmentManager.autoTarget() {
fragmentFactory = ChildManagerFragmentFactory(this)
}
/** An [AutoTargetFragmentFactory] which determines current fragment via the child [FragmentManager] of [fragmentManager] */
class ChildManagerFragmentFactory(
private val fragmentManager: FragmentManager
) : AutoTargetFragmentFactory() {
override fun getCurrentFragment() =
fragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.firstOrNull()
}
abstract class AutoTargetFragmentFactory : FragmentFactory() {
abstract fun getCurrentFragment(): Fragment?
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
val fragment = super.instantiate(classLoader, className)
val currentFragment = getCurrentFragment()
fragment.setTargetFragment(currentFragment, REQUEST_CODE)
return fragment
}
companion object {
const val REQUEST_CODE = 0
}
}
@LukeNeedham
Copy link
Author

Simply setup like so:

class MainActivity : AppCompatActivity(R.layout.activity_main) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportFragmentManager.autoTarget()
    }
}

And then to use a callback, use:

withCallback<MyCallbackType> { myCallback() }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment