ProComponents, templates & AI tooling
2.3k

Popover 弹出框更新

锚定在触发器上的浮动内容面板,支持方位与对齐选项。

导入

import { Popover } from 'heroui-native';

结构

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content>
      <Popover.Arrow />
      <Popover.Close />
      <Popover.Title>...</Popover.Title>
      <Popover.Description>...</Popover.Description>
    </Popover.Content>
  </Popover.Portal>
</Popover>
  • Popover:根容器,管理展开/收起、定位,并为子组件提供上下文。
  • Popover.Trigger:可点击的触发器,切换浮层可见性;为子元素包裹按压处理。
  • Popover.Portal:在Portal层渲染内容,保证层级与定位正确。
  • Popover.Overlay:可选背景遮罩;可透明或半透明,用于捕获外部点击。
  • Popover.Content:内容容器,含定位、样式与碰撞检测;支持 popover 与底部抽屉呈现。
  • Popover.Arrow:可选箭头,指向触发器;随 placement 自动定位。
  • Popover.Close:关闭按钮;可自定义子节点,默认关闭图标。
  • Popover.Title:可选标题,使用预设排版。
  • Popover.Description:可选说明文字,弱化样式。

用法

基础用法

通过组合子部件创建浮动内容面板。

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover">...</Popover.Content>
  </Popover.Portal>
</Popover>

标题与说明

使用标题与说明组织内容层级。

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover">
      <Popover.Close />
      <Popover.Title>...</Popover.Title>
      <Popover.Description>...</Popover.Description>
    </Popover.Content>
  </Popover.Portal>
</Popover>

带箭头

添加指向触发器的箭头以增强视觉关联。

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover" placement="top">
      <Popover.Arrow />
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>

说明: 使用 <Popover.Arrow /> 时,需要为 Popover.Content 添加边框,例如 border border-border,以便箭头与内容边框视觉衔接。

宽度控制

通过 width 控制浮层内容宽度。

