元素

Modal

modal 在应用其余内容之上、在它自己的原生窗口层中呈现内容:iOS 和 Mac Catalyst 上是一个被 present 的 view controller,Android 上是一个 Dialog。它用于全屏流程、sheet 和对话框。系统自带的手势(下滑关闭 sheet、Android 返回键)都能正常工作,并在原生侧决定。

import { signal, Text, View } from "nsh";
import { Button, Modal, SafeAreaView } from "nsh/ui/mobile";

function Example() {
  const open = signal(false);
  return (
    <View style={{ flex: 1, justifyContent: "center", padding: 24 }}>
      <Button title="Open" onPress={() => open.set(true)} />
      <Modal visible={open()} ios={{ presentationStyle: "pageSheet" }} onRequestClose={() => open.set(false)}>
        <SafeAreaView style={{ flex: 1, padding: 20, gap: 12, backgroundColor: "#ffffff" }}>
          <Text style={{ fontSize: 24, fontWeight: "700" }}>A sheet</Text>
          <Button title="Close" onPress={() => open.set(false)} />
        </SafeAreaView>
      </Modal>
    </View>
  );
}

Modal 从 nsh/ui/mobile 导入。visible 不为 false 时呈现,变为 false 时关闭;它还会给内容提供 modal 的安全区域 inset,供其内部的 SafeAreaView 和 useSafeAreaInsets() 读取。

#属性

属性类型默认值说明
visiblebooleantrue为 true 时呈现。
animationType"slide" | "fade" | "none""slide"modal 的出现方式。
transparentbooleanfalse背景透出下面的内容(用于应用自己绘制的对话框)。
dismissiblebooleanfalse用户可在原生侧直接关闭(iOS 下滑 sheet、Android 返回键),随后触发 onRequestClose 和 onDismiss。不设置时,这些手势只是请求关闭。
onRequestClose() => void用户请求关闭:把 visible 设为 false 即可关闭。
onShow() => voidmodal 已完全出现。
onDismiss() => voidmodal 已完全消失。
styleStyleProp<ViewStyle>modal 的根视图样式。
childrenJSX.Element内容。
ios 键类型默认值说明
presentationStyle"fullScreen" | "pageSheet" | "formSheet""fullScreen"pageSheet 和 formSheet 会让下面的内容保持可见;在大屏上 formSheet 是一个更小的居中 sheet。
supportedOrientations("portrait" | "portrait-upside-down" | "landscape" | "landscape-left" | "landscape-right")[]与呈现者相同modal 允许的方向。
android 键类型默认值说明
statusBarTranslucentbooleanfalse内容延伸到状态栏下方;否则从状态栏下方开始。

#默认是受控的

modal 是受控的:用户下滑 sheet 或按返回键时,nsh 通过 onRequestClose 询问,modal 会一直保留,直到你把 visible 设为 false。这样你可以在关闭前先确认。由于主线程从不等待 JS,这个决定无法在事件处理函数里做出;dismissible 是事先告诉平台它可以自行关闭 modal:

<Modal visible={open()} dismissible ios={{ presentationStyle: "pageSheet" }} onRequestClose={() => open.set(false)}>
  …
</Modal>

设置 dismissible 后,sheet 会跟随手指并在原生侧关闭;之后 onRequestClose 通知你更新状态。

#对话框

一个透明、淡入的 modal 可以在变暗的背景上绘制自己的对话框:

<Modal visible={confirm()} transparent animationType="fade" onRequestClose={() => confirm.set(false)}>
  <View style={{ flex: 1, backgroundColor: "rgba(0,0,0,0.4)", alignItems: "center", justifyContent: "center", padding: 32 }}>
    <View style={{ alignSelf: "stretch", backgroundColor: "#ffffff", borderRadius: 14, padding: 20, gap: 12 }}>
      <Text style={{ fontSize: 20, fontWeight: "700" }}>Delete this item?</Text>
      <Button title="Delete" onPress={remove} />
    </View>
  </View>
</Modal>

如果需要系统提示框或操作表,请改用 nsh/ui/mobile 的 Alert 和 ActionSheet(alert、action sheet)。应用自绘的 sheet 见 Sheet。

#Ref 方法

无。

#平台说明

  • Android:返回键首先交给最上层的 modal,然后才是导航栈和 BackHandler 监听器。
  • presentationStyle 和 supportedOrientations 仅适用于 iOS,在 Android 上会被忽略。
  • 未设置 statusBarTranslucent 时,Android modal 的内容从状态栏下方开始。