替换为ViewPager2

This commit is contained in:
HapeLee committed 2025-06-13 03:37:30 +08:00
1 parent 2ceee5c158
commit 8c43d4bcd1
4 files changed
+80 -97

No files matched your search

@@ -2,6 +2,7 @@
package io.legato.kazusa.ui.main.bookshelf.style1 package io.legato.kazusa.ui.main.bookshelf.style1
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@@ -9,7 +10,9 @@ import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import io.legato.kazusa.R import io.legato.kazusa.R
import io.legato.kazusa.data.appDb import io.legato.kazusa.data.appDb
import io.legato.kazusa.data.entities.Book 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 binding by viewBinding(FragmentBookshelf1Binding::bind)
private val adapter by lazy { TabFragmentPageAdapter(childFragmentManager) }
private val tabLayout: TabLayout by lazy { private val tabLayout: TabLayout by lazy {
binding.tabLayout.findViewById(R.id.tab_layout) binding.tabLayout.findViewById(R.id.tab_layout)
} }
@@ -50,6 +52,8 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
private val fragmentMap = hashMapOf<Long, BooksFragment>() private val fragmentMap = hashMapOf<Long, BooksFragment>()
override val groupId: Long get() = selectedGroup?.groupId ?: 0 override val groupId: Long get() = selectedGroup?.groupId ?: 0
private lateinit var adapter: TabFragmentPageAdapter
override val books: List<Book> override val books: List<Book>
get() { get() {
val fragment = fragmentMap[groupId] val fragment = fragmentMap[groupId]
@@ -63,16 +67,16 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
} }
private val selectedGroup: BookGroup? private val selectedGroup: BookGroup?
get() = bookGroups.getOrNull(tabLayout.selectedTabPosition) get() = bookGroups.getOrNull(binding.viewPagerBookshelf.currentItem)
private fun initView() { private fun initView() {
//binding.viewPagerBookshelf.setEdgeEffectColor(primaryColor) adapter = TabFragmentPageAdapter(this)
//tabLayout.isTabIndicatorFullWidth = false
//tabLayout.tabMode = TabLayout.MODE_SCROLLABLE
// tabLayout.setSelectedTabIndicatorColor(requireContext().accentColor)
tabLayout.setupWithViewPager(binding.viewPagerBookshelf)
binding.viewPagerBookshelf.offscreenPageLimit = 1
binding.viewPagerBookshelf.adapter = adapter 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 { override fun onQueryTextSubmit(query: String?): Boolean {
@@ -84,6 +88,7 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
return false return false
} }
@SuppressLint("NotifyDataSetChanged")
@Synchronized @Synchronized
override fun upGroup(data: List<BookGroup>) { override fun upGroup(data: List<BookGroup>) {
if (data.isEmpty()) { if (data.isEmpty()) {
@@ -93,11 +98,21 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
bookGroups.clear() bookGroups.clear()
bookGroups.addAll(data) bookGroups.addAll(data)
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
adapter = TabFragmentPageAdapter(this)
binding.viewPagerBookshelf.adapter = adapter
TabLayoutMediator(binding.tabLayout, binding.viewPagerBookshelf) { tab, position ->
tab.text = bookGroups[position].groupName
}.attach()
selectLastTab() selectLastTab()
for (i in 0 until adapter.count) {
tabLayout.getTabAt(i)?.view?.setOnLongClickListener { binding.tabLayout.post {
showDialogFragment(GroupEditDialog(bookGroups[i])) for (i in 0 until bookGroups.size) {
true 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() { 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() { private fun selectLastTab() {
tabLayout.post { binding.tabLayout.post {
tabLayout.removeOnTabSelectedListener(this) binding.tabLayout.removeOnTabSelectedListener(this)
tabLayout.getTabAt(AppConfig.saveTabPosition)?.select() binding.tabLayout.getTabAt(AppConfig.saveTabPosition)?.select()
tabLayout.addOnTabSelectedListener(this) binding.tabLayout.addOnTabSelectedListener(this)
} }
} }
@@ -134,54 +159,14 @@ class BookshelfFragment1() : BaseBookshelfFragment(R.layout.fragment_bookshelf1)
fragmentMap[groupId]?.gotoTop() fragmentMap[groupId]?.gotoTop()
} }
private inner class TabFragmentPageAdapter(fm: FragmentManager) : private inner class TabFragmentPageAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { override fun getItemCount(): Int = bookGroups.size
override fun getPageTitle(position: Int): CharSequence { override fun createFragment(position: Int): Fragment {
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 {
val group = bookGroups[position] val group = bookGroups[position]
return BooksFragment(position, group) val fragment = 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
}
fragmentMap[group.groupId] = fragment fragmentMap[group.groupId] = fragment
return fragment return fragment
} }
} }
} }
@@ -8,8 +8,11 @@ import android.view.MenuItem
import android.view.ViewGroup import android.view.ViewGroup
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentStatePagerAdapter import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.lifecycle.lifecycleScope 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.R
import io.legato.kazusa.base.VMBaseActivity import io.legato.kazusa.base.VMBaseActivity
import io.legato.kazusa.databinding.ActivityRssArtivlesBinding import io.legato.kazusa.databinding.ActivityRssArtivlesBinding
@@ -29,9 +32,9 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
override val binding by viewBinding(ActivityRssArtivlesBinding::inflate) override val binding by viewBinding(ActivityRssArtivlesBinding::inflate)
override val viewModel by viewModels<RssSortViewModel>() 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 sortList = mutableListOf<Pair<String, String>>()
private val fragmentMap = hashMapOf<String, Fragment>()
private val editSourceResult = registerForActivityResult( private val editSourceResult = registerForActivityResult(
StartActivityContract(RssSourceEditActivity::class.java) StartActivityContract(RssSourceEditActivity::class.java)
) { ) {
@@ -44,11 +47,11 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
setSupportActionBar(binding.topBar) setSupportActionBar(binding.topBar)
binding.viewPager.adapter = adapter
binding.tabLayout.setupWithViewPager(binding.viewPager)
viewModel.titleLiveData.observe(this) { viewModel.titleLiveData.observe(this) {
binding.topBar.setTitle(it) binding.topBar.title = it
} }
viewModel.initData(intent) { viewModel.initData(intent) {
upFragments() upFragments()
} }
@@ -73,7 +76,9 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
} }
R.id.menu_refresh_sort -> viewModel.clearSortCache { upFragments() } R.id.menu_refresh_sort -> viewModel.clearSortCache { upFragments() }
R.id.menu_set_source_variable -> setSourceVariable() R.id.menu_set_source_variable -> setSourceVariable()
R.id.menu_edit_source -> viewModel.rssSource?.sourceUrl?.let { R.id.menu_edit_source -> viewModel.rssSource?.sourceUrl?.let {
editSourceResult.launch { editSourceResult.launch {
putExtra("sourceUrl", it) putExtra("sourceUrl", it)
@@ -100,16 +105,24 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
private fun upFragments() { private fun upFragments() {
lifecycleScope.launch { lifecycleScope.launch {
viewModel.rssSource?.sortUrls()?.let { val sorts = viewModel.rssSource?.sortUrls().orEmpty()
sortList.clear()
sortList.addAll(it) sortList.clear()
} sortList.addAll(sorts)
if (sortList.size == 1) {
if (sortList.size <= 1) {
binding.tabLayout.gone() binding.tabLayout.gone()
} else { } else {
binding.tabLayout.visible() 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) viewModel.rssSource?.setVariable(variable)
} }
private inner class TabFragmentPageAdapter : private class TabFragmentPageAdapter(
FragmentStatePagerAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { activity: FragmentActivity,
private val items: List<Pair<String, String>>
) : FragmentStateAdapter(activity) {
override fun getItemPosition(`object`: Any): Int { override fun getItemCount(): Int = items.size
return POSITION_NONE
}
override fun getPageTitle(position: Int): CharSequence { override fun createFragment(position: Int): Fragment {
return sortList[position].first val sort = items[position]
}
override fun getItem(position: Int): Fragment {
val sort = sortList[position]
return RssArticlesFragment(sort.first, sort.second) 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
}
} }
}
}
@@ -43,7 +43,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager <androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager" android:id="@+id/view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -43,7 +43,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<!-- ViewPager --> <!-- ViewPager -->
<androidx.viewpager.widget.ViewPager <androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager_bookshelf" android:id="@+id/view_pager_bookshelf"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"