diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 55a1498f4..ee817d9e1 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -3,12 +3,10 @@ package io.legado.app.ui.main import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.activity.viewModels import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter -import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.bottomnavigation.BottomNavigationView import io.legado.app.BuildConfig import io.legado.app.R @@ -36,14 +34,15 @@ import io.legado.app.utils.toastOnUi class MainActivity : VMBaseActivity(), BottomNavigationView.OnNavigationItemSelectedListener, - BottomNavigationView.OnNavigationItemReselectedListener, - ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() { + BottomNavigationView.OnNavigationItemReselectedListener { override val viewModel: MainViewModel by viewModels() private var exitTime: Long = 0 private var bookshelfReselected: Long = 0 private var exploreReselected: Long = 0 private var pagePosition = 0 - private val fragmentMap = hashMapOf() + private val fragmentMap = hashMapOf() + + val viewPager get() = binding.viewPagerMain override fun getViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) @@ -53,8 +52,21 @@ class MainActivity : VMBaseActivity(), ATH.applyEdgeEffectColor(viewPagerMain) ATH.applyBottomNavigationColor(bottomNavigationView) viewPagerMain.offscreenPageLimit = 3 - viewPagerMain.adapter = TabFragmentPageAdapter(supportFragmentManager) - viewPagerMain.addOnPageChangeListener(this@MainActivity) + viewPagerMain.adapter = TabFragmentPageAdapter() + viewPagerMain.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + viewPagerMain.isUserInputEnabled = (viewPagerMain.currentItem != 0) + pagePosition = position + when (position) { + 0, 1, 3 -> bottomNavigationView.menu.getItem(position).isChecked = true + 2 -> if (AppConfig.isShowRSS) { + bottomNavigationView.menu.getItem(position).isChecked = true + } else { + bottomNavigationView.menu.getItem(3).isChecked = true + } + } + } + }) bottomNavigationView.elevation = if (AppConfig.elevation < 0) elevation else AppConfig.elevation.toFloat() bottomNavigationView.setOnNavigationItemSelectedListener(this@MainActivity) @@ -92,14 +104,14 @@ class MainActivity : VMBaseActivity(), if (System.currentTimeMillis() - bookshelfReselected > 300) { bookshelfReselected = System.currentTimeMillis() } else { - (fragmentMap[0] as? BookshelfFragment)?.gotoTop() + (fragmentMap[0L] as? BookshelfFragment)?.gotoTop() } } R.id.menu_explore -> { if (System.currentTimeMillis() - exploreReselected > 300) { exploreReselected = System.currentTimeMillis() } else { - (fragmentMap[1] as? ExploreFragment)?.compressExplore() + (fragmentMap[1L] as? ExploreFragment)?.compressExplore() } } } @@ -120,18 +132,6 @@ class MainActivity : VMBaseActivity(), } } - override fun onPageSelected(position: Int) = with(binding) { - pagePosition = position - when (position) { - 0, 1, 3 -> bottomNavigationView.menu.getItem(position).isChecked = true - 2 -> if (AppConfig.isShowRSS) { - bottomNavigationView.menu.getItem(position).isChecked = true - } else { - bottomNavigationView.menu.getItem(3).isChecked = true - } - } - } - override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { event?.let { when (keyCode) { @@ -186,36 +186,29 @@ class MainActivity : VMBaseActivity(), } } - private inner class TabFragmentPageAdapter(fm: FragmentManager) : - FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + private inner class TabFragmentPageAdapter : + FragmentStateAdapter(this) { - private fun getId(position: Int): Int { + override fun getItemId(position: Int): Long { return when (position) { 2 -> if (AppConfig.isShowRSS) 2 else 3 - else -> position + else -> position.toLong() } } - override fun getItemPosition(`object`: Any): Int { - return POSITION_NONE + override fun getItemCount(): Int { + return if (AppConfig.isShowRSS) 4 else 3 } - override fun getItem(position: Int): Fragment { - return when (getId(position)) { - 0 -> BookshelfFragment() - 1 -> ExploreFragment() - 2 -> RssFragment() + override fun createFragment(position: Int): Fragment { + val id = getItemId(position) + val fragment = when (id) { + 0L -> BookshelfFragment() + 1L -> ExploreFragment() + 2L -> RssFragment() else -> MyFragment() } - } - - override fun getCount(): Int { - return if (AppConfig.isShowRSS) 4 else 3 - } - - override fun instantiateItem(container: ViewGroup, position: Int): Any { - val fragment = super.instantiateItem(container, position) as Fragment - fragmentMap[getId(position)] = fragment + fragmentMap[id] = fragment return fragment } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 4ff1e9b50..626f227ed 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -7,11 +7,13 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View -import android.view.ViewGroup import androidx.appcompat.widget.SearchView import androidx.fragment.app.* import androidx.lifecycle.LiveData +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.constant.AppConst @@ -31,6 +33,7 @@ import io.legado.app.ui.book.local.ImportBookActivity import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.filepicker.FilePicker import io.legado.app.ui.filepicker.FilePickerDialog +import io.legado.app.ui.main.MainActivity import io.legado.app.ui.main.MainViewModel import io.legado.app.ui.main.bookshelf.books.BooksFragment import io.legado.app.utils.* @@ -48,12 +51,18 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private val binding by viewBinding(FragmentBookshelfBinding::bind) override val viewModel: BookshelfViewModel by viewModels() private val activityViewModel: MainViewModel by activityViewModels() - private lateinit var adapter: FragmentStatePagerAdapter private lateinit var tabLayout: TabLayout private var bookGroupLiveData: LiveData>? = null private val bookGroups = mutableListOf() private val fragmentMap = hashMapOf() + private var currentPosition = 0 //当前滑动位置 + private var oldPosition = 0 //上一个滑动位置 + private var currentState = 0 //记录当前手指按下状态 + private var scrolledPixList = mutableListOf() //记录手指滑动时的像素坐标记录 + + private val mainActivity get() = activity as MainActivity + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { tabLayout = binding.titleBar.findViewById(R.id.tab_layout) setSupportToolbar(binding.titleBar.toolbar) @@ -101,15 +110,64 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private val selectedGroup: BookGroup get() = bookGroups[tabLayout.selectedTabPosition] - private fun initView() { - ATH.applyEdgeEffectColor(binding.viewPagerBookshelf) + private fun initView() = with(binding) { + ATH.applyEdgeEffectColor(viewPagerBookshelf) tabLayout.isTabIndicatorFullWidth = false tabLayout.tabMode = TabLayout.MODE_SCROLLABLE tabLayout.setSelectedTabIndicatorColor(requireContext().accentColor) - tabLayout.setupWithViewPager(binding.viewPagerBookshelf) - binding.viewPagerBookshelf.offscreenPageLimit = 1 - adapter = TabFragmentPageAdapter(childFragmentManager) - binding.viewPagerBookshelf.adapter = adapter + viewPagerBookshelf.offscreenPageLimit = 1 + viewPagerBookshelf.adapter = TabFragmentPageAdapter() + TabLayoutMediator(tabLayout, viewPagerBookshelf) { tab, i -> + tab.text = bookGroups[i].groupName + }.attach() + viewPagerBookshelf.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + //页面滚动的位置信息回调: position 当前滚动到哪个页面,positionOffset 位置偏移百分比, positionOffsetPixels 当前所在页面偏移量 + //此回调会触发完onPageScrollStateChanged 的 state 值为1时后面才触发回调 + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + currentPosition = position + if (currentState == 1) { + //手指按下滑动坐标记录 + scrolledPixList.add(positionOffsetPixels) + } + } + + + // 滚动状态改变回调,state的值分别有0,1,2 ; + // 0为ViewPager所有事件(1,2)已结束触发 + // 1为在viewPager里按下并滑动触发多次 + // 2是手指抬起触发 + override fun onPageScrollStateChanged(state: Int) { + currentState = state + if (state == 0) { + if (currentPosition == oldPosition) { + when (currentPosition) { + 0 -> { + if (scrolledPixList.size > 1 && scrolledPixList.last() == 0 || scrolledPixList.last() - scrolledPixList[0] > 0) { + //有可能出现滑到一半放弃的情况也是可以出现currentPosition == oldPositon=0,则先判断是否是往右滑时放弃 + return + } + //若还有上一个bottom fragment页面则切换 + mainActivity.viewPager.currentItem.takeIf { it > 0 } + ?.also { mainActivity.viewPager.setCurrentItem(it - 1, true) } + } + + (viewPagerBookshelf.adapter as FragmentStateAdapter).itemCount - 1 -> { + //若还有下一个bottom fragment页面则切换 + mainActivity.viewPager.currentItem.takeIf { it < mainActivity.viewPager.adapter!!.itemCount - 1 } + ?.also { mainActivity.viewPager.setCurrentItem(it + 1, true) } + } + } + } + oldPosition = currentPosition + scrolledPixList.clear()//清空滑动记录 + } + } + + }) } private fun initBookGroupData() { @@ -141,7 +199,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b if (data != bookGroups) { bookGroups.clear() bookGroups.addAll(data) - adapter.notifyDataSetChanged() + binding.viewPagerBookshelf.adapter?.notifyDataSetChanged() selectLastTab() } } @@ -251,29 +309,21 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } } - private inner class TabFragmentPageAdapter(fm: FragmentManager) : - FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - - override fun getPageTitle(position: Int): CharSequence { - return bookGroups[position].groupName - } - - override fun getItemPosition(`object`: Any): Int { - return POSITION_NONE - } + private inner class TabFragmentPageAdapter : + FragmentStateAdapter(this) { - override fun getItem(position: Int): Fragment { + override fun getItemId(position: Int): Long { val group = bookGroups[position] - return BooksFragment.newInstance(position, group.groupId) + return group.groupId } - override fun getCount(): Int { + override fun getItemCount(): Int { return bookGroups.size } - override fun instantiateItem(container: ViewGroup, position: Int): Any { - val fragment = super.instantiateItem(container, position) as BooksFragment + override fun createFragment(position: Int): Fragment { val group = bookGroups[position] + val fragment = BooksFragment.newInstance(position, group.groupId) fragmentMap[group.groupId] = fragment return fragment } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a387ecb36..80c952ab8 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - -