如何基于OnDrag和OnDragEnd实现移动端面板的平滑左右滑动?
实现基于OnDrag/OnDragEnd的移动端面板平滑滑动切换
不用直接通过启禁用面板来切换,改用横向容器+位移补间的方案,完全基于你现有的OnDrag和OnDragEnd方法实现平滑过渡,具体步骤如下:
1. 调整布局结构
- 把所有9:16尺寸的面板放在一个横向容器内,容器总宽度设为「单个面板宽度 × 面板数量」,高度和面板一致。
- 确保容器接收拖拽事件,面板自身禁用拖拽交互(内部按钮等元素保持可交互)。
2. 拖拽过程:实时跟随手指位移
在OnDrag方法中,让容器的X轴位置跟随拖拽偏移实时变化,同时加上边界限制防止拖出空白区域:
// 伪代码适配移动端框架逻辑 void OnDrag(PointerEventData eventData) { float deltaX = eventData.delta.x; float currentPosX = panelContainer.transform.localPosition.x; float newPosX = currentPosX + deltaX; // 计算边界:第一个面板X=0,最后一个面板X=-(面板数-1)*单面板宽度 float minX = -(panelCount - 1) * singlePanelWidth; float maxX = 0; newPosX = Mathf.Clamp(newPosX, minX, maxX); panelContainer.transform.localPosition = new Vector3(newPosX, 0, 0); }
3. 拖拽结束:平滑归位与切换判断
在OnDragEnd中,通过拖拽位移占比或滑动速度判断最终要停留的面板,然后用补间动画平滑移动到目标位置:
void OnDragEnd(PointerEventData eventData) { float currentPosX = panelContainer.transform.localPosition.x; int currentPanelIndex = Mathf.RoundToInt(-currentPosX / singlePanelWidth); // 两种判断逻辑:位移占比(简单)或滑动速度(灵敏),选其一或结合 float dragDistance = Mathf.Abs(eventData.position.x - eventData.pressPosition.x); float dragSpeed = Mathf.Abs(eventData.delta.x / Time.deltaTime); int targetIndex = currentPanelIndex; // 切换到下一个面板:位移超过1/3面板宽度,或速度超过阈值 if (dragDistance > singlePanelWidth / 3 || dragSpeed > 600) { if (eventData.delta.x < 0) // 向左滑 targetIndex = Mathf.Min(currentPanelIndex + 1, panelCount - 1); else // 向右滑 targetIndex = Mathf.Max(currentPanelIndex - 1, 0); } // 平滑移动到目标面板位置 float targetPosX = -targetIndex * singlePanelWidth; // 用补间动画实现过渡,可替换为对应框架的原生动画API panelContainer.transform.DOLocalMoveX(targetPosX, 0.3f).SetEase(Ease.OutQuad); }
4. 细节优化
- 如果用滚动容器组件(如ScrollRect),禁用默认滚动条,设置
movementType为Clamped避免过度滚动。 - 面板切换时,可给内部元素加淡入/缩放小动画,强化过渡体验。
- 动画播放时可暂时禁用拖拽事件,避免快速连续拖拽导致的动画冲突。
内容的提问来源于stack exchange,提问作者Jolyne Cujo
相关产品推荐
相关产品推荐

