Accompagnist.kt (2395B) - raw


      1 package me.rhunk.snapenhance.ui.util
      2 
      3 import androidx.compose.foundation.ExperimentalFoundationApi
      4 import androidx.compose.foundation.pager.PagerState
      5 import androidx.compose.material3.TabPosition
      6 import androidx.compose.ui.Modifier
      7 import androidx.compose.ui.layout.layout
      8 import androidx.compose.ui.unit.Constraints
      9 import androidx.compose.ui.unit.lerp
     10 
     11 //https://github.com/google/accompanist/blob/main/pager-indicators/src/main/java/com/google/accompanist/pager/PagerTab.kt#L78
     12 @OptIn(ExperimentalFoundationApi::class)
     13 fun Modifier.pagerTabIndicatorOffset(
     14     pagerState: PagerState,
     15     tabPositions: List<TabPosition>,
     16     pageIndexMapping: (Int) -> Int = { it },
     17 ): Modifier = layout { measurable, constraints ->
     18     if (tabPositions.isEmpty()) {
     19         // If there are no pages, nothing to show
     20         layout(constraints.maxWidth, 0) {}
     21     } else {
     22         val currentPage = minOf(tabPositions.lastIndex, pageIndexMapping(pagerState.currentPage))
     23         val currentTab = tabPositions[currentPage]
     24         val previousTab = tabPositions.getOrNull(currentPage - 1)
     25         val nextTab = tabPositions.getOrNull(currentPage + 1)
     26         val fraction = pagerState.currentPageOffsetFraction
     27         val indicatorWidth = if (fraction > 0 && nextTab != null) {
     28             lerp(currentTab.width, nextTab.width, fraction).roundToPx()
     29         } else if (fraction < 0 && previousTab != null) {
     30             lerp(currentTab.width, previousTab.width, -fraction).roundToPx()
     31         } else {
     32             currentTab.width.roundToPx()
     33         }
     34         val indicatorOffset = if (fraction > 0 && nextTab != null) {
     35             lerp(currentTab.left, nextTab.left, fraction).roundToPx()
     36         } else if (fraction < 0 && previousTab != null) {
     37             lerp(currentTab.left, previousTab.left, -fraction).roundToPx()
     38         } else {
     39             currentTab.left.roundToPx()
     40         }
     41         val placeable = measurable.measure(
     42             Constraints(
     43                 minWidth = indicatorWidth,
     44                 maxWidth = indicatorWidth,
     45                 minHeight = 0,
     46                 maxHeight = constraints.maxHeight
     47             )
     48         )
     49         layout(constraints.maxWidth, maxOf(placeable.height, constraints.minHeight)) {
     50             placeable.placeRelative(
     51                 indicatorOffset,
     52                 maxOf(constraints.minHeight - placeable.height, 0)
     53             )
     54         }
     55     }
     56 }