From 52f44c79fc68b775afb8e4fd511194e9d6563bdb Mon Sep 17 00:00:00 2001 From: edubinskaya Date: Wed, 11 Sep 2024 16:39:30 +0300 Subject: [PATCH] fixed focus navigation inside `gallery`. 490183979ceae7bbd78065bad0af92b208c59377 --- .../view2/divs/widgets/DivRecyclerView.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivRecyclerView.kt b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivRecyclerView.kt index fb198547e..b47fee7c3 100644 --- a/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivRecyclerView.kt +++ b/client/android/div/src/main/java/com/yandex/div/core/view2/divs/widgets/DivRecyclerView.kt @@ -8,12 +8,15 @@ import android.view.MotionEvent import android.view.View import android.view.ViewGroup import androidx.appcompat.view.ContextThemeWrapper +import androidx.recyclerview.widget.LinearLayoutManager import com.yandex.div.R import com.yandex.div.core.annotations.Mockable import com.yandex.div.core.view2.Releasable import com.yandex.div.core.view2.backbutton.BackHandlingRecyclerView import com.yandex.div.core.view2.divs.drawChildrenShadows +import com.yandex.div.core.view2.divs.gallery.DivGridLayoutManager import com.yandex.div.core.view2.divs.gallery.PagerSnapStartHelper +import com.yandex.div.core.widget.DivViewWrapper import com.yandex.div.internal.widget.OnInterceptTouchEventListener import com.yandex.div.internal.widget.OnInterceptTouchEventListenerHost import com.yandex.div2.DivGallery @@ -48,6 +51,7 @@ internal class DivRecyclerView @JvmOverloads constructor( var scrollMode = ScrollMode.DEFAULT var pagerSnapStartHelper: PagerSnapStartHelper? = null private var needFling = false + private var beforeScrollFocusPosition = NO_POSITION override fun fling(velocityX: Int, velocityY: Int): Boolean { val flingPerformed = super.fling(velocityX, velocityY) @@ -56,6 +60,43 @@ internal class DivRecyclerView @JvmOverloads constructor( return flingPerformed } + override fun onScrollStateChanged(state: Int) { + when (state) { + SCROLL_STATE_SETTLING -> { + val focusedChild = focusedChild ?: run { + beforeScrollFocusPosition = NO_POSITION + return + } + + beforeScrollFocusPosition = getChildAdapterPosition(focusedChild) + } + } + super.onScrollStateChanged(state) + } + + override fun onScrolled(dx: Int, dy: Int) { + // if there was no focus before scroll we should not set extra focus + if (beforeScrollFocusPosition == NO_POSITION) return + + val orientation = when (val layoutManager = layoutManager) { + is LinearLayoutManager -> layoutManager.orientation + is DivGridLayoutManager -> layoutManager.orientation + else -> HORIZONTAL + } + + val nextPosition = when { + orientation == VERTICAL && dy > 0 -> beforeScrollFocusPosition + 1 + orientation == VERTICAL && dy <= 0 -> beforeScrollFocusPosition - 1 + dx > 0 -> beforeScrollFocusPosition + 1 + else -> beforeScrollFocusPosition - 1 + } + + (findViewHolderForAdapterPosition(nextPosition)?.itemView as? DivViewWrapper) + ?.child?.requestFocus() + + super.onScrolled(dx, dy) + } + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { val intercepted = onInterceptTouchEventListener?.onInterceptTouchEvent(target = this, event = event) ?: false