使用Jetpack Compose ModalBottomSheet:在初始化之前读取偏移量

Sag*_*tus 12 android kotlin android-jetpack-compose

我正在使用ModalBottomSheet并且必须State hoisting使用它的祖先组件。

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      Demo4Theme {
        // A surface container using the 'background' color from the theme
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
          ArticleScreen()
        }
      }
    }
  }
}
@Stable
class ArticleState(
  val orderModalState: SageSheetState,
  val filterModalState: DrawerState
)

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun rememberSageSheetState(
  state: SageSheetState = SageSheetState(
    coroutineScope = rememberCoroutineScope(), sheetState = rememberSheetState()
  )): SageSheetState {
  return remember { state }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun rememberArticleState(
  orderModalState: SageSheetState = rememberSageSheetState(),
  filterModalState: DrawerState = rememberDrawerState(DrawerValue.Closed)
): ArticleState {

  return remember {
    ArticleState(
      orderModalState = orderModalState,
      filterModalState = filterModalState
    )
  }
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ArticleScreen(
  state: ArticleState = rememberArticleState()
) {

  Column {
    Text("${state.orderModalState.sheetState.currentValue}")
    Text("${state.orderModalState.sheetState.isVisible}")
    Text("${state.orderModalState.sheetState.targetValue}")
    Button(onClick = { state.orderModalState.showModal() }) {
      Text("Show Modal")
    }
  }
  Modal(
    modalState = state.orderModalState,
  )
}

@OptIn(ExperimentalMaterial3Api::class)
class SageSheetState(
  private val coroutineScope: CoroutineScope,
  val sheetState: SheetState,
  openBottomSheet: Boolean = false
) {
  var openBottomSheet by mutableStateOf(openBottomSheet)

  fun showModal() {
    coroutineScope.launch {
      openBottomSheet = true
      sheetState.collapse()
    }
  }

  fun closeModal() {
    coroutineScope.launch {
      sheetState.hide()
      openBottomSheet = false
    }
  }
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Modal(
  modalState: SageSheetState
) {

// Sheet content
  if (modalState.openBottomSheet) {
    ModalBottomSheet(
      onDismissRequest = { modalState.closeModal() },
      sheetState = modalState.sheetState,
    ) {
      Text("Hello")
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但是当我点击按钮时Show Modal,就出错了。

The offset was read before being initialized. Did you access the offset in a phase before layout, like effects or composition?
Run Code Online (Sandbox Code Playgroud)

我不知道我哪里做错了,也许使用State hoisting方式错误,官方示例工作正常(状态保存本身)。

您可以在此处查看完整的代码以及在此处查看完整的错误消息。

注意
  1. 我正在使用最新版本的 Compose Material3androidx.compose.material3:material3:1.1.0-alpha06
  2. 如果要运行该项目,您可能需要修改存储库设置。

小智 1

您可以使用 DisposableEffect 来确保仅在布局阶段之后调用 showModal 和 closeModal 函数。

@OptIn(ExperimentalMaterial3Api::class)
class SageSheetState(
    private val coroutineScope: CoroutineScope,
    val sheetState: SheetState,
    openBottomSheet: Boolean = false
) {
    var openBottomSheet by mutableStateOf(openBottomSheet)
        private set

    fun showModal() {
        coroutineScope.launch {
            openBottomSheet = true
            sheetState.collapse()
        }
    }

    fun closeModal() {
        coroutineScope.launch {
            sheetState.hide()
            openBottomSheet = false
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Modal(
    modalState: SageSheetState
) {
    DisposableEffect(modalState.openBottomSheet) {
        onDispose { }
    }

    // Sheet content
    if (modalState.openBottomSheet) {
        ModalBottomSheet(
            onDismissRequest = { modalState.closeModal() },
            sheetState = modalState.sheetState,
        ) {
            Text("Hello")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)