{
  /* 固定像素宽度 */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover" width={320}>
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>;

{
  /* 与触发器同宽 */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover" width="trigger">
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>;

{
  /* 全宽(100%) */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover" width="full">
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>;

{
  /* 随内容自适应(默认) */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover" width="content-fit">
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>;

底部抽屉呈现

在移动端使用底部抽屉交互。

重要: Popover.Contentpresentation 必须与 Popover 根上的 presentation 一致。开发模式下不一致会抛错。

<Popover presentation="bottom-sheet">
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="bottom-sheet">
      <Popover.Title>...</Popover.Title>
      <Popover.Description>...</Popover.Description>
      <Button>关闭</Button>
    </Popover.Content>
  </Popover.Portal>
</Popover>

方位选项

控制浮层相对触发器出现的位置。

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Content presentation="popover" placement="left">
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>

对齐选项

沿放置轴微调内容对齐。

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Content presentation="popover" placement="top" align="start">
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>

自定义动画

Popover 根上使用 animation 配置展开/收起过渡。

<Popover
  animation={{
    entering: {
      type: 'spring',
      config: { damping: 15, stiffness: 300 },
    },
    exiting: {
      type: 'timing',
      config: { duration: 200 },
    },
  }}
>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover">...</Popover.Content>
  </Popover.Portal>
</Popover>

编程式控制

// 通过 ref 编程式打开/关闭
const popoverRef = useRef<PopoverTriggerRef>(null);

// 打开
popoverRef.current?.open();

// 关闭
popoverRef.current?.close();

// 完整示例
<Popover>
  <Popover.Trigger ref={popoverRef} asChild>
    <Button>触发器</Button>
  </Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="popover">
      <Text>内容</Text>
      <Button onPress={() => popoverRef.current?.close()}>关闭</Button>
    </Popover.Content>
  </Popover.Portal>
</Popover>;

示例

import { Ionicons } from '@expo/vector-icons';
import { Button, Popover, useThemeColor } from 'heroui-native';
import { Text, View } from 'react-native';

export default function PopoverExample() {
  const themeColorMuted = useThemeColor('muted');

  return (
    <Popover>
      <Popover.Trigger asChild>
        <Button variant="tertiary" size="sm">
          <Ionicons
            name="information-circle"
            size={20}
            color={themeColorMuted}
          />
          <Button.Label>查看说明</Button.Label>
        </Button>
      </Popover.Trigger>
      <Popover.Portal>
        <Popover.Overlay />
        <Popover.Content
          presentation="popover"
          width={320}
          className="gap-1 rounded-xl px-6 py-4"
        >
          <Popover.Close className="absolute top-3 right-3 z-50" />
          <Popover.Title>说明</Popover.Title>
          <Popover.Description>
            此浮层包含标题与描述,用于向用户提供更有层次的信息。
          </Popover.Description>
        </Popover.Content>
      </Popover.Portal>
    </Popover>
  );
}

更多示例见 GitHub 仓库

API 参考

Popover

proptypedefaultdescription
childrenReactNode-浮层内的子节点
isOpenboolean-是否展开(受控)
isDefaultOpenboolean-初始是否展开(非受控)
onOpenChange(isOpen: boolean) => void-展开状态变化时的回调
animationAnimationRootDisableAll-动画配置,可为 false"disabled""disable-all"trueundefined
presentation'popover' | 'bottom-sheet''popover'内容呈现方式
asChildbooleanfalse是否将子元素作为实际渲染节点
...ViewPropsViewProps-支持全部标准 React Native View 属性

AnimationRootDisableAll

根级动画配置,可为:

  • false"disabled":仅禁用根动画
  • "disable-all":禁用根与子级全部动画
  • trueundefined:使用默认动画

Popover.Trigger

proptypedefaultdescription
childrenReactNode-触发器内容
classNamestring-触发器额外 class
asChildbooleantrue是否将子元素作为实际渲染节点
...PressablePropsPressableProps-支持全部标准 React Native Pressable 属性

Popover.Portal

proptypedefaultdescription
childrenReactNode-Portal内容(必填)
disableFullWindowOverlaybooleanfalse在 iOS 为 true 时使用 View 代替 FullWindowOverlay,便于元素检查器;遮罩将无法叠在原生模态之上
unstable_accessibilityContainerViewIsModalbooleanfalse控制 VoiceOver 是否将遮罩窗口视为模态容器。为 true 时,VoiceOver 仅聚焦遮罩内元素。仅 iOS;API 不稳定,可能随 react-native-screens 变更
hostNamestring-Portal宿主元素的可选名称
forceMountboolean-是否强制挂载
classNamestring-Portal容器额外 class
...ViewPropsViewProps-支持全部标准 React Native View 属性

Popover.Overlay

proptypedefaultdescription
classNamestring-遮罩额外 class
closeOnPressbooleantrue点击遮罩是否关闭
forceMountboolean-是否强制挂载
animationPopoverOverlayAnimation-动画配置
isAnimatedStyleActivebooleantrue是否启用 Reanimated 动画样式
asChildbooleanfalse是否将子元素作为实际渲染节点
...Animated.ViewPropsAnimated.ViewProps-支持 Reanimated Animated.View 的全部属性

PopoverOverlayAnimation

遮罩动画配置,可为:

  • false"disabled":禁用全部动画
  • trueundefined:使用默认动画
  • object:自定义动画配置
proptypedefaultdescription
state'disabled' | boolean-在自定义属性时用于禁用动画
opacity.value[number, number, number][0, 1, 0]透明度 [空闲, 打开, 关闭],用于底部抽屉等呈现
enteringEntryOrExitLayoutType默认淡入 200ms自定义进入关键帧,用于 popover 呈现
exitingEntryOrExitLayoutType默认淡出 150ms自定义退出关键帧,用于 popover 呈现

Popover.Content(Popover 呈现)

proptypedefaultdescription
childrenReactNode-浮层内容
presentation'popover''popover'呈现模式,须与 Popover 根一致;未传时默认为 popover
widthnumber | 'trigger' | 'content-fit' | 'full''content-fit'内容宽度策略
placement'top' | 'bottom' | 'left' | 'right''bottom'相对触发器的方位
align'start' | 'center' | 'end''center'沿放置轴的对齐
avoidCollisionsbooleantrue靠近视口边缘时是否翻转 placement
offsetnumber9与触发器的间距(像素)
alignOffsetnumber0沿对齐轴的偏移(像素)
disablePositioningStylebooleanfalse是否禁用自动定位样式
forceMountboolean-是否强制挂载
insetsInsets-定位时需遵守的屏幕边距
classNamestring-内容容器额外 class
animationPopupPopoverContentAnimation-动画配置
isAnimatedStyleActivebooleantrue是否启用 Reanimated 动画样式
asChildbooleanfalse是否将子元素作为实际渲染节点
...Animated.ViewPropsAnimated.ViewProps-支持 Reanimated Animated.View 的全部属性

Popover.Content(底部抽屉呈现)

proptypedefaultdescription
childrenReactNode-底部抽屉内容
presentation'bottom-sheet'-呈现模式,须为 bottom-sheet 并与根一致(必填)
contentContainerClassNamestring-内容容器额外 class
contentContainerPropsBottomSheetViewProps-内容容器属性
enablePanDownToClosebooleantrue是否允许下滑关闭
backgroundStyleViewStyle-底部抽屉背景样式
handleIndicatorStyleViewStyle-把手指示器样式
...BottomSheetPropsBottomSheetProps-支持 @gorhom/bottom-sheet 的全部属性

PopupPopoverContentAnimation

内容(popover 呈现)动画配置,可为:

  • false"disabled":禁用全部动画
  • trueundefined:使用默认动画
  • object:自定义动画配置
proptypedefaultdescription
state'disabled' | boolean-在自定义属性时用于禁用动画
enteringEntryOrExitLayoutType默认关键帧:translateY/translateX、scale、opacity(200ms)自定义进入关键帧
exitingEntryOrExitLayoutType默认与进入镜像(150ms)自定义退出关键帧

Popover.Arrow

proptypedefaultdescription
classNamestring-箭头额外 class
heightnumber12箭头高度(像素)
widthnumber20箭头宽度(像素)
fillstring-填充色(默认与内容背景一致)
strokestring-描边色(默认与内容边框色一致)
strokeWidthnumber1描边宽度(像素)
strokeBaselineInsetnumber1描边基线内缩(像素)
placement'top' | 'bottom' | 'left' | 'right'-浮层方位(自内容继承)
childrenReactNode-自定义箭头内容(替换默认 SVG)
styleStyleProp<ViewStyle>-箭头容器额外样式
...ViewPropsViewProps-支持全部标准 React Native View 属性

Popover.Close

Popover.Close 继承 CloseButton,按下时自动关闭浮层。

Popover.Title

proptypedefaultdescription
childrenReactNode-标题文案
classNamestring-标题额外 class
...TextPropsTextProps-支持全部标准 React Native Text 属性

Popover.Description

proptypedefaultdescription
childrenReactNode-说明文案
classNamestring-说明额外 class
...TextPropsTextProps-支持全部标准 React Native Text 属性

Hooks

usePopover

在自定义或复合子组件中读取浮层上下文。

import { usePopover } from 'heroui-native';

const CustomContent = () => {
  const { isOpen, onOpenChange, triggerPosition } = usePopover();
  // …实现
};

返回值

propertytypedescription
isOpenboolean当前是否打开
onOpenChange(open: boolean) => void修改展开状态的回调
isDefaultOpenboolean | undefined默认是否打开(非受控)
isDisabledboolean | undefined是否禁用
triggerPositionLayoutPosition | null触发器相对视口的位置
setTriggerPosition(triggerPosition: LayoutPosition | null) => void更新触发器位置
contentLayoutLayoutRectangle | null浮层内容的布局测量
setContentLayout(contentLayout: LayoutRectangle | null) => void更新内容布局测量
nativeIDstring当前实例唯一标识

说明: 必须在 Popover 内使用;在上下文外调用将抛错。

usePopoverAnimation

在自定义或复合子组件中读取浮层动画共享值。

import { usePopoverAnimation } from 'heroui-native';

const CustomContent = () => {
  const { progress, isDragging } = usePopoverAnimation();
  // …实现
};

返回值

propertytypedescription
progressSharedValue<number>动画进度(0=空闲,1=打开,2=关闭)
isDraggingSharedValue<boolean>是否正在拖拽

说明: 必须在 Popover 内使用;在动画上下文外调用将抛错。

特别说明

元素检查器(iOS)

Popover 在 iOS 使用 FullWindowOverlay。开发时若需启用 React Native 元素检查器,可在 Popover.Portal 设置 disableFullWindowOverlay={true}。代价:浮层将无法叠在原生系统模态之上。

原生模态(iOS)

Popover 位于以原生模态形式呈现的页面内时(presentation: 'modal' | 'formSheet' | 'pageSheet'),浮层内容可能会向上偏移渲染。在新架构(Fabric)中,react-native-screensRNSModalScreen 标记为 Fabric 根节点,因此触发器的坐标是相对于模态原点上报的,而 FullWindowOverlay(浮层挂载点)锚定在 iOS 应用窗口上。可通过将 safeAreaInsets.top 加到 offset 来补偿:

import { useSafeAreaInsets } from 'react-native-safe-area-context';

const insets = useSafeAreaInsets();

<Popover.Content presentation="popover" offset={insets.top + 20}>
  ...
</Popover.Content>;

本页目录