例如,我有一个活动和三个片段(1、2、3)。
我显示第一个片段,然后是第二个片段(将其添加到后台堆栈)和第三个片段(不将其添加到后台堆栈,因为按下后退按钮时我想从当前的第三个片段转到第一个片段而不是继续到第二个片段)
这个逻辑有效,但是当它回到第一个片段时,第三个片段仍然可见(同时显示两个片段)
这是同时显示Fragment 1和Fragment 3时的完整流程示例和完整代码
活动:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showFragment(
addToBackStack = false,
backStackName = null,
fragmentNumber = 1,
tag = "FRAGMENT_FIRST"
)
// simulate going to other fragments sequentially
val mainHandler = Handler(Looper.getMainLooper())
mainHandler.postDelayed(
{
showFragment(
addToBackStack = true,
backStackName = null,
fragmentNumber = 2,
tag = "FRAGMENT_SECOND"
)
},
1000L
)
mainHandler.postDelayed(
{
showFragment(
addToBackStack = false, // when back pressing from third fragment I want it to get back to first fragment, not second
backStackName = null,
fragmentNumber = 3,
tag = "FRAGMENT_THIRD"
)
},
2000L
)
}
private fun showFragment(
addToBackStack: Boolean,
backStackName: String?,
fragmentNumber: Int,
tag: String
) {
val transaction = supportFragmentManager.beginTransaction()
var fragment =
supportFragmentManager.findFragmentByTag(tag) as FragmentGeneral?
if (fragment == null) {
fragment = FragmentGeneral.newInstance(number = fragmentNumber)
transaction.replace(R.id.fragment_container, fragment, tag)
if (addToBackStack) {
transaction.addToBackStack(backStackName)
}
} else {
transaction.show(fragment)
}
transaction.commit()
}
}
class FragmentGeneral : Fragment() {
private lateinit var binding: FragmentGeneralBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
) = FragmentGeneralBinding.inflate(layoutInflater, container, false).apply {
binding = this
}.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
arguments?.getInt(ARG_FRAGMENT_NUMBER)?.let { number ->
binding.fragmentNumber = number
// set different position of the text so we could clearly see overlapping of two fragments
binding.textView.gravity = when (number) {
1 -> Gravity.TOP
2 -> Gravity.CENTER_VERTICAL
3 -> Gravity.BOTTOM
else -> return
}
// simulate pressing back button pressing
if (number == 3) {
// should go to first fragment because it wasn't added to backstack
Handler(Looper.getMainLooper()).postDelayed(
{ activity?.onBackPressed() },
1000L
)
}
}
}
companion object {
private const val ARG_FRAGMENT_NUMBER = "ARG_FRAGMENT_NUMBER"
fun newInstance(number: Int) =
FragmentGeneral().apply {
arguments = bundleOf(ARG_FRAGMENT_NUMBER to number)
}
}
}
activity_main.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</layout>
fragment_general.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".FragmentGeneral">
<data>
<variable
name="fragmentNumber"
type="int" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:text='@{"Fragment #" + fragmentNumber}'
android:textColor="@android:color/black"
android:textSize="64sp"
tools:text="Fragment #?" />
</FrameLayout>
</layout>
那么为什么第三个片段仍然可见?如何解决此问题以及处理此类交易的正确方法是什么?
如果他们的片段不透明,开发人员通常不会注意到这些问题,但在我的例子中它是透明的,所以白色背景 - 它是活动背景