Comments (14)
Fix here: #204
Will be available in 1.3.0-alpha02
from dpadrecyclerview.
Hi @fankloano . Thank you for the detailed bug report, this will help me a lot to investigate.
Will let you know once a fix is available.
from dpadrecyclerview.
@fankloano 1.3.0-alpha02
is already available. Please let me know if the problem was solved in that version
from dpadrecyclerview.
@rubensousa
sorry for my late answer. The issue seems solved with 1.3.0-alpha02, thanks :-)
Another thing, regarding to the same recyclerview: I just realised that the first image/cardview is smaller then the others. I checked if I have set a margin or something similar that eventually could cause the problem, but there isn't set any. Can you reproduce it?
(should I open a new issue?)
from dpadrecyclerview.
@fankloano yes, please open a new issue and attach a sample project that reproduces it if possible. I won't be able to fix that one so soon since I will be away for vacation
from dpadrecyclerview.
Hi there, I hope you are doing well
I'm facing an issue that when I use setSpanSizeLookup, the last row of items won't get focused.
I've upgraded the library version to 1.3.0-alpha02 but the problem persists.
Is it related to this issue or do I need to open another one?
from dpadrecyclerview.
Hi there @tyrel-carlson . No, this issue should be solved. Please create a new one, ideally with reproduction steps and a video recording
from dpadrecyclerview.
Sorry for late answer, I'm using the dpad recycler with a span count of 4 integrated with a spanSizeLookup to decide if the span size should be 1 or 4 depending on the item type (header or cell) in a sectioned grid view.
the problem is that the last row of items (including a date header) is not getting focused unless I do a fast scrolling but not from direct upper items, so for your information I'm not allowed to publish any screen recording of the production app, so I provide some code here and let me know if I'm missing something, if not I'll open an issue:
private fun setupRecyclerView() = with(binding) {
recycler.adapter = adapter
recycler.setSpanCount(SPAN_COUNT)
recycler.setSpanSizeLookup(object : DpadSpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (position < adapter.itemCount
&& adapter.isSectionHeader(position)
) SPAN_COUNT else 1
}
})
recycler.attachListController(viewModel.listController)
}
companion object {
const val SPAN_COUNT = 4
}
open fun isSectionHeader(position: Int): Boolean {
return differ.currentList[position] is DataHolder.Section<*>
}
fun DpadRecyclerView.attachListController(
controller: StreamingListController
) {
val listener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as? PivotLayoutManager
?: return
val firstVisibleIndex = layoutManager.findFirstVisibleItemPosition()
val lastVisibleIndex = max(firstVisibleIndex, layoutManager.findLastVisibleItemPosition())
controller.setIndexRange(range = StreamingListController.IndexRange(
start = firstVisibleIndex,
endInclusive = lastVisibleIndex
))
}
}
addOnScrollListener(listener)
}
<com.rubensousa.dpadrecyclerview.DpadRecyclerView
android:id="@+id/recycler"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="10dp"
android:clipToPadding="false"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
from dpadrecyclerview.
I'm still stuck on this, can you please help me with that? @rubensousa
from dpadrecyclerview.
Please open a new issue with a video recording and attach this code snippet above. @tyrel-carlson
from dpadrecyclerview.
@tyrel-carlson did you solve this problem?
from dpadrecyclerview.
Yeah, I managed to solve this using my own focusSearch. Here is my solution, so feel free to use it to improve the repo.
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.rubensousa.dpadrecyclerview.DpadRecyclerView
class SectionableRecyclerView : DpadRecyclerView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
init {
installGlobalLayoutListener {
// Here we prevent the focus from being lost when the user focuses the empty recyclerview
if (hasFocus() && childCount > 1) {
val focused = findFocus()
if (focused == null || focused is RecyclerView) {
getChildAt(1)?.requestFocus()
}
}
}
}
override fun setAdapter(adapter: Adapter<*>?) {
if (adapter != null && adapter !is SectionedListAdapter<*, *, *, *>) {
throw IllegalArgumentException("Must be a SectionedListAdapter")
}
super.setAdapter(adapter)
}
override fun focusSearch(focused: View, direction: Int): View? {
try {
val adapter = adapter as SectionedListAdapter<*, *, *, *>
// Get the current position of the focused view
val currentPosition = getChildAdapterPosition(focused)
if (currentPosition == NO_POSITION) {
return super.focusSearch(focused, direction)
}
// Find the next position based on the focus direction
val nextPosition = when (direction) {
View.FOCUS_UP,
View.FOCUS_DOWN -> findNextPosition(adapter, currentPosition, direction)
else -> return super.focusSearch(focused, direction)
}
// Ensure the next position is valid
if (nextPosition == NO_POSITION || !isPositionValid(adapter, nextPosition)) {
return when (direction) {
View.FOCUS_UP -> parent.focusSearch(focused, direction)
else -> super.focusSearch(focused, direction)
}
}
// This is to prevent the recycler from reverting to previously focused item
// in some situations
layoutManager?.scrollToPosition(nextPosition)
return findViewAtPosition(nextPosition) ?: return super.focusSearch(focused, direction)
} catch (e: Exception) {
return super.focusSearch(focused, direction)
}
}
/**
* Finds the next valid position to focus on when navigating in the specified direction.
*
* @param adapter The adapter of the RecyclerView, which must be a SectionedListAdapter.
* @param currentPosition The current position of the focused item.
* @param direction The direction of the focus movement, either View.FOCUS_DOWN or View.FOCUS_UP.
* @return The next valid position to focus on, or NO_POSITION if no valid position is found.
*/
private fun findNextPosition(adapter: SectionedListAdapter<*, *, *, *>, currentPosition: Int, direction: Int): Int {
val spanCount = getSpanCount()
val currentSpanIndex = getSpanIndex(currentPosition, spanCount)
return when (direction) {
View.FOCUS_DOWN -> {
var nextPosition = currentPosition + 1
while (
isPositionValid(adapter, nextPosition) &&
(currentSpanIndex != getSpanIndex(nextPosition, spanCount) || adapter.isSectionHeader(nextPosition))
) {
nextPosition++
}
// Prevent unusual focus movement if the destination cell is empty
if (nextPosition - currentPosition > (spanCount + 1))
findNextPosition(adapter, currentPosition - 1, direction)
else nextPosition
}
View.FOCUS_UP -> {
var previousPosition = currentPosition - 1
while (
isPositionValid(adapter, previousPosition) &&
(currentSpanIndex != getSpanIndex(previousPosition, spanCount) || adapter.isSectionHeader(previousPosition))
) {
previousPosition--
}
// Prevent unusual focus movement if the destination cell is empty
if (currentPosition - previousPosition > (spanCount + 1))
findNextPosition(adapter, currentPosition - 1, direction)
else previousPosition
}
else -> NO_POSITION
}
}
/**
* Checks if the given position is valid within the adapter's item count.
*
* @param adapter The adapter of the RecyclerView, which must be a SectionedListAdapter.
* @param position The position to check.
* @return True if the position is within the bounds of the adapter's item count, false otherwise.
*/
private fun isPositionValid(adapter: SectionedListAdapter<*, *, *, *>, position: Int): Boolean {
return position in 0 until adapter.itemCount
}
/**
* Retrieves the span index for the given position in the grid.
*
* @param position The position of the item.
* @param spanCount The number of spans in the grid.
*/
private fun getSpanIndex(position: Int, spanCount: Int): Int {
return getSpanSizeLookup().getSpanIndex(position, spanCount)
}
/**
* Finds the view at the specified adapter position.
*
* @param position The adapter position of the item.
* @return The view at the specified position, or null if no view is found.
*/
private fun findViewAtPosition(position: Int): View? {
val layoutManager = layoutManager ?: return null
return (0 until layoutManager.childCount)
.mapNotNull { layoutManager.getChildAt(it) }
.firstOrNull { getChildAdapterPosition(it) == position }
}
}
from dpadrecyclerview.
Can you please raise a new issue with the original problem so I can have a look for the next release? Meanwhile 1.3.0-alpha03
should remove the need for that workaround you have for focus in that constructor
from dpadrecyclerview.
Sure, I will open a new issue. FYI, I've tested 1.3.0-alpha03
, and it doesn't solve this issue yet.
from dpadrecyclerview.
Related Issues (20)
- First item of first row is smaller then all the others HOT 4
- Fast scrolling - loosing focus when having images from an url in the items HOT 21
- Scrolling issue when loading images in onBindViewHolder HOT 9
- Scroll a nested recyclerview to a specific item (without focussing it) HOT 3
- Bug: DpadSpanSizeLookup's getSpanSize function is being called infinitely after removing an item HOT 8
- Bug: Last row not getting focused while using DpadSpanSizeLookup HOT 1
- Bug: DpadSpanSizeLookup's getSpanSize function is being called infinitely while fast scrolling HOT 19
- Focus does not leave DpadRecyclerView in some cases when using Compose HOT 1
- Do not allow focusing other rows if grids are incomplete
- how to center scroll like CenterLayoutManager in horizontal HOT 1
- OnViewFocused is not called for parent RecyclerView if child does not attach a listener
- DpadRecyclerView shouldn't lose focus if adapter is cleared
- Nested Child recycler view onCreate called every time during parent recycler view scroll. HOT 9
- Incorrect predictive animation after adapter changes
- java.lang.IllegalStateException: Cannot call removeView(At) within removeView(At) HOT 8
- How can I bind the selected state to the holder content? HOT 7
- Drag & Drop Implementation Help HOT 4
- Crash when app:layoutManager is set in XML
- issue while scrolling top to button and left to right HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dpadrecyclerview.