Реализация нижней навигации с помощью ViewPager - PullRequest
0 голосов
/ 21 апреля 2020

Я пытаюсь реализовать BottomNavigation с ViewPager, чтобы он сохранял состояние нижних фрагментов навигации и стек стека, когда пользователь переключается между ними, и я пришел к следующему решению:

class MainActivity : AppCompatActivity() {

    private val autoFragment: RootFragment = RootFragment.newInstance(AutoFragment())
    private val ordersFragment: RootFragment = RootFragment.newInstance(OrdersContainerFragment())
    private val driversFragment: RootFragment = RootFragment.newInstance(DriversFragment())
    private val infoFragment: RootFragment = RootFragment.newInstance(InfoContainerFragment())
    private var selectedFragment: RootFragment = autoFragment

    private var prevMenuItem: MenuItem? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)
        setupBottomNav()
        setupViewPager()
    }

    private fun setupViewPager() {
        nonSwipeableViewPager.adapter = FragmentAdapter(
            supportFragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
        )
            .apply {
                add(autoFragment, getString(R.string.title_auto))
                add(ordersFragment, getString(R.string.title_orders))
                add(driversFragment, getString(R.string.title_drivers))
                add(infoFragment, getString(R.string.title_info))
            }

        nonSwipeableViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(state: Int) {}

            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

            override fun onPageSelected(position: Int) {
                if (prevMenuItem != null) {
                    prevMenuItem!!.isChecked = false
                } else {
                    bottomNav.menu.getItem(0).isChecked = false
                }
                bottomNav.menu.getItem(position).isChecked = true
                prevMenuItem = bottomNav.menu.getItem(position)
            }
        })

        nonSwipeableViewPager.offscreenPageLimit = 4
    }

    private fun setupBottomNav() {
        bottomNav.setOnNavigationItemSelectedListener {
            when (it.itemId) {
                R.id.navigation_auto -> selectFragment(autoFragment, 0)
                R.id.navigation_orders -> selectFragment(ordersFragment, 1)
                R.id.navigation_drivers -> selectFragment(driversFragment, 2)
                R.id.navigation_info -> selectFragment(infoFragment, 3)
                else -> false
            }
        }
    }

    private fun selectFragment(fragment: RootFragment, fragmentIndex: Int): Boolean {
        nonSwipeableViewPager.setCurrentItem(fragmentIndex, false)
        if (selectedFragment == fragment) fragment.popToRoot()
        selectedFragment = fragment
        return true
    }
}


class RootFragment : Fragment() {

    private lateinit var fragment: Fragment
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        childFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit()

        return inflater.inflate(R.layout.fragment_root, container, false)
    }

    fun popToRoot() {
        for (i in 0 until childFragmentManager.backStackEntryCount) {
            childFragmentManager.popBackStack()
        }
    }

    companion object {
        fun newInstance(fragment: Fragment) = RootFragment().apply {
            this.fragment = fragment
        }
    }
}

Но иногда, когда я покидаю приложение и затем пытаюсь открыть его снова, появляется эта ошибка:

java.lang.RuntimeException: Unable to start activity ComponentInfo{kg.umarcargo.owner/kg.umarcargo.owner.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property fragment has not been initialized
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2895)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1616)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:6651)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)
 Caused by: kotlin.UninitializedPropertyAccessException: lateinit property fragment has not been initialized
    at kg.umarcargo.owner.RootFragment.onCreateView(RootFragment.kt:20)
    at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
    at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
    at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
    at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625)
    at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
    at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
    at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
    at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1335)
    at android.app.Activity.performStart(Activity.java:7108)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2895) 
    at android.app.ActivityThread.-wrap11(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1616) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:176) 
    at android.app.ActivityThread.main(ActivityThread.java:6651) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824) 

Возможно, что-то не так с моей реализацией. Надеюсь получить ответ на мою проблему и вероятное решение. Кроме того, одним из побочных эффектов является то, что по какой-то причине приложение не закрывается, когда я нажимаю кнопку «Назад». Если вы знаете ответ, пожалуйста, поделитесь со мной!

...