简体   繁体   中英

How can I scroll over sections in Jetpack Compose?

PROBLEM:

I have a screen with one column full of (too many) text fields which could be packed into categories - to make it easier for the user to see what he is working with.


My Idea is that I could make a form of tabs that the text fields will be put into, then only the tab that the user is currently working on is open and the others are closed but visible.

I would like to make it something like a vertical View Pager but where you can see all the elements to scroll over.

To change the view you would either scroll or click the category to access.

Only one tab will always be open.

在此处输入图片说明

QUESTION:

However I don't know, what this is called or how to do this in Jetpack Compose - So I want to ask if someone can point me in the right direction.

You can store selected item index with rememberSaveable , and then you can use AnimatedVisibility to animate opened view. To add swipes I've created Modifier.swipeableTopBottom , see more details about how it works in this answer .

var selectedItem by rememberSaveable { mutableStateOf(0) }
val itemsCount = 10
Column(
    verticalArrangement = Arrangement.spacedBy(10.dp),
    modifier = Modifier
        .padding(10.dp)
        .swipeableTopBottom(
            onTop = {
                selectedItem = (selectedItem - 1).coerceIn(0, itemsCount)
            },
            onBottom = {
                selectedItem = (selectedItem + 1).coerceIn(0, itemsCount)
            },
        )
) {
    repeat(itemsCount) { i ->
        Column(
            Modifier
                .clickable {
                    selectedItem = i
                }
                .fillMaxWidth()
                .background(Color.DarkGray)
                .padding(10.dp)
        ) {
            Text("Title $i")
            AnimatedVisibility(visible = i == selectedItem) {
                Column {
                    repeat(5) { j ->
                        Text("Subtitle $i $j")
                    }
                }
            }
        }
    }
}

Modifier.swipeableTopBottom :

fun Modifier.swipeableTopBottom(onTop: () -> Unit, onBottom: () -> Unit): Modifier = composed {
    var width by rememberSaveable { mutableStateOf(0f) }
    val swipeableState = rememberSwipeableState(
        SwipeDirection.Initial,
        animationSpec = snap()
    )
    val anchorWidth = remember(width) {
        if (width == 0f) {
            1f
        } else {
            width
        }
    }
    val scope = rememberCoroutineScope()
    if (swipeableState.isAnimationRunning) {
        DisposableEffect(Unit) {
            onDispose {
                when (swipeableState.currentValue) {
                    SwipeDirection.Top -> {
                        onTop()
                    }
                    SwipeDirection.Bottom -> {
                        onBottom()
                    }
                    else -> {
                        return@onDispose
                    }
                }
                scope.launch {
                    swipeableState.snapTo(SwipeDirection.Initial)
                }
            }
        }
    }
    return@composed Modifier
        .onSizeChanged { width = it.width.toFloat() }
        .swipeable(
            state = swipeableState,
            anchors = mapOf(
                0f to SwipeDirection.Top,
                anchorWidth / 2 to SwipeDirection.Initial,
                anchorWidth to SwipeDirection.Bottom,
            ),
            thresholds = { _, _ -> FractionalThreshold(0.3f) },
            orientation = Orientation.Vertical
        )
}

private enum class SwipeDirection(val raw: Int) {
    Top(0),
    Initial(1),
    Bottom(2),
}

Result:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM