Android NDK开发详解Wear之滑动关闭

Android NDK开发详解Wear之滑动关闭


滑动关闭动画用于表现在用户转到上一页时的过渡。
SwipeToDismissBox


fun SwipeToDismissBox(
    state: SwipeToDismissBoxState,
    modifier: Modifier = Modifier,
    backgroundScrimColor: Color = MaterialTheme.colors.background,
    contentScrimColor: Color = MaterialTheme.colors.background,
    backgroundKey: Any = SwipeToDismissKeys.Background,
    contentKey: Any = SwipeToDismissKeys.Content,
    hasBackground: Boolean = true,
    content:  BoxScope.(isBackground: Boolean) -> Unit
): Unit

This function is deprecated.
This overload is provided for backwards compatibility. A newer overload is available that uses androidx.wear.compose.foundation.SwipeToDismissBoxState.
Wear Material SwipeToDismissBox that handles the swipe-to-dismiss gesture. Takes a single slot for the background (only displayed during the swipe gesture) and the foreground content.

Example of a SwipeToDismissBox with stateful composables:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.Icon
import androidx.wear.compose.material.SplitToggleChip
import androidx.wear.compose.material.SwipeToDismissBox
import androidx.wear.compose.material.Text

// State for managing a 2-level navigation hierarchy between
// MainScreen and ItemScreen composables.
// Alternatively, use SwipeDismissableNavHost from wear.compose.navigation.
var showMainScreen by remember {
    
     mutableStateOf(true) }
val saveableStateHolder = rememberSaveableStateHolder()

// Swipe gesture dismisses ItemScreen to return to MainScreen.
val state = rememberSwipeToDismissBoxState()
LaunchedEffect(state.currentValue) {
    
    
    if (state.currentValue == SwipeToDismissValue.Dismissed) {
    
    
        state.snapTo(SwipeToDismissValue.Default)
        showMainScreen = !showMainScreen
    }
}

// Hierarchy is ListScreen -> ItemScreen, so we show ListScreen as the background behind
// the ItemScreen, otherwise there's no background to show.
SwipeToDismissBox(
    state = state,
    hasBackground = !showMainScreen,
    backgroundKey = if (!showMainScreen) "MainKey" else "Background",
    contentKey = if (showMainScreen) "MainKey" else "ItemKey",
) {
    
     isBackground ->

    if (isBackground || showMainScreen) {
    
    
        // Best practice would be to use State Hoisting and leave this composable stateless.
        // Here, we want to support MainScreen being shown from different destinations
        // (either in the foreground or in the background during swiping) - that can be achieved
        // using SaveableStateHolder and rememberSaveable as shown below.
        saveableStateHolder.SaveableStateProvider(
            key = "MainKey",
            content = {
    
    
                // Composable that maintains its own state
                // and can be shown in foreground or background.
                val checked = rememberSaveable {
    
     mutableStateOf(true) }
                Column(
                    modifier = Modifier
                        .fillMaxSize().padding(horizontal = 8.dp, vertical = 8.dp),
                    verticalArrangement =
                    Arrangement.spacedBy(4.dp, Alignment.CenterVertically),
                ) {
    
    
                    SplitToggleChip(
                        checked = checked.value,
                        label = {
    
     Text("Item details") },
                        modifier = Modifier.height(40.dp),
                        onCheckedChange = {
    
     v -> checked.value = v },
                        onClick = {
    
     showMainScreen = false },
                        toggleControl = {
    
    
                            Icon(
                                imageVector = ToggleChipDefaults.checkboxIcon(
                                    checked = checked.value
                                ),
                                contentDescription = null,
                            )
                        }
                    )
                }
            }
        )
    } else {
    
    
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
    
    
            Text("Show details here...", color = MaterialTheme.colors.onPrimary)
            Text("Swipe right to dismiss", color = MaterialTheme.colors.onPrimary)
        }
    }
}

滑动关闭的动画详情与 RSB 按下类似。手指最多可控制 50% 的动画进度。

应用视图上还有一个与关闭手势关联的动画。应用视图上显示的移动量与手指需要移动的距离并不完全相同。应用视图绝不应离开屏幕边缘,显示带有一些阻力的类似挤压的效果。

实现

Wear 有自己的 Box 版本,即 SwipeToDismissBox。这增加了对滑动关闭手势(与移动设备上的返回按钮类似)的支持。

SwipeToDismissBox 是一个可以通过向右滑动来关闭的可组合项。

如需使用 SwipeToDismissBox,您必须先创建一个状态。该状态包含滑动方向、动画是否正在运行、当前值和目标等信息。以下示例展示了如何设计一个简单的滑动关闭操作:

val state = rememberSwipeToDismissBoxState()
SwipeToDismissBox(
    onDismissed = {
    
     /* navigateBack */ },
) {
    
     isBackground ->
    if (isBackground) {
    
    
        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
    } else {
    
    
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
    
    
            Text("Swipe to dismiss", color = MaterialTheme.colors.onPrimary)
        }
    }
}

如需详细了解如何将 SwipeToDismissBox 与 Navigation 库结合使用,请参阅 Wear Compose Navigation 库的参考文档。

设计

在设计滑动关闭操作时,请牢记以下两条原则:

屏幕边缘

应考虑到可滑动的其他界面元素,例如分页的应用视图。如果可以滑动关闭,请预留 20% 的屏幕边缘,用于触发该动作。

如需查看内容可水平滚动时的边缘滑动示例,请参阅此示例。

决定是返回还是留在应用视图的阈值

如果用户手指拖动超过屏幕宽度的 50%,应用应触发剩余的滑动返回动画。如果不到此阈值,应用应迅速恢复完整的应用视图。

如果手势速度很快,请忽略 50% 阈值规则并滑动返回。

本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。

最后更新时间 (UTC):2022-09-07。

猜你喜欢

转载自blog.csdn.net/hnjzfwy/article/details/134867237