【问题标题】:Issue with backstack and bottomnav in kotlinkotlin 中的 backstack 和 bottomnav 问题
【发布时间】:2022-01-13 09:16:29
【问题描述】:

您好,我在片段之间的导航方面遇到了一些问题

好的,我详细解释一下

我有一个带有 4 个片段 Home、Following、Notification 和 Profile 的底部导航,backstack 上的底部导航没有问题,但现在例如从配置文件片段我跳转到一个名为 edit_profile 的片段,它不是一部分底部导航,当按下返回时,我希望它应该返回到配置文件片段,但后台堆栈正在将我从 edit_profile 直接带到主页片段

这是link的录音

我最近将我的项目从 java 更改为 kotlin,我是 kotlin 的初学者

我真的很喜欢 Pinterest 和 Instagram 的导航

注意:- 所有这些代码都会自动更改为 kotlin(带有一些 手动完成更改),此问题也与 java 相关,而不是在迁移到 kotlin 之后,另外,如果您想要更多参考代码 请告诉我我会更新问题

代码

MainActivity.kt // 底部导航

class MainActivity : AppCompatActivity() {
    var bottomNavigationView: BottomNavigationView? = null
    var integerDeque: Deque<Int> = ArrayDeque(3)
    var flag = true

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
        setContentView(R.layout.activity_main)
        val window = this.window
        window.statusBarColor = this.resources.getColor(R.color.black)
        bottomNavigationView = findViewById(R.id.bottom_navigation_view)
        integerDeque.push(R.id.nav_home)
        loadFragments(Home_Fragment())
        bottomNavigationView!!.selectedItemId = R.id.nav_home
        bottomNavigationView!!.setOnNavigationItemSelectedListener(
            BottomNavigationView.OnNavigationItemSelectedListener { item: MenuItem ->
                val id = item.itemId
                if (integerDeque.contains(id)) {
                    if (id == R.id.nav_home) {
                        integerDeque.size
                        if (flag) {
                            integerDeque.addFirst(R.id.nav_home)
                            flag = false
                        }
                    }
                    integerDeque.remove(id)
                }
                integerDeque.push(id)
                loadFragments(getFragment(item.itemId))
                false
            }
        )
    }

    @SuppressLint("NonConstantResourceId")
    private fun getFragment(itemId: Int): Fragment {
        when (itemId) {
            R.id.nav_home -> {
                bottomNavigationView!!.menu.getItem(0).isChecked = true
                return Home_Fragment()
            }
            R.id.nav_following -> {
                bottomNavigationView!!.menu.getItem(1).isChecked = true
                return Following_Fragment()
            }
            R.id.nav_notification -> {
                bottomNavigationView!!.menu.getItem(2).isChecked = true
                return Notification_Fragment()
            }
            R.id.nav_profile -> {
                bottomNavigationView!!.menu.getItem(3).isChecked = true
                return Profile_Fragment()
            }
        }
        bottomNavigationView!!.menu.getItem(0).isChecked = true
        return Home_Fragment()
    }

    private fun loadFragments(fragment: Fragment?) {
        if (fragment != null) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.fragment_container, fragment, fragment.javaClass.simpleName)
                .commit()
        }
    }

    override fun onBackPressed() {
        integerDeque.pop()
        if (!integerDeque.isEmpty()) {
            loadFragments(getFragment(integerDeque.peek()))
        } else {
            finish()
        }
    }

Edit_Profile.kt // 从这个片段我想回到最后一个片段,它应该是配置文件片段

class Edit_Profile : Fragment() {
    private var profilePhoto: CircleImageView? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_edit_profile, container, false)
        profilePhoto = view.findViewById(R.id.circleImageView)
        initImageLoader()
        setProfileImage()
        val imageView = view.findViewById<ImageView>(R.id.backArrow)
        imageView.setOnClickListener {
            val newCase: Fragment = Profile_Fragment()
            assert(fragmentManager != null)
            val transaction = requireFragmentManager().beginTransaction()
            transaction.replace(R.id.fragment_container, newCase)
            transaction.addToBackStack(Profile_Fragment.toString())
            transaction.commit()
        }
        return view
    }

