替换为ViewPager2

This commit is contained in:
HapeLee
2025-06-13 03:37:30 +08:00
parent 2ceee5c158
commit 8c43d4bcd1
4 changed files with 80 additions and 97 deletions
@@ -2,6 +2,7 @@
package io.legato.kazusa.ui.main.bookshelf.style1
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
@@ -9,7 +10,9 @@ import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import io.legato.kazusa.R
import io.legato.kazusa.data.appDb
import io.legato.kazusa.data.entities.Book
@@ -42,7 +45,6 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
}
private val binding by viewBinding(FragmentBookshelf1Binding::bind)
private val adapter by lazy { TabFragmentPageAdapter(childFragmentManager) }
private val tabLayout: TabLayout by lazy {
binding.tabLayout.findViewById(R.id.tab_layout)
}
@@ -50,6 +52,8 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
private val fragmentMap = hashMapOf<Long, BooksFragment>()
override val groupId: Long get() = selectedGroup?.groupId ?: 0
private lateinit var adapter: TabFragmentPageAdapter
override val books: List<Book>
get() {
val fragment = fragmentMap[groupId]
@@ -63,16 +67,16 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
}
private val selectedGroup: BookGroup?
get() = bookGroups.getOrNull(tabLayout.selectedTabPosition)
get() = bookGroups.getOrNull(binding.viewPagerBookshelf.currentItem)
private fun initView() {
//binding.viewPagerBookshelf.setEdgeEffectColor(primaryColor)
//tabLayout.isTabIndicatorFullWidth = false
//tabLayout.tabMode = TabLayout.MODE_SCROLLABLE
// tabLayout.setSelectedTabIndicatorColor(requireContext().accentColor)
tabLayout.setupWithViewPager(binding.viewPagerBookshelf)
binding.viewPagerBookshelf.offscreenPageLimit = 1
adapter = TabFragmentPageAdapter(this)
binding.viewPagerBookshelf.adapter = adapter
binding.viewPagerBookshelf.offscreenPageLimit = 1
TabLayoutMediator(binding.tabLayout, binding.viewPagerBookshelf) { tab, position ->
tab.text = bookGroups[position].groupName
}.attach()
}
override fun onQueryTextSubmit(query: String?): Boolean {
@@ -84,6 +88,7 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
return false
}
@SuppressLint("NotifyDataSetChanged")
@Synchronized
override fun upGroup(data: List<BookGroup>) {
if (data.isEmpty()) {
@@ -93,11 +98,21 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
bookGroups.clear()
bookGroups.addAll(data)
adapter.notifyDataSetChanged()
adapter = TabFragmentPageAdapter(this)
binding.viewPagerBookshelf.adapter = adapter
TabLayoutMediator(binding.tabLayout, binding.viewPagerBookshelf) { tab, position ->
tab.text = bookGroups[position].groupName
}.attach()
selectLastTab()
for (i in 0 until adapter.count) {
tabLayout.getTabAt(i)?.view?.setOnLongClickListener {
showDialogFragment(GroupEditDialog(bookGroups[i]))
true
binding.tabLayout.post {
for (i in 0 until bookGroups.size) {
binding.tabLayout.getTabAt(i)?.view?.setOnLongClickListener {
showDialogFragment(GroupEditDialog(bookGroups[i]))
true
}
}
}
}
@@ -105,14 +120,24 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
}
override fun upSort() {
adapter.notifyDataSetChanged()
childFragmentManager.fragments.forEach {
if (it is BooksFragment) {
val position = it.position
val group = bookGroups.getOrNull(position) ?: return@forEach
val newSort = group.getRealBookSort()
it.setEnableRefresh(group.enableRefresh)
if (it.bookSort != newSort) {
it.upBookSort(newSort)
}
}
}
}
private fun selectLastTab() {
tabLayout.post {
tabLayout.removeOnTabSelectedListener(this)
tabLayout.getTabAt(AppConfig.saveTabPosition)?.select()
tabLayout.addOnTabSelectedListener(this)
binding.tabLayout.post {
binding.tabLayout.removeOnTabSelectedListener(this)
binding.tabLayout.getTabAt(AppConfig.saveTabPosition)?.select()
binding.tabLayout.addOnTabSelectedListener(this)
}
}
@@ -134,54 +159,14 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
fragmentMap[groupId]?.gotoTop()
}
private inner class TabFragmentPageAdapter(fm: FragmentManager) :
FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private inner class TabFragmentPageAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = bookGroups.size
override fun getPageTitle(position: Int): CharSequence {
return bookGroups[position].groupName
}
/**
* 确定视图位置是否更改时调用
* @return POSITION_NONE 已更改,刷新视图. POSITION_UNCHANGED 未更改,不刷新视图
*/
override fun getItemPosition(any: Any): Int {
val fragment = any as BooksFragment
val position = fragment.position
val group = bookGroups.getOrNull(position)
if (fragment.groupId != group?.groupId) {
return POSITION_NONE
}
val bookSort = group.getRealBookSort()
fragment.setEnableRefresh(group.enableRefresh)
if (fragment.bookSort != bookSort) {
fragment.upBookSort(bookSort)
}
return POSITION_UNCHANGED
}
override fun getItem(position: Int): Fragment {
override fun createFragment(position: Int): Fragment {
val group = bookGroups[position]
return BooksFragment(position, group)
}
override fun getCount(): Int {
return bookGroups.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
var fragment = super.instantiateItem(container, position) as BooksFragment
val group = bookGroups[position]
/**
* Activity recreate 会复用之前的 Fragment,不正确的需要重新创建
*/
if (fragment.isCreated && getItemPosition(fragment) == POSITION_NONE) {
destroyItem(container, position, fragment)
fragment = super.instantiateItem(container, position) as BooksFragment
}
val fragment = BooksFragment(position, group)
fragmentMap[group.groupId] = fragment
return fragment
}
}
}
@@ -8,8 +8,11 @@ import android.view.MenuItem
import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayoutMediator
import io.legato.kazusa.R
import io.legato.kazusa.base.VMBaseActivity
import io.legato.kazusa.databinding.ActivityRssArtivlesBinding
@@ -29,9 +32,9 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
override val binding by viewBinding(ActivityRssArtivlesBinding::inflate)
override val viewModel by viewModels<RssSortViewModel>()
private val adapter by lazy { TabFragmentPageAdapter() }
private var adapter: TabFragmentPageAdapter? = null
private val sortList = mutableListOf<Pair<String, String>>()
private val fragmentMap = hashMapOf<String, Fragment>()
private val editSourceResult = registerForActivityResult(
StartActivityContract(RssSourceEditActivity::class.java)
) {
@@ -44,11 +47,11 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
override fun onActivityCreated(savedInstanceState: Bundle?) {
setSupportActionBar(binding.topBar)
binding.viewPager.adapter = adapter
binding.tabLayout.setupWithViewPager(binding.viewPager)
viewModel.titleLiveData.observe(this) {
binding.topBar.setTitle(it)
binding.topBar.title = it
}
viewModel.initData(intent) {
upFragments()
}
@@ -73,7 +76,9 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
}
R.id.menu_refresh_sort -> viewModel.clearSortCache { upFragments() }
R.id.menu_set_source_variable -> setSourceVariable()
R.id.menu_edit_source -> viewModel.rssSource?.sourceUrl?.let {
editSourceResult.launch {
putExtra("sourceUrl", it)
@@ -100,16 +105,24 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
private fun upFragments() {
lifecycleScope.launch {
viewModel.rssSource?.sortUrls()?.let {
sortList.clear()
sortList.addAll(it)
}
if (sortList.size == 1) {
val sorts = viewModel.rssSource?.sortUrls().orEmpty()
sortList.clear()
sortList.addAll(sorts)
if (sortList.size <= 1) {
binding.tabLayout.gone()
} else {
binding.tabLayout.visible()
}
adapter.notifyDataSetChanged()
adapter = TabFragmentPageAdapter(this@RssSortActivity, sortList)
binding.viewPager.adapter = adapter
// 重新绑定 TabLayout
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = sortList[position].first
}.attach()
}
}
@@ -138,31 +151,16 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
viewModel.rssSource?.setVariable(variable)
}
private inner class TabFragmentPageAdapter :
FragmentStatePagerAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private class TabFragmentPageAdapter(
activity: FragmentActivity,
private val items: List<Pair<String, String>>
) : FragmentStateAdapter(activity) {
override fun getItemPosition(`object`: Any): Int {
return POSITION_NONE
}
override fun getItemCount(): Int = items.size
override fun getPageTitle(position: Int): CharSequence {
return sortList[position].first
}
override fun getItem(position: Int): Fragment {
val sort = sortList[position]
override fun createFragment(position: Int): Fragment {
val sort = items[position]
return RssArticlesFragment(sort.first, sort.second)
}
override fun getCount(): Int {
return sortList.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val fragment = super.instantiateItem(container, position) as Fragment
fragmentMap[sortList[position].first] = fragment
return fragment
}
}
}
}