UIDragDetector 实例促进并鼓励与体验中的 2D 用户界面元素的交互,例如滑块、旋转器等。主要功能包括:
将 UIDragDetector 放置在任何 GuiObject 实例下,可以通过所有用户输入实现可拖拽,而无需编写一行代码。
从多个 DragStyle 选项中进行选择,定义对象对运动的响应方式,通过 ResponseStyle,并可以选择施加轴、运动限制或拖动边界。
脚本可以根据拖动对象的操作作出响应,以驱动逻辑响应,例如调整设置。
UIDragDetectors 在 Studio 的编辑和播放模式下工作,只要您不使用选择、移动、缩放或旋转工具,以及某些插件或 Studio 的 UI 编辑器工具。
使 UI 元素可拖动
要使任何 GuiObject 实例可拖动,只需添加 UIDragDetector 作为直接后代。
从菜单中,插入一个 UIDragDetector。

默认情况下,该对象现在将在 LayerCollector 界面中可拖动。
自定义 UI 拖动检测器
拖动样式
UIDragDetectors 将光标运动映射以计算提议的 2D 运动和/或旋转。通过 DragStyle 属性,您可以选择不同的映射以满足您的需求。例如,Enum.UIDragDetectorDragStyle.TranslatePlane 在 LayerCollector 的 2D 平面内产生平移,而 Enum.UIDragDetectorDragStyle.Rotate 通常产生旋转而不是平移。
| 设置 | 描述 |
|---|---|
| TranslateLine | 沿检测器的 DragAxis 的 1D 运动。 |
| TranslatePlane | LayerCollector 平面内的 2D 运动。 |
| Rotate | 默认情况下,围绕检测器的父 GuiObject 的绝对中心位置旋转。如果设置了 ReferenceUIInstance,则旋转将围绕该实例的绝对中心位置进行。 |
| Scriptable | 通过 SetDragStyleFunction() 提供的自定义函数计算期望运动。 |
拖动方向
默认情况下,2D 运动和相关的 DragStyle 映射到祖先 LayerCollector 的空间。不过,当构建不同的 UI 组件时,您可能希望更改 ReferenceUIInstance 或 DragAxis。
| 设置 | 描述 | 默认 |
|---|---|---|
| ReferenceUIInstance | 作为检测器的参考空间和原点的 GuiObject 实例,其局部空间和绝对中心位置。设置此参考会影响 DragUDim2、DragRotation 和 DragAxis 的行为等属性。 | nil |
| DragAxis | 当 DragStyle 设置为 Enum.UIDragDetectorDragStyle.TranslateLine 时,定义拖动对象的运动轴的 Vector2 值。该轴是在 UIDragDetector 的局部空间中定义的,除非定义了 ReferenceUIInstance,在这种情况下,轴在该实例的局部空间中定义。 | (1, 0) |
对运动的响应
UIDragDetector.ResponseStyle 属性指定对象的位置值如何被提议的运动所改变。自定义响应样式允许您根据需要使用结果的 UIDragDetector.DragUDim2 和 UIDragDetector.DragRotation 值,而无需让检测器的父级执行提议的运动。
| 设置 | 描述 |
|---|---|
| Offset | 根据检测器父级的 GuiObject.Position 值的 Offset 值移动。这是默认设置。 |
| Scale | 根据检测器父级的 GuiObject.Position 值的 Scale 值移动。 |
| CustomOffset | UI 元素将完全不移动,但检测器的 DragUDim2 的 Offset 值仍将更新,检测器的事件仍将触发,使您能够根据需要响应拖动操作。 |
| CustomScale | UI 元素将完全不移动,但检测器的 DragUDim2 的 Scale 值仍将更新,检测器的事件仍将触发,使您能够根据需要响应拖动操作。 |
平移与旋转限制
默认情况下,2D 运动不受 DragStyle 的固有限制。如果需要,可以使用以下属性声明平移和旋转的最小和最大限制。此外,您可以定义拖动对象在指定的 GuiObject(例如 Frame)的边界内如何约束。
| 属性 | 描述 | 默认 |
|---|---|---|
| MinDragTranslation MaxDragTranslation | 在每个维度上的拖动平移限制,由 UDim2 值定义。如果 MaxDragTranslation 大于 MinDragTranslation,则平移将在该范围内限制。 | {0, 0}, {0, 0} |
| MinDragAngle MaxDragAngle | 仅在 DragStyle 设置为 Enum.UIDragDetectorDragStyle.Rotate 时相关,或当通过 SetDragStyleFunction() 或 AddConstraintFunction() 设置的函数定义了旋转值。如果 MaxDragAngle 大于 MinDragAngle,则旋转将在该范围内限制。 | 0 |
| BoundingBehavior | 确定 UIDragDetector 实例的边界行为,当其 BoundingUI 设置时。将其设置为 EntireObject 会将整个拖动 UI 限制在 BoundingUI 内,而将其设置为 HitPoint 仅会根据精确的点击/抓取点及其在平移/旋转后的相应位置限制拖动的 UI。作为方便,Automatic 的默认值对于完全包含在 BoundingUI 内的 UI 对象模拟 EntireObject 的行为,否则对于部分在 BoundingUI 外部的 UI 对象模拟 HitPoint 的行为。 | Automatic |
速度调整
通过 SelectionModeDragSpeed 和 SelectionModeRotateSpeed,您可以微调检测器的最大拖动/旋转速度。此外,通过 UIDragSpeedAxisMapping,您可以根据检测器的 SelectionModeDragSpeed 微调 X/Y 维度的拖动速度。
| 属性 | 描述 |
|---|---|
| SelectionModeDragSpeed | 定义拖动平移的最大速度,作为检测器所属的第一个祖先 ScreenGui 或 SurfaceGui 的 Scale 和 Offset 的组合。 |
| SelectionModeRotateSpeed | 定义 UIDragDetector 可以旋转的每秒最大角度。 |
| UIDragSpeedAxisMapping | 根据检测器的 SelectionModeDragSpeed 决定 X/Y 维度的拖动速度。默认值为 XY,意味着 X 和 Y 轴速度基于 X 和 Y 的 Scale/Offset 值。 可选值为 XX 和 YY,意即 X 和 Y 轴速度分别基于 X(XX) 或 Y(YY) 轴的 Scale,同时 Offset 值仍然适用于其各自的轴。例如,如果第一个祖先 ScreenGui 的大小为 800×600,而 SelectionModeDragSpeed 为 {0.1, 10}, {0.1, 20},则设置为 XX 会导致 X/Y 拖动速度为 80+10/80+20,而 YY 则会导致 60+10/60+20(请注意 Offset 值在两种情况下保持不变)。 |
脚本对点击和拖动的响应
通过 事件信号、属性更改、Scriptable 拖动样式和自定义函数,脚本可以响应对拖动 UI 元素的操作,以驱动各种设置或做出逻辑决策,例如单独调整音乐和音效音量的滑块。
事件信号
通过以下事件信号,您可以检测用户何时开始、继续和结束拖动对象。
| 事件 | 描述 |
|---|---|
| DragStart | 当用户开始拖动对象时触发。 |
| DragContinue | 当用户在 DragStart 触发后继续拖动对象时触发。 |
| DragEnd | 当用户停止拖动对象时触发。 |
以下滑块将其容器指定为 BoundingUI,以限制其在容器区域内的移动,允许基于缩放的 TranslateLine 拖动限制在容器的全宽内,而无需额外的脚本。
UIDragDetector - 事件信号透明度变化
-- 层次结构是 SliderContainer ⟩ Handle ⟩ UIDragDetector ⟩ (此脚本)
local sliderContainer = script.Parent.Parent.Parent
local handle = sliderContainer:FindFirstChild("Handle")
local uiDragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
uiDragDetector.ResponseStyle = Enum.UIDragDetectorResponseStyle.Scale -- 设置按比例拖动
uiDragDetector.DragStyle = Enum.UIDragDetectorDragStyle.TranslateLine -- 限制拖动到直线
uiDragDetector.BoundingUI = sliderContainer
-- 初始化设置容器透明度为手柄的 X 比例值
sliderContainer.BackgroundTransparency = 1 - handle.Position.X.Scale
-- 扩展手柄边框以指示抓取开始
uiDragDetector.DragStart:Connect(function(inputPosition)
handle:FindFirstChildWhichIsA("UIStroke").Thickness = 6
end)
-- 根据拖动的缩放量改变透明度
uiDragDetector.DragContinue:Connect(function(inputPosition)
sliderContainer.BackgroundTransparency = 1 - handle.Position.X.Scale
end)
-- 恢复手柄边框以指示抓取结束
uiDragDetector.DragEnd:Connect(function(inputPosition)
handle:FindFirstChildWhichIsA("UIStroke").Thickness = 4
end)
位置与旋转更改
除了 事件信号 之外,您还可以直接监视检测器的 DragUDim2 和/或 DragRotation 属性的变化。
以下检测器的 DragStyle 设置为 Rotate,允许用户在色调旋转环周围拖动手柄,同时通过 Instance:GetPropertyChangedSignal() 检测拖动旋转的变化。
UIDragDetector - DragRotation 更改
local handle = script.Parent.Parent -- 要拖动的 UI 元素
local uiDragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
uiDragDetector.DragStyle = Enum.UIDragDetectorDragStyle.Rotate -- 设置拖动样式为旋转
local function changeHue()
local currAngle = (math.fmod(handle.Rotation, 360)) / 360
if currAngle < 0 then
currAngle += 1
end
handle.BackgroundColor3 = Color3.fromHSV(currAngle, 1, 1)
end
-- 初始化设置色调为手柄的旋转
changeHue()
-- 将函数连接到检测器的拖动旋转的 GetPropertyChangedSignal()
uiDragDetector:GetPropertyChangedSignal("DragRotation"):Connect(changeHue)
脚本化拖动样式
如果您将检测器的 UIDragDetector.DragStyle 设置为 Enum.UIDragDetectorDragStyle.Scriptable,则可以提供自己的函数,该函数接受 Vector2 的输入位置并返回 UDim2(位置)和一个浮点数(旋转)。检测器将根据返回值、DragSpace 属性和 DragRelativity 属性更新对象的位置/旋转。
默认情况下,返回的 UDim2 和浮点数将是检测器父级局部空间中的 最终 所需位置/旋转。现有的平移/旋转限制和由指定的 BoundingUI 实例施加的边界限制仍然适用。
以下示例通过输入的 X 坐标变化计算正弦波拖动 UI 元素。请注意,检测器的 DragSpace 被设置为 Enum.UIDragDetectorDragSpace.Relative。
UIDragDetector - 拖动跟随正弦波
local frame = script.Parent -- 要拖动的 UI 元素
local uiDragDetector = frame:FindFirstChildWhichIsA("UIDragDetector")
local initialXValue = 0
local maxHeightChange = 200
local pixelsPerRadian = 75 -- 降低该值以增加频率
uiDragDetector.DragStart:Connect(function(inputPosition)
initialXValue = inputPosition.X
end)
local function computeSinWaveCoordinate(inputPosition)
local deltaX = inputPosition.X - initialXValue
-- 负 Y 增量使其在屏幕上以正 Y 变化向“上”移动
local deltaY = -math.sin(deltaX / pixelsPerRadian) * maxHeightChange
return UDim2.fromOffset(deltaX, deltaY)
end
uiDragDetector:SetDragStyleFunction(computeSinWaveCoordinate)
自定义约束函数
UIDragDetectors 没有关于网格和对齐的内置运动规则,但您可以注册自定义约束函数,以在应用之前编辑检测器的 UIDragDetector.DragUDim2 和 UIDragDetector.DragRotation。例如,您可以通过将位置四舍五入到特定增量使运动保持在网格上,或定义允许的运动区域。请注意,这在应用任何现有平移/旋转限制之前进行。
以下示例利用约束函数将平面拖动限制在基于行和列数的 X/Y 网格中。请注意,检测器的 ResponseStyle 设置为 Enum.UIDragDetectorResponseStyle.Scale,其 BoundingUI 设置为网格容器。
UIDragDetector - 在网格中拖动,贴合瓦片
-- 层次结构是 GridContainer ⟩ Handle ⟩ UIDragDetector ⟩ (此脚本)
local gridContainer = script.Parent.Parent.Parent
local handle = gridContainer:FindFirstChild("Handle") -- 要拖动的 UI 元素
local uiDragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")
uiDragDetector.ResponseStyle = Enum.UIDragDetectorResponseStyle.Scale -- 设置按比例拖动
uiDragDetector.DragRelativity = Enum.UIDragDetectorDragRelativity.Relative
uiDragDetector.BoundingUI = gridContainer
local NUM_COLUMNS = 10
local NUM_ROWS = 5
local xScaleIncrement = 1 / NUM_COLUMNS
local yScaleIncrement = 1 / NUM_ROWS
local initialParentPosition = uiDragDetector.Parent.Position
uiDragDetector.DragStart:Connect(function()
initialParentPosition = uiDragDetector.Parent.Position
end)
local function dragToGridOnly(proposedPosition, proposedRotation)
local griddedXScale = math.round(proposedPosition.X.Scale / xScaleIncrement) * xScaleIncrement
local griddedYScale = math.round(proposedPosition.Y.Scale / yScaleIncrement) * yScaleIncrement
return UDim2.fromScale(griddedXScale, griddedYScale), proposedRotation
end
uiDragDetector:AddConstraintFunction(1, dragToGridOnly)