@@ -4,6 +4,8 @@ package com.getcode.ui.utils
44import androidx.compose.animation.AnimatedVisibility
55import androidx.compose.animation.EnterTransition
66import androidx.compose.animation.ExitTransition
7+ import androidx.compose.foundation.gestures.animateScrollBy
8+ import androidx.compose.foundation.gestures.scrollBy
79import androidx.compose.foundation.lazy.LazyItemScope
810import androidx.compose.foundation.lazy.LazyListScope
911import androidx.compose.foundation.lazy.LazyListState
@@ -41,4 +43,98 @@ fun LazyListState.isScrolledToTheEnd() =
4143 layoutInfo.visibleItemsInfo.lastOrNull()?.index == layoutInfo.totalItemsCount - 1
4244
4345fun LazyListState.isScrolledToTheBeginning () =
44- (layoutInfo.visibleItemsInfo.firstOrNull()?.index ? : 0 ) == 0
46+ (layoutInfo.visibleItemsInfo.firstOrNull()?.index ? : 0 ) == 0
47+
48+ suspend fun LazyListState.scrollToItemWithFullVisibility (index : Int ) {
49+ // 1️⃣ Scroll to the item initially
50+ scrollToItem(index)
51+
52+ // 2️⃣ Fetch updated layout info
53+ val layoutInfo = layoutInfo
54+ val itemInfo = layoutInfo.visibleItemsInfo.find { it.index == index }
55+
56+ if (itemInfo != null ) {
57+ val viewportStart = layoutInfo.viewportStartOffset
58+ val viewportEnd = layoutInfo.viewportEndOffset
59+
60+ val itemStart = itemInfo.offset
61+ val itemEnd = itemInfo.offset + itemInfo.size
62+
63+ println (
64+ " ItemStart: $itemStart , ItemEnd: $itemEnd , ViewportStart: $viewportStart , ViewportEnd: $viewportEnd "
65+ )
66+
67+ // 3️⃣ Determine if the item is partially clipped upwards
68+ if (itemStart < viewportStart) {
69+ val scrollAmount = (viewportStart - itemStart).coerceAtLeast(0 )
70+ println (" Item is clipped upwards, scrolling upwards by $scrollAmount " )
71+ scrollBy(- scrollAmount.toFloat()) // Scroll upwards
72+ }
73+
74+ // 4️⃣ Determine if the item is partially clipped downwards
75+ if (itemEnd > viewportEnd) {
76+ val scrollAmount = (itemEnd - viewportEnd).coerceAtLeast(0 )
77+ println (" Item is clipped downwards, scrolling downwards by $scrollAmount " )
78+ scrollBy(scrollAmount.toFloat()) // Scroll downwards
79+ }
80+
81+ // 5️⃣ If the item is still misaligned, enforce alignment manually
82+ val fullyVisible = itemStart >= viewportStart && itemEnd <= viewportEnd
83+ if (! fullyVisible) {
84+ println (" Item is still misaligned, performing final alignment" )
85+ scrollToItem(index, scrollOffset = 0 )
86+ }
87+ } else {
88+ // 6️⃣ Fallback alignment
89+ println (" Item not found in visibleItemsInfo, performing fallback alignment" )
90+ scrollToItem(index, scrollOffset = 0 )
91+ }
92+ }
93+
94+ suspend fun LazyListState.animateScrollToItemWithFullVisibility (to : Int , from : Int ) {
95+ println (" 🔄 Ensuring full visibility for index: $to " )
96+
97+ val firstIndex = firstVisibleItemIndex
98+ val firstOffset = firstVisibleItemScrollOffset
99+
100+ println (" 📊 FirstVisibleItemIndex: $firstIndex , FirstVisibleItemScrollOffset: $firstOffset " )
101+
102+ val layoutInfo = layoutInfo
103+ val itemInfo = layoutInfo.visibleItemsInfo.find { it.index == to }
104+
105+ // Estimate item height if dynamic size is not available
106+ val averageItemHeight = itemInfo?.size ? : 200 // Default to 200px if not found
107+
108+ // Calculate the true item offset based on reverseLayout
109+ val indexDifference = to - firstIndex
110+ val estimatedItemStart = firstOffset
111+
112+ println (
113+ " 📐 Calculated EstimatedItemStart: $estimatedItemStart (IndexDifference: $indexDifference , AverageItemHeight: $averageItemHeight )"
114+ )
115+
116+ val viewportStart = layoutInfo.viewportStartOffset
117+ val viewportEnd = layoutInfo.viewportEndOffset
118+
119+ println (" ViewportStart: $viewportStart , ViewportEnd: $viewportEnd " )
120+
121+ // Determine if adjustment is needed
122+ val scrollOffset = when {
123+ estimatedItemStart > viewportEnd -> {
124+ println (" 🔼 Item is clipped at the bottom in reverse layout, adjusting by ${estimatedItemStart - viewportEnd} " )
125+ estimatedItemStart - viewportEnd // Scroll upwards in reverse
126+ }
127+ estimatedItemStart < viewportStart -> {
128+ println (" 🔽 Item is clipped at the top in reverse layout, adjusting by ${viewportStart - estimatedItemStart} " )
129+ viewportStart - estimatedItemStart // Scroll downwards in reverse
130+ }
131+ else -> {
132+ println (" ✅ Item is fully visible in reverse layout, no adjustment needed." )
133+ 0
134+ }
135+ }
136+
137+ // Perform the final scroll adjustment
138+ println (" 🎯 Performing final scroll with offset: $scrollOffset " )
139+ animateScrollToItem(to, scrollOffset = scrollOffset)
140+ }
0 commit comments