navigation+viewpager2简单使用

2022-11-12  本文已影响0人  梧叶已秋声

最后效果图如下:


image.png

添加gradle。

    // viewpager2
    implementation 'androidx.viewpager2:viewpager2:1.0.0'

    // navigation
    implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
    implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'

新增navigation.xml。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation.xml"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.viewpager2.fragment.home.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" />
    <fragment
        android:id="@+id/userFragment"
        android:name="com.example.viewpager2.fragment.user.UserFragment"
        android:label="UserFragment" />

</navigation>

新增bottom_nav.xml。

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/homeFragment"
        android:icon="@drawable/nav_home"
        android:title="@string/tab_home" />

    <item
        android:id="@+id/userFragment"
        android:icon="@drawable/nav_user"
        android:title="@string/tab_user" />

</menu>

MainActivity 中初始化navigation。

class MainActivity : AppCompatActivity() {
    private val binding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        initNavigation()
    }

    private fun initNavigation() {
        val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = host.navController

        // 移除 长按 toast
        binding.navigationView.menu.forEach {
            val menuItemView = findViewById<BottomNavigationItemView>(it.itemId)
            menuItemView.setOnLongClickListener(View.OnLongClickListener {
                return@OnLongClickListener true
            })
        }
        // BottomNavigationView 设置 navController
        binding.navigationView.setupWithNavController(navController)

    }
}

新建ViewPagerAdapter。

class ViewPagerAdapter(
    private val fragmentStringList: MutableList<String>,
    fm: FragmentManager,
    lifecycle: Lifecycle
) : FragmentStateAdapter(fm, lifecycle) {

    override fun getItemCount(): Int {
        return fragmentStringList.size
    }

    override fun createFragment(position: Int): Fragment {
        return when (fragmentStringList[position]) {
            "FirstFragment" -> FirstFragment.newInstance("","")
            "SecondFragment" -> SecondFragment.newInstance("","")
            else -> ThirdFragment.newInstance("","")
        }
    }
}

使用adapter

class HomeFragment : Fragment() {
    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    private var mLayoutMediator: TabLayoutMediator? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG,"inner onCreate")

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
       // return inflater.inflate(R.layout.fragment_home, container, false)
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        Log.d(TAG,"inner onCreateView")

        val fragmentStringList = arrayListOf<String>(
            "FirstFragment",
            "SecondFragment",
            "ThirdFragment"
        )

// https://issuetracker.google.com/issues/154751401
// 解决 使用 navigation + viewPager2 + recyclerview 界面切换时内存泄漏问题 注意点:
// 1.使用viewLifecycleOwner.lifecycle 而不是 lifecycle
// 2. recyclerview的adapter 在onDestroyView 中置 null
        val adapter = ViewPagerAdapter(
            fragmentStringList,
            /*requireActivity().supportFragmentManager*/
            childFragmentManager,
            //lifecycle
            viewLifecycleOwner.lifecycle
        )

        binding.viewPager2.adapter = adapter
        // 设置 offscreenPageLimit
        binding.viewPager2.offscreenPageLimit = fragmentStringList.size -1
        //绑定 tabLayout 和viewPager
        mLayoutMediator =  TabLayoutMediator(
            binding.tabLayout,
            binding.viewPager2
        ) { tab, position ->
            when (position) {
                0 -> tab.text = "First"
                1 -> tab.text = "Second"
                else -> tab.text = "Third"
            }
        }
        mLayoutMediator?.attach()

        return binding.root
    }

    override fun onDestroyView() {
        Log.d(TAG,"inner onDestroyView")
        super.onDestroyView()
        // https://stackoverflow.com/questions/61779776/leak-canary-detects-memory-leaks-for-tablayout-with-viewpager2
        // TabLayout 解绑
        mLayoutMediator?.detach()
        mLayoutMediator = null
        binding.viewPager2.adapter = null
        _binding = null
    }

}

本文代码地址:
https://github.com/VIVILL/SimpleDemo/tree/main/ViewPager2

参考链接:
关于ViewPager2内存泄露问题
FragmentStatePagerAdapter使用不当引起的内存泄漏问题

上一篇下一篇

猜你喜欢

热点阅读