Skip to content

Commit

Permalink
Fix crash when layout manager is set via XML
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensousa committed Aug 9, 2024
1 parent d326500 commit f27a163
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 8 deletions.
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,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
internal val DEBUG = BuildConfig.DEBUG
}

private val viewHolderTaskExecutor = ViewHolderTaskExecutor()
private var viewHolderTaskExecutor: ViewHolderTaskExecutor? = null
private val focusableChildDrawingCallback = FocusableChildDrawingCallback()
private val fadingEdge = FadingEdge()

Expand Down Expand Up @@ -212,7 +212,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 +225,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 +236,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
hasPendingLayout = false
}
}
layout.addOnViewHolderSelectedListener(viewHolderTaskExecutor)
viewHolderTaskExecutor?.let { layout.addOnViewHolderSelectedListener(it) }
pivotLayoutManager = layout
}
}
Expand Down Expand Up @@ -1022,7 +1025,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 +1044,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 +1065,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 +1102,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

0 comments on commit f27a163

Please sign in to comment.