Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash when layout manager is set via XML #247

Merged
merged 3 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dpadrecyclerview/api/dpadrecyclerview.api
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ public final class com/rubensousa/dpadrecyclerview/layoutmanager/DpadLayoutParam
}

public final class com/rubensousa/dpadrecyclerview/layoutmanager/PivotLayoutManager : androidx/recyclerview/widget/RecyclerView$LayoutManager, androidx/recyclerview/widget/ItemTouchHelper$ViewDropHandler, androidx/recyclerview/widget/RecyclerView$SmoothScroller$ScrollVectorProvider {
public fun <init> (Landroid/content/Context;Landroid/util/AttributeSet;II)V
public fun <init> (Landroidx/recyclerview/widget/RecyclerView$LayoutManager$Properties;)V
public final fun addOnLayoutCompletedListener (Lcom/rubensousa/dpadrecyclerview/DpadRecyclerView$OnLayoutCompletedListener;)V
public final fun addOnViewFocusedListener (Lcom/rubensousa/dpadrecyclerview/OnViewFocusedListener;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

package com.rubensousa.dpadrecyclerview.test.tests

import androidx.fragment.app.Fragment
import androidx.fragment.app.testing.launchFragment
import androidx.recyclerview.widget.RecyclerView.LayoutManager.Properties
import com.google.common.truth.Truth.assertThat
import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.layoutmanager.PivotLayoutManager
import com.rubensousa.dpadrecyclerview.test.R
import org.junit.Test

class PivotLayoutManagerTest {
Expand All @@ -41,4 +45,21 @@ class PivotLayoutManagerTest {
assertThat(config.focusOutSideBack).isTrue()
}

@Test
fun testPivotLayoutManagerFromXML() {
// given
val fragment = launchFragment<XMLFragment>()
var recyclerView: DpadRecyclerView? = null

// when
fragment.onFragment {
recyclerView = it.requireView() as DpadRecyclerView
}

// then
assertThat(recyclerView).isNotNull()
}

class XMLFragment : Fragment(R.layout.dpadrecyclerview_layout_name)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.rubensousa.dpadrecyclerview.DpadRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="com.rubensousa.dpadrecyclerview.layoutmanager.PivotLayoutManager" />
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ open class DpadRecyclerView @JvmOverloads constructor(
internal val DEBUG = BuildConfig.DEBUG
}

private val viewHolderTaskExecutor = ViewHolderTaskExecutor()
// Nullable because setLayoutManager can be called by the parent class before this instantiated
private var viewHolderTaskExecutor: ViewHolderTaskExecutor? = ViewHolderTaskExecutor()
private val focusableChildDrawingCallback = FocusableChildDrawingCallback()
private val fadingEdge = FadingEdge()

Expand Down Expand Up @@ -212,7 +213,9 @@ open class DpadRecyclerView @JvmOverloads constructor(

final override fun setLayoutManager(layout: LayoutManager?) {
super.setLayoutManager(layout)
pivotLayoutManager?.removeOnViewHolderSelectedListener(viewHolderTaskExecutor)
viewHolderTaskExecutor?.let {
pivotLayoutManager?.removeOnViewHolderSelectedListener(it)
}
pivotLayoutManager?.updateRecyclerView(null)
if (pivotLayoutManager !== layout) {
pivotLayoutManager?.layoutCompletedListener = null
Expand All @@ -223,7 +226,8 @@ open class DpadRecyclerView @JvmOverloads constructor(

if (layout != null && layout !is PivotLayoutManager) {
throw IllegalArgumentException(
"Only PivotLayoutManager is supported, but got $layout"
"Only com.rubensousa.dpadrecyclerview.layoutmanager.PivotLayoutManager" +
".PivotLayoutManager is supported, but got $layout"
)
}
if (layout is PivotLayoutManager) {
Expand All @@ -233,7 +237,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
hasPendingLayout = false
}
}
layout.addOnViewHolderSelectedListener(viewHolderTaskExecutor)
viewHolderTaskExecutor?.let { layout.addOnViewHolderSelectedListener(it) }
pivotLayoutManager = layout
}
}
Expand Down Expand Up @@ -1022,7 +1026,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
* @param task Task to executed on the ViewHolder at the given position
*/
fun setSelectedPosition(position: Int, task: ViewHolderTask) {
viewHolderTaskExecutor.schedule(position, task)
viewHolderTaskExecutor?.schedule(position, task)
requireLayout().selectPosition(position, subPosition = 0, smooth = false)
}

Expand All @@ -1041,7 +1045,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
* @param task Task to executed on the ViewHolder at the given position
*/
fun setSelectedPositionSmooth(position: Int, task: ViewHolderTask) {
viewHolderTaskExecutor.schedule(position, task)
viewHolderTaskExecutor?.schedule(position, task)
requireLayout().selectPosition(position, subPosition = 0, smooth = true)
}

Expand All @@ -1062,7 +1066,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
* @param task Task to executed on the ViewHolder at the given position
*/
fun setSelectedSubPosition(position: Int, subPosition: Int, task: ViewHolderTask) {
viewHolderTaskExecutor.schedule(position, subPosition, task)
viewHolderTaskExecutor?.schedule(position, subPosition, task)
requireLayout().selectPosition(position, subPosition, smooth = false)
}

Expand Down Expand Up @@ -1099,7 +1103,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
* @param task Task to executed on the ViewHolder at the given position
*/
fun setSelectedSubPositionSmooth(position: Int, subPosition: Int, task: ViewHolderTask) {
viewHolderTaskExecutor.schedule(position, subPosition, task)
viewHolderTaskExecutor?.schedule(position, subPosition, task)
requireLayout().selectPosition(position, subPosition, smooth = true)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ class PivotLayoutManager(properties: Properties) : RecyclerView.LayoutManager(),
private var isScrollingFromTouchEvent = false
internal var layoutCompletedListener: DpadRecyclerView.OnLayoutCompletedListener? = null

// This is required for XML usage
@Suppress("unused", "UNUSED_PARAMETER")
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : this(
Properties()
)

override fun checkLayoutParams(layoutParams: RecyclerView.LayoutParams?): Boolean {
return layoutParams is DpadLayoutParams
}
Expand Down
Loading