You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Material UI Swipeable Drawer滑动范围限制与禁用向下关闭求助

解决Material UI Swipeable Drawer的滑动限制与状态控制问题

需求概述

  • 数据加载阶段显示加载状态
  • 加载完成后抽屉自动停靠在页面中部并展示数据
  • 仅允许抽屉在**屏幕顶部(完全展开)和页面中部(半关闭)**间切换,禁止向下完全关闭

当前待解决问题

  1. 阻止抽屉向下滑动至完全关闭状态
  2. 实现顶部与中部两个位置的滑动切换逻辑

现有代码

return (
<>
  <CssBaseline/>
  <Global
    styles={{
      '.MuiDrawer-root': {
        position: 'static !important',
      },
      '.MuiDrawer-root > .MuiPaper-root': {
        height: `calc(95% - ${drawerBleeding}px)`,
        overflow: 'visible',
      },
    }}
  />
  <SwipeableDrawer
    container={container}
    anchor="bottom"
    open={open}
    onClose={toggleDrawer(false)}
    onOpen={toggleDrawer(true)}
    swipeAreaWidth={drawerBleeding}
    disableBackdropTransition={true}
    disableDiscovery={true}
    hideBackdrop={true}
    disableSwipeToOpen={!searchCompleted}
    ModalProps={{
      keepMounted: true,
    }}
  >
    <StyledBox
      sx={{
        position: 'absolute',
        top: -drawerBleeding,
        borderTopLeftRadius: 8,
        borderTopRightRadius: 8,
        visibility: 'visible',
        right: 0,
        left: 0,
        backgroundColor: '#FFF',
        height: `${drawerBleeding + 1}px`,
      }}
    >
      <Puller />
      {!searchCompleted
      && <>
        <Typography sx={[Styles.searchingText]}>
          <FormattedMessage id="searching" />
        </Typography>
        <Box sx={{ marginBottom: '15px' }}>
          <ProgressBar searchCompleted={() => {
            setSearchCompleted(true);
            setOpen(true);
          }}
          />
        </Box>
      </>}
      {searchCompleted
      && <Typography sx={Styles.searchingResult}>
        <FormattedMessage id="searchingResult" />
      </Typography>}

    </StyledBox>
    <StyledBox sx={{
      height: '100%',
      overflow: 'hidden',
    }}>
      {searchCompleted && results.length !== 0
      &&
      <VisualSearchResult id="visualSearchResult" />
      }
    </StyledBox>

  </SwipeableDrawer>
</>
);

解决方案实现

1. 新增状态控制停靠位置

添加两个状态变量,分别控制抽屉的中部停靠和顶部完全展开状态:

const [isMiddleOpen, setIsMiddleOpen] = useState(false);
const [isFullOpen, setIsFullOpen] = useState(false);

2. 自定义滑动事件处理逻辑

通过监听滑动动作,阻止完全关闭行为,并根据滑动距离切换停靠位置:

// 滑动结束时阻止完全关闭,切换对应状态
const handleSwipeEnd = (event, openStatus) => {
  if (!openStatus) {
    event.preventDefault();
    // 若滑动未达到顶部阈值,默认回到中部
    setIsFullOpen(false);
    setIsMiddleOpen(true);
  }
};

// 滑动过程中根据距离判断切换目标位置
const handleSwipeMove = (event, deltaY) => {
  const screenHeight = window.innerHeight;
  // 设定滑动阈值,超过则切换状态
  const threshold = screenHeight * 0.25;

  if (deltaY < -threshold) {
    setIsFullOpen(true);
    setIsMiddleOpen(false);
  } else if (deltaY > threshold) {
    setIsFullOpen(false);
    setIsMiddleOpen(true);
  }
};

3. 动态调整Drawer样式

修改全局样式,根据当前状态动态设置抽屉高度:

<Global
  styles={{
    '.MuiDrawer-root': {
      position: 'fixed !important',
    },
    '.MuiDrawer-root > .MuiPaper-root': {
      // 完全展开时占满屏幕,中部状态占50%高度
      height: isFullOpen ? '100%' : `calc(50% - ${drawerBleeding}px)`,
      bottom: 0,
      overflow: 'auto',
    },
  }}
/>

4. 更新SwipeableDrawer属性配置

绑定自定义滑动逻辑,禁用完全关闭的触发条件:

<SwipeableDrawer
  container={container}
  anchor="bottom"
  // 加载完成后保持打开,不允许完全关闭
  open={searchCompleted}
  onClose={handleSwipeEnd}
  onOpen={() => setIsMiddleOpen(true)}
  swipeAreaWidth={drawerBleeding}
  disableBackdropTransition={true}
  disableDiscovery={true}
  hideBackdrop={true}
  disableSwipeToOpen={!searchCompleted}
  onSwipeMove={handleSwipeMove}
  ModalProps={{
    keepMounted: true,
    // 禁止点击背景关闭抽屉
    onBackdropClick: (e) => e.preventDefault(),
  }}
>
  {/* 原有内容保持不变 */}
</SwipeableDrawer>

5. 加载完成后的自动触发逻辑

修改ProgressBar的回调,确保加载完成后抽屉自动停靠在中部:

<ProgressBar searchCompleted={() => {
  setSearchCompleted(true);
  setIsMiddleOpen(true);
  setIsFullOpen(false);
}} />

核心逻辑说明

  • 通过动态修改抽屉高度实现双位置停靠的视觉效果
  • 监听滑动距离判断用户操作意图,切换对应状态
  • 重写关闭事件与背景点击事件,彻底阻止抽屉完全关闭的行为

内容的提问来源于stack exchange,提问作者hossein ketabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:24:54