Material UI Swipeable Drawer滑动范围限制与禁用向下关闭求助
解决Material UI Swipeable Drawer的滑动限制与状态控制问题
需求概述
- 数据加载阶段显示加载状态
- 加载完成后抽屉自动停靠在页面中部并展示数据
- 仅允许抽屉在**屏幕顶部(完全展开)和页面中部(半关闭)**间切换,禁止向下完全关闭
当前待解决问题
- 阻止抽屉向下滑动至完全关闭状态
- 实现顶部与中部两个位置的滑动切换逻辑
现有代码
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
相关产品推荐
相关产品推荐

