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..d62a7b596 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,11 @@ 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 @@ -43,7 +42,7 @@ class MainActivity : VMBaseActivity(), private var bookshelfReselected: Long = 0 private var exploreReselected: Long = 0 private var pagePosition = 0 - private val fragmentMap = hashMapOf() + private val fragmentMap = hashMapOf() override fun getViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) @@ -53,8 +52,12 @@ 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) { + this@MainActivity.onPageSelected(position) + } + }) bottomNavigationView.elevation = if (AppConfig.elevation < 0) elevation else AppConfig.elevation.toFloat() bottomNavigationView.setOnNavigationItemSelectedListener(this@MainActivity) @@ -105,6 +108,10 @@ class MainActivity : VMBaseActivity(), } } + fun getViewPager(): ViewPager2 { + return binding.viewPagerMain + } + private fun upVersion() { if (LocalConfig.versionCode != appInfo.versionCode) { LocalConfig.versionCode = appInfo.versionCode @@ -186,36 +193,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/RootView.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/RootView.kt new file mode 100644 index 000000000..938116e4e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/RootView.kt @@ -0,0 +1,88 @@ +package io.legado.app.ui.main.bookshelf + +import android.content.Context +import android.gesture.GestureOverlayView.ORIENTATION_HORIZONTAL +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import android.widget.LinearLayout +import androidx.viewpager2.widget.ViewPager2 +import io.legado.app.R +import io.legado.app.ui.main.MainActivity +import io.legado.app.utils.activity +import kotlin.math.absoluteValue +import kotlin.math.sign + +class RootView : LinearLayout { + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + private var touchSlop = 0 + private var initialX = 0f + private var initialY = 0f + + private val parentViewPager: ViewPager2 + get() { + return (activity as MainActivity).getViewPager() + } + + private val childViewPager: View get() = findViewById(R.id.view_pager_bookshelf) + + init { + touchSlop = ViewConfiguration.get(context).scaledTouchSlop + } + + private fun canChildScroll(orientation: Int, delta: Float): Boolean { + val direction = -delta.sign.toInt() + return when (orientation) { + 0 -> childViewPager.canScrollHorizontally(direction) + 1 -> childViewPager.canScrollVertically(direction) + else -> throw IllegalArgumentException() + } + } + + override fun onInterceptTouchEvent(e: MotionEvent): Boolean { + handleInterceptTouchEvent(e) + return super.onInterceptTouchEvent(e) + } + + private fun handleInterceptTouchEvent(e: MotionEvent) { + val orientation = parentViewPager.orientation + // Early return if child can't scroll in same direction as parent + if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) { + return + } + + if (e.action == MotionEvent.ACTION_DOWN) { + initialX = e.x + initialY = e.y + parent.requestDisallowInterceptTouchEvent(true) + } else if (e.action == MotionEvent.ACTION_MOVE) { + val dx = e.x - initialX + val dy = e.y - initialY + val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL + // assuming ViewPager2 touch-slop is 2x touch-slop of child + val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f + val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f + + if (scaledDx > touchSlop || scaledDy > touchSlop) { + + if (isVpHorizontal == (scaledDy > scaledDx)) { + // Gesture is perpendicular, allow all parents to intercept + parent.requestDisallowInterceptTouchEvent(false) + } else { + // Gesture is parallel, query child if movement in that direction is possible + if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) { + // Child can scroll, disallow all parents to intercept + parent.requestDisallowInterceptTouchEvent(true) + } else { + // Child cannot scroll, allow all parents to intercept + parent.requestDisallowInterceptTouchEvent(false) + } + } + } + } + } +} \ No newline at end of file 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"> - - + app:contentLayout="@layout/view_tab_layout_min" + app:title="@string/bookshelf" /> - \ No newline at end of file + \ No newline at end of file