I have an activity composed of a button and a ViewGroup, in which I want to stack fragments. Fragments will just show a number 1, 2, 3 ... and, I want the visual behavior of a new fragment "sliding or fading in" while covering the lower-numbered fragment below, which should "stay in place".
When popping fragments from the stack using the back button, the higher number fragment should "slide or fade out" while revealing the lower-numbered fragment, as if it was below all along.
I want to use the Transition APIs (android.transition.*) along with the fragments setEnterTransition / setExitTransition methods, so that I can later on, add shared element transitions.
In the video, I'm forcing the "exit" transition to actually move (slide up) to it's easy to see that for some reason, it renders on top of my the new fragment animating in.
This is my main issue & question: how can I make the fragment being covered render below my new fragment that's animating in?
Also by the way, the only way I found to have the lower-numbered fragment "stay put" while it gets covered, is by hacking a Fade transition to actually return an Animator that basically does "nothing" to the view.
I spent several hours on this and I'm starting to think that I might have something conceptually wrong, since my requirements seem to me the most "natural" thing to expect when "stacking" fragments, but at the same time have been pretty impossible to achieve.
The relevant pieces of my code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.button).apply {
setOnClickListener {
stackMagicFragment()
}
}
supportFragmentManager.beginTransaction()
.replace(R.id.injectionPoint, ColorFragment())
.commit()
}
private fun stackMagicFragment() {
supportFragmentManager.beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.injectionPoint, ColorFragment().apply { character = 'a' + supportFragmentManager.backStackEntryCount + 1 })
.addToBackStack(null)
.commit()
}
}
class ColorFragment : Fragment() {
companion object {
private val rnd = Random()
}
var character: Char = 'a'
private val ourColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = Slide(Gravity.END).apply { duration = 1000 }
exitTransition = Slide(Gravity.TOP).apply { duration = 1000 }
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return FrameLayout(requireContext()).apply {
setBackgroundColor(ourColor)
addView(TextView(requireContext()).apply {
text = getOurText()
textSize = 200.toFloat()
gravity = Gravity.CENTER
})
}
}
private fun getOurText(): String {
return "" + character
}
}