编辑

将部分交易从 Profile Fragment 添加到 Edit Profile

ProfileFragment.kt

editProfileButton!!.setOnClickListener(View.OnClickListener { v: View? ->
            val edit_profile: Fragment = Edit_Profile()
            requireActivity().getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_container, edit_profile,"TAG")
                .addToBackStack("TAG")
                .commit()
        })

【问题讨论】:

  • 我的猜测是替换可能是问题,因为这意味着清除所有片段然后添加新片段,而是尝试添加片段而不是替换。
  • 嘿,我是 kotlin 新手,你能告诉我有没有一种简单的方法来管理后台导航(我真的很喜欢 Pinterest 和 Instagram 的导航)
  • 你是如何对Edit_Profile片段进行交易的?
  • @Zain 我已在编辑部分添加代码,请查看我是如何完成交易的

标签: android kotlin android-fragments navigation fragment-backstack


【解决方案1】:

现在您正在通过integerDeque 数组管理后台堆栈。

  • 当你转到一个新的BottomNavigationView 片段时;如果它不存在,则将其 id 添加到数组中。
  • 当你弹出回栈时;顶部的片段被踢出数组。

但是由于您在 bottomNavigationView.setOnItemSelectedListener 回调中推送了所有这些 ID;那么integerDeque数组只包含BottomNavigationView片段ID。

由于Edit_Profile 片段不是BottomNavigationView 片段的一部分,因此它不会被添加/弹出队列。相反,当您尝试在显示 Edit_Profile 片段时弹出返回堆栈时;您在onBackPressed() 中管理的正常行为将继续,Profile_Fragment id 将从队列中弹出,使您返回到上述示例中的前一个片段 (Home_Fragment)。

解决这个问题的一个小办法是,当您与Edit_Profile 片段进行交易时,考虑将一个 id 添加到队列中,以便将该 id 从队列中弹出,从而返回到Profile_Fragment 片段。

您可以使用片段的 id 执行此操作,以确保它是唯一的:

editProfileButton!!.setOnClickListener(View.OnClickListener { v: View? ->
        val edit_profile: Fragment = Edit_Profile()
        requireActivity().getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.fragment_container, edit_profile,"TAG")
            .addToBackStack("TAG")
            .commit()
            
        (requireActivity() as MainActivity).integerDeque.push(id) // <<<< pushing id to the queue
        
    })

这应该可以解决您的问题。


小贴士:

  • BNV 上使用 setOnItemSelectedListener 而不是 setOnNavigationItemSelectedListener,因为后者已被弃用。
  • setOnItemSelectedListener 回调返回true 而不是false,因为这应该消耗事件并将BNV 标记为选中。
  • Edit_Profile 事务replace 中添加片段,而不是使用add 添加它,因为容器已被消耗;这样可以避免容器中的片段重叠。
  • onBackPressed();你会用bottomNavigationView.selectedItemId = integerDeque.peek()替换loadFragments(..);重用相同的片段而不是重做事务可能会更轻松。

【讨论】:

  • 谢谢 Soooooo 很多兄弟,我在过去 3 个月一直被这个问题困扰,我在 SO 上问了很多次这个问题,并且有答案但没有解决我的问题,但是这个问题line 解决了这个问题,再次感谢您
  • 你好,我正在尝试将此 kotlin 行添加到 java 中的新项目中,但不知道 java 中应该包含什么,这是 kotlin 行“bottomNavigationView!!.selectedItemId = integerDeque .peek(); "你能帮我解决这个问题吗
  • @VasantRaval HYG bottomNavigationView.setSelectedItemId(integerDeque.peek());
【解决方案2】:

通常我遵循这种模式

我在包含所有底部导航选项卡的主容器中添加 HomeF,所有底部导航选项卡将在主容器中打开,而那些不属于底部导航的片段将在主容器中打开。我通常添加(而不是替换)主容器中的所有片段并将添加到后台堆栈,这样如果用户从配置文件(home_container)转到主容器中的某个内容,而后台我们可以弹出顶部片段并且用户将看到配置文件.

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多