### Create Individual Styles Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/xml.md Examples of custom styles for horizontal and vertical DpadRecyclerView configurations. ```xml ``` -------------------------------- ### Set Extra Layout Space Strategy Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/layout.md Implement ExtraLayoutSpaceStrategy to define how extra layout space is calculated. This example adds half a page of extra space at the start for alignment purposes. ```kotlin recyclerView.setExtraLayoutSpaceStrategy(object : ExtraLayoutSpaceStrategy { override fun calculateStartExtraLayoutSpace(state: RecyclerView.State): Int { return recyclerView.width / 2 } }) ``` -------------------------------- ### Configure Start Alignment Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/alignment.md Aligns items to the start of the container with a specific offset. ```xml ``` ```kotlin recyclerView.setParentAlignment( ParentAlignment( fraction = 0f, offset = 24.dp.toPx() ) ) recyclerView.setChildAlignment( ChildAlignment(fraction = 0f) ) ``` -------------------------------- ### Enable Infinite Looping Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Configure adapter content looping behavior when reaching the start or end of the list. ```kotlin // Loop in both directions recyclerView.setLoopDirection(DpadLoopDirection.MIN_MAX) // Loop only at the end recyclerView.setLoopDirection(DpadLoopDirection.MAX) // Disable looping recyclerView.setLoopDirection(DpadLoopDirection.NONE) ``` -------------------------------- ### Start Dragging an Item Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/dragdrop.md Initiate a drag operation on a specific item by calling startDrag with its position. If the item is not selected, a selection will be triggered first. ```kotlin dragHelper.startDrag(position = 0) ``` -------------------------------- ### Custom Span Sizes with DpadSpanSizeLookup Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/layout.md Implement DpadSpanSizeLookup to customize the span size of items in a grid. This example makes the first item span the full width. ```kotlin recyclerView.setSpanSizeLookup(object : DpadSpanSizeLookup() { override fun getSpanSize(position: Int): Int { return if (position == 0) { recyclerView.getSpanCount() } else { 1 } } }) ``` -------------------------------- ### Asserting DpadRecyclerView State Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/testing.md Example of using DpadRecyclerViewAssertions to verify the focus state of a ViewHolder at a specific position. ```kotlin Espresso.onView(withId(R.id.recyclerView)) .assert(DpadRecyclerViewAssertions.isFocused(position = 5)) ``` -------------------------------- ### Setup Horizontal Spacing for DpadRecyclerView Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/spacing.md Use this function to configure horizontal item and edge spacing for a DpadRecyclerView. Ensure R.dimen.grid_horizontal_item_spacing and R.dimen.horizontal_edge_spacing are defined in your resources. ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadGridSpacingDecoration.create( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.grid_horizontal_item_spacing ), perpendicularItemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.grid_horizontal_item_spacing ), edgeSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.horizontal_edge_spacing ) ) ) } ``` -------------------------------- ### Limit Pending Focus Requests Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/scrolling.md Control the responsiveness to key events by setting `setFocusSearchDebounceMs`. This example ignores key events faster than 200ms to prevent excessive scrolling. ```kotlin // Will ignore key events faster than 200ms recyclerView.setFocusSearchDebounceMs(200) ``` -------------------------------- ### Performing DpadRecyclerView Actions Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/testing.md Example of using DpadRecyclerViewActions to scroll to a specific item within a RecyclerView. ```kotlin Espresso.onView(withId(R.id.recyclerView)) .perform(DpadRecyclerViewActions.scrollTo( hasDescendant(withText("Some title")) )) ``` -------------------------------- ### Change Smooth Scrolling Behavior with Linear Interpolator Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/scrolling.md Customize the smooth scrolling behavior by providing a custom `SmoothScrollByBehavior`. This example sets a `LinearInterpolator` to change the default animation. ```kotlin val linearInterpolator = LinearInterpolator() recyclerView.setSmoothScrollBehavior( object : DpadRecyclerView.SmoothScrollByBehavior { override fun configSmoothScrollByDuration(dx: Int, dy: Int): Int { return RecyclerView.UNDEFINED_DURATION } override fun configSmoothScrollByInterpolator(dx: Int, dy: Int): Interpolator { return linearInterpolator } } ) ``` -------------------------------- ### Configure DpadRecyclerView via XML Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Define layout, alignment, spacing, and focus behavior directly in XML layout files. ```xml android:orientation="vertical" app:spanCount="5" app:reverseLayout="false" android:gravity="center" app:dpadRecyclerViewParentAlignmentFraction="0.5" app:dpadRecyclerViewParentAlignmentOffset="24dp" app:dpadRecyclerViewParentAlignmentEdge="min_max" app:dpadRecyclerViewChildAlignmentFraction="0.5" app:dpadRecyclerViewChildAlignmentOffset="0dp" app:dpadRecyclerViewItemSpacing="8dp" app:dpadRecyclerViewItemEdgeSpacing="16dp" app:dpadRecyclerViewFocusOutFront="true" app:dpadRecyclerViewFocusOutBack="false" app:dpadRecyclerViewFocusOutSideFront="true" app:dpadRecyclerViewFocusOutSideBack="true" app:dpadRecyclerViewSmoothFocusChangesEnabled="true" app:dpadRecyclerViewFocusableDirection="standard" /> ``` -------------------------------- ### Implement Dpad-compatible Composable Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/getting_started.md Create a focusable Composable using dpadClickable and onFocusChanged modifiers. ```kotlin @Composable fun ItemComposable( item: Int, onClick: () -> Unit, modifier: Modifier = Modifier, ) { var isFocused by remember { mutableStateOf(false) } val backgroundColor = if (isFocused) Color.White else Color.Black val textColor = if (isFocused) Color.Black else Color.White Box( modifier = modifier .background(backgroundColor) .onFocusChanged { focusState -> isFocused = focusState.hasFocus } .focusable() .dpadClickable { onClick() }, contentAlignment = Alignment.Center, ) { Text( text = item.toString(), color = textColor, fontSize = 35.sp ) } } ``` -------------------------------- ### Assert Focus and Selection in Espresso Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Use DpadRecyclerViewAssertions to verify the focus and selection state of items at specific positions. ```kotlin @Test fun testFocusAndSelection() { // Assert ViewHolder at position is focused Espresso.onView(withId(R.id.recyclerView)) .check(DpadRecyclerViewAssertions.isFocused(position = 5)) // Assert ViewHolder at position is selected Espresso.onView(withId(R.id.recyclerView)) .check(DpadRecyclerViewAssertions.isSelected(position = 5)) // Assert selection with sub-position Espresso.onView(withId(R.id.recyclerView)) .check(DpadRecyclerViewAssertions.isSelected(position = 5, subPosition = 1)) } ``` -------------------------------- ### Configure DpadRecyclerView in XML Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/getting_started.md Add the view to your layout file. Do not manually set a LayoutManager as it is handled internally. ```xml ``` -------------------------------- ### Dispatching Key Events with KeyEvents Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/testing.md Utility methods for simulating key presses with configurable counts and delays. ```kotlin KeyEvents.click() KeyEvents.back() KeyEvents.pressDown(times = 5) // 50 ms between each key press KeyEvents.pressUp(times = 5, delay = 50) ``` -------------------------------- ### Listen for Selection Changes Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Add a listener to observe selection changes and alignment events as users navigate items with DPAD controls. ```kotlin recyclerView.addOnViewHolderSelectedListener(object : OnViewHolderSelectedListener { override fun onViewHolderSelected( parent: DpadRecyclerView, child: RecyclerView.ViewHolder?, position: Int, subPosition: Int ) { // Called immediately when selection changes Log.d("Selection", "Selected position: $position, subPosition: $subPosition") } override fun onViewHolderSelectedAndAligned( parent: DpadRecyclerView, child: RecyclerView.ViewHolder?, position: Int, subPosition: Int ) { // Called after scrolling animation completes Log.d("Selection", "Aligned to position: $position") } }) ``` -------------------------------- ### Add DpadRecyclerView dependencies Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/getting_started.md Include the library and optional Compose or testing modules in your build.gradle file. ```groovy implementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview:{{ dpadrecyclerview.version }}" // Recommended: To use Compose together with DpadRecyclerView implementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-compose:{{ dpadrecyclerview.version }}" // Optional: Espresso test helpers for your instrumented tests: androidTestImplementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-testing:{{ dpadrecyclerview.version }}" ``` -------------------------------- ### Manage Programmatic Selection in Kotlin Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Navigates to specific positions or sub-positions with optional smooth scrolling and completion callbacks. ```kotlin // Immediate jump to position recyclerView.setSelectedPosition(position = 10) // Smooth scroll to position recyclerView.setSelectedPositionSmooth(position = 10) // Selection with callback when complete recyclerView.setSelectedPosition(position = 0, object : ViewHolderTask() { override fun execute(viewHolder: RecyclerView.ViewHolder) { // ViewHolder is now selected and aligned viewHolder.itemView.requestFocus() } }) // Select specific sub-position recyclerView.setSelectedSubPosition(position = 5, subPosition = 1) recyclerView.setSelectedSubPositionSmooth(position = 5, subPosition = 2) // Get current selection val position = recyclerView.getSelectedPosition() val subPosition = recyclerView.getSelectedSubPosition() ``` -------------------------------- ### Create and Attach DpadDragHelper Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/dragdrop.md Instantiate DpadDragHelper with your mutable adapter and a callback for drag events. Then, attach the helper to your DpadRecyclerView. ```kotlin private val adapter = ExampleAdapter() private val dragHelper = DpadDragHelper( adapter = dragAdapter, callback = object : DpadDragHelper.DragCallback { override fun onDragStarted(viewHolder: RecyclerView.ViewHolder) { // ViewHolder is now being dragged } override fun onDragStopped(fromUser: Boolean) { // Dragging was cancelled either by user or programmatically } } ) dragHelper.attachToRecyclerView(dpadRecyclerView) ``` -------------------------------- ### Configure Grid Spacing Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/spacing.md Apply spacing decorations to grid layouts. ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadGridSpacingDecoration.createVertical( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.grid_horizontal_item_spacing ), perpendicularItemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.grid_vertical_item_spacing ), edgeSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.grid_vertical_edge_spacing ) ) ) } ``` ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadGridSpacingDecoration.create( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.grid_item_spacing ) ) ) } ``` -------------------------------- ### Apply Theme Styling Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/xml.md Configuration for setting a default style for DpadRecyclerView within an application theme. ```xml ``` -------------------------------- ### Dispatch DPAD Key Events in Espresso Tests Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Utilize the KeyEvents utility to dispatch DPAD key events within Espresso tests for navigation testing. Supports single key presses and multiple presses with optional delays. ```kotlin @Test fun testNavigation() { // Single key presses KeyEvents.click() KeyEvents.back() // Multiple presses KeyEvents.pressDown(times = 5) KeyEvents.pressUp(times = 5, delay = 50) // 50ms between presses KeyEvents.pressLeft(times = 3) KeyEvents.pressRight(times = 3) } ``` -------------------------------- ### Configure Custom Grid Span Sizes Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Implement DpadSpanSizeLookup to define custom span sizes for items, such as full-width headers. ```kotlin // Custom span sizes for headers recyclerView.setSpanSizeLookup(object : DpadSpanSizeLookup() { override fun getSpanSize(position: Int): Int { return if (position == 0) { recyclerView.getSpanCount() // Full-width header } else { 1 // Regular item } } }) ``` -------------------------------- ### Configure Spacing APIs Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/spacing.md Available methods for setting spacing properties on the DpadRecyclerView. ```kotlin setItemSpacing() setItemEdgeSpacing() setItemMaxEdgeSpacing() setItemMinEdgeSpacing() ``` -------------------------------- ### Migrating Selection Listeners from BaseGridView to DpadRecyclerView Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/migrating_leanback.md This code shows how to migrate from BaseGridView's addOnChildViewHolderSelectedListener to DpadRecyclerView's addOnViewHolderSelectedListener. ```kotlin recyclerView.addOnChildViewHolderSelectedListener(object : OnChildViewHolderSelectedListener() { override fun onChildViewHolderSelected( parent: RecyclerView, child: RecyclerView.ViewHolder?, position: Int, subposition: Int ) {} override fun onChildViewHolderSelectedAndPositioned( parent: RecyclerView, child: RecyclerView.ViewHolder?, position: Int, subposition: Int ) {} }) ``` ```kotlin recyclerView.addOnViewHolderSelectedListener(object : OnViewHolderSelectedListener { override fun onViewHolderSelected( parent: DpadRecyclerView, child: RecyclerView.ViewHolder?, position: Int, subPosition: Int ) {} override fun onViewHolderSelectedAndAligned( parent: DpadRecyclerView, child: RecyclerView.ViewHolder?, position: Int, subPosition: Int ) {} }) ``` -------------------------------- ### Configure Smooth Scrolling Behavior Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Adjust scroll speed, interpolation, and pending request limits to customize the smooth scrolling experience. ```kotlin // Disable smooth scrolling for immediate focus changes recyclerView.setSmoothFocusChangesEnabled(false) // Slow down smooth scrolling (2x slower) recyclerView.setSmoothScrollSpeedFactor(2f) // Custom scroll behavior with interpolator val linearInterpolator = LinearInterpolator() recyclerView.setSmoothScrollBehavior( object : DpadRecyclerView.SmoothScrollByBehavior { override fun configSmoothScrollByDuration(dx: Int, dy: Int): Int { return RecyclerView.UNDEFINED_DURATION // Use default } override fun configSmoothScrollByInterpolator(dx: Int, dy: Int): Interpolator { return linearInterpolator } } ) // Limit pending scroll requests to prevent over-scrolling recyclerView.setSmoothScrollMaxPendingAlignments(2) recyclerView.setSmoothScrollMaxPendingMoves(3) ``` -------------------------------- ### Configure Grid Layout in XML Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/layout.md Use this XML to set up a DpadRecyclerView as a grid. The 'app:spanCount' attribute defines the number of columns in the grid. ```xml ``` -------------------------------- ### Configure Grid Layout in Kotlin Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/layout.md Use this Kotlin code to set up a DpadRecyclerView as a grid programmatically. Call setSpanCount to define the number of columns. ```kotlin recyclerView.setSpanCount(5) ``` -------------------------------- ### Add DpadRecyclerView Dependencies Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Add these dependencies to your Gradle build file to include the core library, Compose integration, and testing utilities. ```groovy // Core library implementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview:1.5.0-beta01" // Recommended: Compose integration implementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-compose:1.5.0-beta01" // Optional: Espresso test helpers androidTestImplementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-testing:1.5.0-beta01" ``` -------------------------------- ### Migrating Window Alignment from BaseGridView to DpadRecyclerView Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/migrating_leanback.md This snippet shows how to migrate window alignment settings from BaseGridView to DpadRecyclerView's ParentAlignment. ```kotlin recyclerView.windowAlignment = BaseGridView.WINDOW_ALIGN_NO_EDGE recyclerView.windowAlignmentOffset = 0 recyclerView.windowAlignmentOffsetPercent = 100f recyclerView.windowAlignmentPreferKeyLineOverLowEdge = false recyclerView.windowAlignmentPreferKeyLineOverHighEdge = false ``` ```kotlin recyclerView.setParentAlignment( ParentAlignment( edge = ParentAlignment.Edge.NONE, offset = 0, fraction = 1f, preferKeylineOverEdge = false ) ) ``` -------------------------------- ### Configure Grid Layout Span Count Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Set the number of columns for a grid layout. This should be called before the adapter is set. ```kotlin // Set up a 5-column grid recyclerView.setSpanCount(5) ``` -------------------------------- ### Implement DpadComposeViewHolder for View-system focus Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/compose.md Use DpadComposeViewHolder to maintain focus state within the View system and pass it as a parameter to Composables. ```kotlin class ComposeItemAdapter( private val onItemClick: (Int) -> Unit ) : ListAdapter>(Item.DIFF_CALLBACK) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): DpadComposeViewHolder { return DpadComposeViewHolder( parent, onClick = onItemClick ) { item, isFocused -> ItemComposable(item, isFocused) } } override fun onBindViewHolder( holder: DpadComposeViewHolder, position: Int ) { holder.setItemState(getItem(position)) } } ``` -------------------------------- ### Configure grid focus direction Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/focus.md Sets the focus navigation strategy for the grid layout. ```kotlin recyclerView.setFocusableDirection(FocusableDirection.CIRCULAR) ``` ```kotlin recyclerView.setFocusableDirection(FocusableDirection.CONTINUOUS) ``` -------------------------------- ### Migrate Window Alignment from BaseGridView to DpadRecyclerView Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Use ParentAlignment in DpadRecyclerView to replicate window alignment settings from Leanback's BaseGridView. Ensure correct mapping of edge alignment constants. ```kotlin // Leanback BaseGridView recyclerView.windowAlignment = BaseGridView.WINDOW_ALIGN_NO_EDGE recyclerView.windowAlignmentOffset = 0 recyclerView.windowAlignmentOffsetPercent = 100f // DpadRecyclerView equivalent recyclerView.setParentAlignment( ParentAlignment( edge = ParentAlignment.Edge.NONE, offset = 0, fraction = 1f ) ) // Edge alignment mapping: // WINDOW_ALIGN_NO_EDGE -> ParentAlignment.Edge.NONE // WINDOW_ALIGN_LOW_EDGE -> ParentAlignment.Edge.MIN // WINDOW_ALIGN_MAX_EDGE -> ParentAlignment.Edge.MAX // WINDOW_ALIGN_BOTH_EDGE -> ParentAlignment.Edge.MIN_MAX ``` -------------------------------- ### Enable Infinite Scrolling with Looping Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/layout.md Configure DpadRecyclerView to loop its adapter contents for infinite scrolling. Use setLoopDirection with DpadLoopDirection.MIN_MAX for both directions or DpadLoopDirection.MAX for end-only looping. Looping requires enough items to fill the viewport. ```kotlin // This will loop when scrolling towards both the start and end edges recyclerView.setLoopDirection(DpadLoopDirection.MIN_MAX) // This will loop only when scrolling towards the end recyclerView.setLoopDirection(DpadLoopDirection.MAX) ``` -------------------------------- ### Configure Fading Edges Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Set up visual fading indicators for off-screen content via XML or programmatically. ```xml ``` ```kotlin // Programmatic fading edge control recyclerView.setFadingEdgeLength(120.dpToPx()) recyclerView.setMinEdgeFadingLength(60.dpToPx()) recyclerView.setMaxEdgeFadingLength(120.dpToPx()) recyclerView.enableMinEdgeFading(true) recyclerView.enableMaxEdgeFading(true) ``` -------------------------------- ### Compose Integration with DpadComposeViewHolder Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Create ViewHolders that render Composables while keeping focus within the View system. This adapter uses DpadComposeViewHolder to render Composables. ```kotlin class ComposeItemAdapter( private val onItemClick: (Int) -> Unit ) : ListAdapter>(DiffCallback) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): DpadComposeViewHolder { return DpadComposeViewHolder( parent, onClick = onItemClick ) { item, isFocused -> ItemComposable(item, isFocused) } } override fun onBindViewHolder( holder: DpadComposeViewHolder, position: Int ) { holder.setItemState(getItem(position)) } } ``` ```kotlin @Composable fun ItemComposable(item: Int, isFocused: Boolean) { val backgroundColor = if (isFocused) Color.White else Color.Black val textColor = if (isFocused) Color.Black else Color.White Box( modifier = Modifier.background(backgroundColor), contentAlignment = Alignment.Center ) { Text( text = item.toString(), color = textColor, fontSize = 35.sp ) } } ``` -------------------------------- ### Implement DpadViewHolder Interface Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/selection.md Implement DpadViewHolder in your ViewHolder to automatically receive selection and deselection events. ```kotlin class ExampleViewHolder( view: View ) : RecyclerView.ViewHolder(view), DpadViewHolder { override fun onViewHolderSelected() {} override fun onViewHolderDeselected() {} } ``` -------------------------------- ### Configure Linear Column Spacing Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/spacing.md Apply spacing decorations to a vertical linear layout. ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadLinearSpacingDecoration.create( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.vertical_item_spacing ), edgeSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.vertical_edge_spacing ), perpendicularEdgeSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.horizontal_edge_spacing ) ) ) } ``` ```xml ``` ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadLinearSpacingDecoration.create( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.vertical_item_spacing ) ) ) } ``` -------------------------------- ### Implement Sub Position Alignment Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/alignment.md Defines custom alignment points within a ViewHolder by implementing DpadViewHolder. ```kotlin class ExampleViewHolder( view: View ) : RecyclerView.ViewHolder(view), DpadViewHolder { private val alignments = ArrayList() init { alignments.apply { add( SubPositionAlignment( fraction = 0f, alignmentViewId = R.id.firstView, focusViewId = R.id.firstView ) ) add( SubPositionAlignment( fraction = 0.5f, alignmentViewId = R.id.firstView, focusViewId = R.id.secondView ) ) add( SubPositionAlignment( fraction = 0f, alignmentViewId = R.id.secondView, focusViewId = R.id.thirdView ) ) } } override fun getSubPositionAlignments(): List { return alignments } } ``` -------------------------------- ### Configure Scrollbars Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Define scrollbar appearance and behavior using XML attributes. ```xml ``` -------------------------------- ### Perform DpadRecyclerView Actions in Espresso Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Use DpadRecyclerViewActions to perform scrolling, selection, and synchronization tasks within Espresso tests. ```kotlin @Test fun testScrolling() { // Scroll to ViewHolder matching condition Espresso.onView(withId(R.id.recyclerView)) .perform(DpadRecyclerViewActions.scrollTo( hasDescendant(withText("Target Item")) )) // Select specific position Espresso.onView(withId(R.id.recyclerView)) .perform(DpadRecyclerViewActions.selectPosition(position = 10)) // Select last position Espresso.onView(withId(R.id.recyclerView)) .perform(DpadRecyclerViewActions.selectLastPosition()) // Wait for adapter updates Espresso.onView(withId(R.id.recyclerView)) .perform(DpadRecyclerViewActions.waitForAdapterUpdate(expectedUpdates = 1)) // Wait for scroll to complete Espresso.onView(withId(R.id.recyclerView)) .perform(DpadRecyclerViewActions.waitForIdleScroll()) } ``` -------------------------------- ### Implement DpadComposeFocusViewHolder for focus-aware Composables Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/compose.md Use DpadComposeFocusViewHolder to allow Composables to manage their own focus state directly. ```kotlin class ComposeItemAdapter( private val onItemClick: (Int) -> Unit ) : ListAdapter>(Item.DIFF_CALLBACK) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): DpadComposeFocusViewHolder { return DpadComposeFocusViewHolder(parent) { item -> ItemComposable( item = item, onClick = { onItemClick(item) } ) } } override fun onBindViewHolder( holder: DpadComposeFocusViewHolder, position: Int ) { holder.setItemState(getItem(position)) } } ``` -------------------------------- ### Observe selection changes Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/getting_started.md Implement OnViewHolderSelectedListener to track selection and alignment events. ```kotlin recyclerView.addOnViewHolderSelectedListener(object : OnViewHolderSelectedListener { override fun onViewHolderSelected( parent: DpadRecyclerView, child: RecyclerView.ViewHolder?, position: Int, subPosition: Int ) {} override fun onViewHolderSelectedAndAligned( parent: DpadRecyclerView, child: RecyclerView.ViewHolder?, position: Int, subPosition: Int ) {} }) ``` -------------------------------- ### Compose Integration with DpadComposeFocusViewHolder Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Create ViewHolders that render Composables with focus handled within the Compose tree. This adapter uses DpadComposeFocusViewHolder to manage focus for Composable items. ```kotlin class ComposeItemAdapter( private val onItemClick: (Int) -> Unit ) : ListAdapter>(DiffCallback) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): DpadComposeFocusViewHolder { return DpadComposeFocusViewHolder(parent) { item -> ItemComposable( item = item, onClick = { onItemClick(item) } ) } } override fun onBindViewHolder( holder: DpadComposeFocusViewHolder, position: Int ) { holder.setItemState(getItem(position)) } } ``` ```kotlin @Composable fun ItemComposable( item: Int, onClick: () -> Unit, modifier: Modifier = Modifier ) { var isFocused by remember { mutableStateOf(false) } val backgroundColor = if (isFocused) Color.White else Color.Black val textColor = if (isFocused) Color.Black else Color.White Box( modifier = modifier .background(backgroundColor) .onFocusChanged { focusState -> isFocused = focusState.hasFocus } .focusable() .dpadClickable { onClick() }, contentAlignment = Alignment.Center ) { Text( text = item.toString(), color = textColor, fontSize = 35.sp ) } } ``` -------------------------------- ### Migrating Item Alignment from BaseGridView to DpadRecyclerView Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/migrating_leanback.md This snippet demonstrates migrating item alignment configurations from BaseGridView to DpadRecyclerView's ChildAlignment. ```kotlin recyclerView.itemAlignmentOffset = 0 recyclerView.itemAlignmentOffsetPercent = 100f recyclerView.isItemAlignmentOffsetWithPadding = true ``` ```kotlin recyclerView.setChildAlignment( ChildAlignment( offset = 0, fraction = 1f, includePadding = true ) ) ``` -------------------------------- ### Apply Grid Spacing Decoration in Kotlin Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Adds spacing between items in grid layouts with control over gaps and edges. ```kotlin // Simple grid spacing (same on all sides) recyclerView.addItemDecoration( DpadGridSpacingDecoration.create( itemSpacing = resources.getDimensionPixelOffset(R.dimen.grid_spacing) ) ) // Vertical grid with custom spacing recyclerView.addItemDecoration( DpadGridSpacingDecoration.createVertical( itemSpacing = resources.getDimensionPixelOffset(R.dimen.horizontal_spacing), perpendicularItemSpacing = resources.getDimensionPixelOffset(R.dimen.vertical_spacing), edgeSpacing = resources.getDimensionPixelOffset(R.dimen.edge_spacing) ) ) ``` -------------------------------- ### Create ComposeItemAdapter for DpadRecyclerView Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/README.MD This adapter is designed for integrating DpadRecyclerView with Jetpack Compose. It uses DpadComposeFocusViewHolder to manage item focus and rendering within a Compose environment. ```kotlin class ComposeItemAdapter( private val onItemClick: (Int) -> Unit ) : ListAdapter>(Item.DIFF_CALLBACK) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): DpadComposeFocusViewHolder { return DpadComposeFocusViewHolder(parent) { item -> ItemComposable( item = item, onClick = { onItemClick(item) } ) } } override fun onBindViewHolder( holder: DpadComposeFocusViewHolder, position: Int ) { holder.setItemState(getItem(position)) } } ``` -------------------------------- ### Configure ParentAlignment with offset Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/alignment.md Sets the parent anchor with a specific pixel offset and fraction. ```kotlin ParentAlignment(offset = 16.dp.toPx(), fraction = 0f) ``` -------------------------------- ### Implement Mutable Adapter for Drag and Drop Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/dragdrop.md Implement DpadDragHelper.DragAdapter to expose a mutable list of items. This allows DpadDragHelper to automatically reorder elements. ```kotlin class ExampleAdapter( private val adapterConfig: AdapterConfig ) : RecyclerView.Adapter(), DpadDragHelper.DragAdapter { private val items = ArrayList() override fun getMutableItems(): MutableList = items ``` -------------------------------- ### Configure Child Alignment in Kotlin Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Defines how individual child ViewHolders align to the parent's keyline position. ```kotlin // Center of child aligns to keyline recyclerView.setChildAlignment( ChildAlignment(fraction = 0.5f) ) // Start of child aligns to keyline recyclerView.setChildAlignment( ChildAlignment(fraction = 0f) ) // Include padding in alignment calculation recyclerView.setChildAlignment( ChildAlignment( fraction = 0f, includePadding = true ) ) // Combined alignment setup recyclerView.setAlignments( parentAlignment = ParentAlignment(fraction = 0.5f), childAlignment = ChildAlignment(fraction = 0.5f), smooth = true // Animate to new alignment ) ``` -------------------------------- ### Configure Focus Direction Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Define how focus navigation behaves at grid boundaries using standard, circular, or continuous modes. ```kotlin // Standard: Focus stops at edges recyclerView.setFocusableDirection(FocusableDirection.STANDARD) // Circular: Focus wraps to opposite span recyclerView.setFocusableDirection(FocusableDirection.CIRCULAR) // Continuous: Focus moves to next/previous row recyclerView.setFocusableDirection(FocusableDirection.CONTINUOUS) ``` -------------------------------- ### Make ViewHolder Focusable Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/selection.md Set a child view as focusable in XML or after onCreateViewHolder to enable DPAD navigation. ```kotlin view.isFocusable = true view.isFocusableInTouchMode = true ``` -------------------------------- ### Configure Horizontal Row Layout in XML Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/layout.md Use this XML to set up a DpadRecyclerView as a horizontal row. Ensure the orientation attribute is set to 'horizontal'. ```xml ``` -------------------------------- ### Define Extra Layout Space Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Implement a strategy to calculate additional space for off-screen items, useful for edge-aligned layouts. ```kotlin recyclerView.setExtraLayoutSpaceStrategy(object : ExtraLayoutSpaceStrategy { override fun calculateStartExtraLayoutSpace(state: RecyclerView.State): Int { return recyclerView.width / 2 // Half page at start } override fun calculateEndExtraLayoutSpace(state: RecyclerView.State): Int { return recyclerView.width / 2 // Half page at end } }) ``` -------------------------------- ### Configure Linear Row Spacing Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/spacing.md Apply spacing decorations to a horizontal linear layout. ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadLinearSpacingDecoration.create( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.horizontal_item_spacing ), edgeSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.horizontal_edge_spacing ), perpendicularEdgeSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.vertical_edge_spacing ) ) ) } ``` ```kotlin fun setupSpacing(recyclerView: DpadRecyclerView) { recyclerView.addItemDecoration( DpadLinearSpacingDecoration.create( itemSpacing = recyclerView.resources.getDimensionPixelOffset( R.dimen.vertical_item_spacing ) ) ) } ``` -------------------------------- ### Define Sub-Position Alignment in Kotlin Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Implements DpadViewHolder to define multiple focusable alignment points within a single ViewHolder. ```kotlin class DetailViewHolder(view: View) : RecyclerView.ViewHolder(view), DpadViewHolder { private val alignments = listOf( SubPositionAlignment( fraction = 0f, alignmentViewId = R.id.headerView, focusViewId = R.id.headerView ), SubPositionAlignment( fraction = 0.5f, alignmentViewId = R.id.headerView, focusViewId = R.id.descriptionView ), SubPositionAlignment( fraction = 0f, alignmentViewId = R.id.descriptionView, focusViewId = R.id.actionButton ) ) override fun getSubPositionAlignments(): List = alignments } // Navigate sub-positions programmatically recyclerView.setSelectedSubPosition(subPosition = 1) recyclerView.setSelectedSubPositionSmooth(position = 0, subPosition = 2) ``` -------------------------------- ### Add DpadRecyclerView Dependency Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/README.MD Include the DpadRecyclerView library in your app's build.gradle file. The compose and testing artifacts are optional. ```groovy implementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview:$latestVersion" // Recommended: To use Compose together with DpadRecyclerView implementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-compose:$latestVersion" // Optional: Espresso test helpers for your instrumented tests: androidTestImplementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-testing:$latestVersion" ``` -------------------------------- ### Page-by-Page Scrolling with DpadScroller Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Enable page-by-page scrolling for long text content. Attach DpadScroller to your DpadRecyclerView and optionally enable smooth scrolling. ```kotlin val scroller = DpadScroller() scroller.attach(dpadRecyclerView) // Enable smooth scrolling scroller.setSmoothScrollEnabled(true) // Detach when done scroller.detach() ``` -------------------------------- ### Style DpadRecyclerView with Themes Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Apply global styles or reusable component styles to DpadRecyclerView instances using Android themes. ```xml ``` -------------------------------- ### Configure ParentAlignment for vertical centering Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/alignment.md Sets the parent anchor to the center of the container using a fraction. ```kotlin ParentAlignment(fraction = 0.5f) ``` -------------------------------- ### Apply Linear Spacing Decoration in Kotlin Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Adds consistent spacing between items in linear row or column layouts. ```kotlin // Simple even spacing recyclerView.addItemDecoration( DpadLinearSpacingDecoration.create( itemSpacing = resources.getDimensionPixelOffset(R.dimen.item_spacing) ) ) // Full configuration with edge spacing recyclerView.addItemDecoration( DpadLinearSpacingDecoration.create( itemSpacing = resources.getDimensionPixelOffset(R.dimen.item_spacing), edgeSpacing = resources.getDimensionPixelOffset(R.dimen.edge_spacing), perpendicularEdgeSpacing = resources.getDimensionPixelOffset(R.dimen.perpendicular_spacing) ) ) ``` -------------------------------- ### Configure Center Alignment Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/alignment.md Sets the parent and child alignment fractions to 0.5 to center items in the view. ```xml ``` ```kotlin recyclerView.setParentAlignment( ParentAlignment(fraction = 0.5f) ) recyclerView.setChildAlignment( ChildAlignment(fraction = 0.5f) ) ``` -------------------------------- ### Enable Drag and Drop with DPAD Controls Source: https://context7.com/rubensousa/dpadrecyclerview/llms.txt Implement drag and drop functionality for RecyclerView items using DPAD controls. Requires making your adapter implement DpadDragHelper.DragAdapter and attaching a DpadDragHelper instance to your RecyclerView. ```kotlin class DraggableAdapter : RecyclerView.Adapter(), DpadDragHelper.DragAdapter { private val items = mutableListOf() override fun getMutableItems(): MutableList = items // ... standard adapter methods } ``` ```kotlin val dragHelper = DpadDragHelper( adapter = draggableAdapter, callback = object : DpadDragHelper.DragCallback { override fun onDragStarted(viewHolder: RecyclerView.ViewHolder) { viewHolder.itemView.alpha = 0.7f } override fun onDragStopped(fromUser: Boolean) { // Save new order } } ) dragHelper.attachToRecyclerView(recyclerView) // Start dragging programmatically dragHelper.startDrag(position = selectedPosition) // Stop dragging dragHelper.stopDrag() ``` -------------------------------- ### Define Focus Attributes Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/xml.md Attributes for managing focus navigation behavior and smooth transitions. ```xml ``` -------------------------------- ### Configure combined Parent and Child alignment Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/alignment.md Sets both parent and child anchor positions for horizontal alignment. ```kotlin ParentAlignment(offset = 24.dp.toPx(), fraction = 0f) ChildAlignment(fraction = 0f) ``` -------------------------------- ### Observe Focus Changes in DpadRecyclerView Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/selection.md Implement OnViewFocusedListener to observe focus changes within the DpadRecyclerView. ```kotlin recyclerView.addOnViewFocusedListener(object : OnViewFocusedListener { override fun onViewFocused(parent: RecyclerView.ViewHolder, child: View) { // Child has focus } }) ``` -------------------------------- ### Supported Layout Attributes Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/xml.md Standard ViewGroup attributes supported by DpadRecyclerView. ```xml ``` -------------------------------- ### React to focus changes in a Composable Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/compose.md Use standard focus APIs like onFocusChanged and focusable to handle focus state within a Composable. ```kotlin @Composable fun ItemComposable( item: Int, onClick: () -> Unit, modifier: Modifier = Modifier, ) { var isFocused by remember { mutableStateOf(false) } val backgroundColor = if (isFocused) Color.White else Color.Black val textColor = if (isFocused) Color.Black else Color.White Box( modifier = modifier .background(backgroundColor) .onFocusChanged { focusState -> isFocused = focusState.hasFocus } .focusable() .dpadClickable { onClick() }, contentAlignment = Alignment.Center, ) { Text( text = item.toString(), color = textColor, fontSize = 35.sp ) } } ``` -------------------------------- ### Include Padding in Child Alignment Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/alignment.md Enables padding consideration for alignment when the fraction is 0f or 1f. ```kotlin recyclerView.setChildAlignment( ChildAlignment(fraction = 0f, includePadding = true) ) ``` -------------------------------- ### Observe focus changes Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/getting_started.md Use OnViewFocusedListener to react when a view gains focus. ```kotlin recyclerView.addOnViewFocusedListener(object : OnViewFocusedListener { override fun onViewFocused( parent: RecyclerView.ViewHolder, child: View, ) { // Child is now focused } }) ``` -------------------------------- ### Observe Focus Changes with OnFocusChangeListener Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/selection.md Use OnFocusChangeListener on a view to react to focus gain or loss. ```kotlin view.setOnFocusChangeListener { _, hasFocus -> if (hasFocus) { // React to focus gain } else { // React to focus loss } } ``` -------------------------------- ### Define Alignment Attributes Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/xml.md Attributes for configuring child and parent alignment within the DpadRecyclerView. ```xml ``` -------------------------------- ### Configure Edge Alignment Preference Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/alignment.md Sets the edge preference to NONE to ensure items remain aligned to the keyline at list boundaries. ```xml app:dpadRecyclerViewParentAlignmentEdge="none" /> ``` ```kotlin recyclerView.setParentAlignment( ParentAlignment( fraction = 0f, offset = 24.dp.toPx() edge = ParentAlignment.Edge.NONE ) ) ``` -------------------------------- ### Scroll to Specific Position with Callback Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/recipes/scrolling.md Use `setSelectedPosition` to scroll immediately to a given position and execute a callback once the ViewHolder is selected and aligned. ```kotlin recyclerView.setSelectedPosition(0, object : ViewHolderTask() { override fun execute(viewHolder: RecyclerView.ViewHolder) { // ViewHolder was selected and aligned to its final location } }) ``` -------------------------------- ### Define Spacing Attributes Source: https://github.com/rubensousa/dpadrecyclerview/blob/master/docs/xml.md Attributes for controlling item spacing and edge spacing configurations. ```xml ```