0

I'm trying to custom a Lazy Column to show it like a Wheel of numbers. Depending how far is the item from center I apply opacity, size and rotation to it. When I only apply the opacity, there is no problem, but if I add the size for example, the Lazy Column, when I dragg it, it lags a little bit.

This is the code:

@Composable
fun WheelPicker(
  items: List<Any> = (1..100).toList(),
  visibleItems: Int = 5,
  itemHeight: Dp = 20.dp 
) {

  val columnHeight = itemHeight*visibleItems
  val columnWidth = getMinWidthForList(items)
  val paddingValues = ((visibleItems/2) * itemHeight.value).dp

  var selection by remember { mutableStateOf(items.first()) }
  val scope = rememberCoroutineScope()
  val lazyListState = rememberLazyListState()

  val offsetViewport = with(LocalDensity.current) { itemHeight.toPx() }
  val offsetToDown = offsetViewport * 0.35
  val offsetToUp = offsetViewport - (offsetViewport * 0.35)

  Box(
      modifier = Modifier
          .fillMaxSize(),
      contentAlignment = Alignment.Center
  ) {
      Box(
        modifier = Modifier
            .fillMaxWidth(0.6f)
            .height(20.dp)
            .clip(RoundedCornerShape(5.dp))
            .background(Color.LightGray)
      )
      BoxWithConstraints(
        modifier = Modifier
            .width(columnWidth)
            .height(columnHeight),
        contentAlignment = Alignment.Center
      ) {
          LazyColumn(
            state = lazyListState,
            horizontalAlignment = Alignment.CenterHorizontally,
            contentPadding = PaddingValues(top = paddingValues, bottom = paddingValues),
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight()
          ) {
              itemsIndexed(items) { index, item ->

                val opacity by remember {
                    derivedStateOf {
                        val currentItemInfo = lazyListState.layoutInfo.visibleItemsInfo
                            .firstOrNull { it.index == index }
                            ?: return@derivedStateOf 0.2f
                        val offsetLimit = lazyListState.layoutInfo.viewportEndOffset
                        (1 - abs(currentItemInfo.offset).toFloat()/offsetLimit)
                    }
                }
                val rotation by remember {
                    derivedStateOf {
                        val currentItemInfo = lazyListState.layoutInfo.visibleItemsInfo
                            .firstOrNull { it.index == index }
                            ?: return@derivedStateOf 0.2f
                        val offsetLimit = lazyListState.layoutInfo.viewportEndOffset
                        (0f + (abs(currentItemInfo.offset).toFloat()/offsetLimit)*90f)
                    }
                }
                val size by remember {
                    derivedStateOf {
                        val currentItemInfo = lazyListState.layoutInfo.visibleItemsInfo
                            .firstOrNull { it.index == index }
                            ?: return@derivedStateOf 0.2f
                        val offsetLimit = lazyListState.layoutInfo.viewportEndOffset
                        (20 - (abs(currentItemInfo.offset).toFloat()/offsetLimit)*10)
                    }
                }

                Text(
                    text = item.toString(),
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(size.dp)
                        .clickable {
                            scope.launch { lazyListState.animateScrollToItem(index) }
                        }
                        .alpha(opacity)
                        .graphicsLayer {
                            rotationX = rotation
                        },
                    textAlign = TextAlign.End
                )
              }
        }
    }
}

  LaunchedEffect(lazyListState.isScrollInProgress) {
      if (!lazyListState.isScrollInProgress) {
          if (lazyListState.firstVisibleItemScrollOffset > offsetToDown) {
              lazyListState.scrollToItem(lazyListState.firstVisibleItemIndex+1)
          }
          if (lazyListState.firstVisibleItemScrollOffset < offsetToUp) {
              lazyListState.scrollToItem(lazyListState.firstVisibleItemIndex)
          }
          selection = items[lazyListState.firstVisibleItemIndex]
      }
  }
}

Maybe the 3 variables to calculate opacity, size and rotation are causing this behavior?

My other question is, is better to make this with a custom layout? or is this approach good?

0 Answers0