Draggable property is hidden on gui objects


#1

As of this morning the Draggable property has been hidden. It still exists, but it’s not longer displayed on the properties window.

Nowhere to be seen. :frowning:

Repro steps:

  1. Open up a new place in studio (or any old one)
  2. Insert a Frame or any Gui object and select it
  3. Check for the Draggable property

I can repro this behavior 10/10 times, as can others I’ve asked to test. I’m on a windows machine.


#2

Same here. Really annoying.


#3

It’s been deprecated.


#4

Oh. Is there any particular reason why? Will there be any alternative method offered?


#5

It’s never worked very well, and it’s not very flexible. You can’t implement behaviors like snapping or constraints using it, and when you decide you need those, your only option is to rewrite it from scratch. The concept of clicking and dragging is also foreign for gamepad controls, so relying on them in your UX is kind of bad.

Here’s a snippet which actually works better than the Draggable property ever did.

local UserInputService = game:GetService("UserInputService")

local gui = script.Parent

local dragging
local dragInput
local dragStart
local startPos

local function update(input)
	local delta = input.Position - dragStart
	gui.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end

gui.InputBegan:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		dragging = true
		dragStart = input.Position
		startPos = gui.Position
		
		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				dragging = false
			end
		end)
	end
end)

gui.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		dragInput = input
	end
end)

UserInputService.InputChanged:Connect(function(input)
	if input == dragInput and dragging then
		update(input)
	end
end)

Why doesn't .Draggable work on mobile?
#7

Why can’t that just he the default behavior then?


#8

We understand the technical reasoning behind the depreciation, but why was it made so suddenly and without warning? I don’t recall Roblox making a public announcement (if they have yet to do so after the fact) or making a poll asking developers if they still needed the property. I recently implemented draggable UI elements in my game so now I can’t even access the Draggable property to switch it off without a script or replacing the dozens of elements entirely. The dragging behavior has always worked just fine for me, and snapping/constraining is not too difficult. This change is very frustrating, and I don’t understand how it was so critical that it had to be removed at all.


#9

Ugh. I get the reason why this was being deprecated but I have a legacy game to support until a new version is pushed out- its terrible UX relies on dragging. I really wish I had a notice; there was a small spike in dislikes and nobody told me it wasn’t working until today.


#10

The property should still be working, it is just deprecated.


#11

Could’ve sworn it wasn’t working where it was being used- works now though.


#12

I do recall a post just before Draggable was deprecated notifying developers about it. Regardless, you can still set the property whether it’s in the properties panel or not, and it will work just as it worked before, so it doesn’t really matter.
(sorry for the late reply, just wanted to clear it up)


#13

There is no reason why it was deprecated other than that it “never worked very well”, and on top of that, I don’t see why it was never fixed. For new players that want to drag GUIs around, they now are required to incorporate code in a place that previously, was not required.

It should be fixed and re implemented, because it is a feature that in my experience has been used widely in many games, particularly for novice developers.

I have successfully been able to implement constraints and snapping in combination with instances that have Draggable enabled.


#14

I second this. Implementing dragging I’ve found to be pretty simple (I’ll take a spelling check because I haven’t looked at the wiki, but if you remember if it’s -ed or -ing off the top of your head, good for you):

local Frame
local DragConnection 

local function Drag()
    -- constrain position to acceptable ranges
    local P = UDim2.new(0,math.max(MinXPosition,math.min(MaxXPosition,Frame.Position.X.Offset)),0,math.max(MinXPosition,math.min(MaxYPosition,Frame.Position.Y.Offset))
    -- apply position to Frame
    Frame.Position = P
    FrameJustGotDragged(P.Position.X.Offset-MinXPosition,P.Position.Y.Offset-MinYPosition) -- send the new input to wherever it's needed
end

local function DragBegin()
    DragConnection = Frame.Changed:connect(Drag)
end

local function DragEnded()
    if DragConnection then
        DragConnection:disconnect()
    end
end

Frame.DragBegin:connect(DragBegin)
Frame.DragEnded:connect(DragEnded)

This is simpler for sliders because one component is hard-coded, either the X component for vertical sliders or the Y component for horizontal sliders.

EDIT:

Here is a code block from an actual project:

	ReverserHandleDragger.DragBegin:connect(function()
		local dragged = ReverserHandleDragger.Changed:connect(function() -- anonymous function to constrain frame, calculate input, and pass it on up
			if not ReverserLocked then
				local px = ReverserHandleDragger.Position.X.Offset -- this is a horizontal slider
				if px > 40 then -- over the max
					px = 40 -- set px to max
					ReverserHandleDragger.Position = UDim2.new(0,px,0,0)
				elseif px < -10 then -- under the min
					px = -10 -- set px to min
					ReverserHandleDragger.Position = UDim2.new(0,px,0,0)
				elseif ReverserHandleDragger.Position.Y.Offset ~= 0 then
					ReverserHandleDragger.Position = UDim2.new(0,px,0,0) -- I probably could have moved this line out of the if block but whatever
				end
				local intermidiatesetting = (px-15)/25 -- alpha from -1 to 1
				if intermidiatesetting < -.333 then
					ReverserSetting =-1 -- put the train in reverse
					ThrottleLocked = false -- unlock the throttle
				elseif intermidiatesetting > .333 then
					ReverserSetting = 1 -- put the train in forward
					ThrottleLocked = false -- unlock the throttle
				else
					ReverserSetting = 0 -- put the train in neutral
					ThrottleLocked = true -- lock the throttle
				end
				if ReverserSetting ~= PreviousReverserSetting then
					remote:FireServer({["Reverser"]=ReverserSetting}) -- tell the server what we are doing
				end
				PreviousReverserSetting = ReverserSetting -- look for changes in the future
				ConfigureReverserHandle() -- update the GUI
			else
				ReverserHandleDragger.Position = UDim2.new(0,ReverserSetting*25+15,0,0) -- locked in place
			end
		end)
		local dragstop = nil
		dragstop = ReverserHandleDragger.DragStopped:connect(function() -- clean up after yourself
			ForceReverserHandle()
			dragged:disconnect()
			dragstop:disconnect()
		end)
	end)

As far as snapping, CmdUtl 5.0.0 has this, and I’m pretty sure SBS has it too. I’ve done it as well, but I’m not about to go deep diving to find it.

I’m missing why “snapping or constraints cannot be implemented” and am still questioning why it was deprecated. I have never had any outstanding issues with it.


#15

I’m so confused why the solution to “hey draggable doesn’t work that well” is to nuke the feature instead of changing it work properly.

Should we just nuke every feature that developers can potentially do better in lua?