This is going to be a step by step tutorial to modify the Lua App Universal App “AdjustmentSlider” Component.
At the end it’s going to look something like this:
There were a few more things that I was trying to do, but I ended up not experimenting with that area, because I’d have to modify UIBlox for that, and this would increase the tutorial to much.
Purpose?
What’s the purpose of this tutorial? It’s only useful to Roblox. But they don’t even need this.
The purpose is that I can show what I wanted the Accessory Adjustment Editor to additionally include.
I might speedran this, but that what is achieved here, is explained.
A few things that may be interesting to you?
What does the Accessory Adjustment do?
Everytime you move the slider, it applies HumanoidDescription… uhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
I guess it works… Though I think there was an alternate version, though at the end it’s math… so you could just alter the welds.
Notes
When I created this, I didn’t know the Slider had a props.textInputEnabled
property that would bring a text input near the slider as well.
UIBlox…
Let’s begin!
Open the following ModuleScript: AvatarExperience.AccessoryAdjustment.Components.AdjustmentSlider
.
This is the only file we will be modifying.
Since things are different for me, the variable names will probably be different compared to what you (if you’re a Roblox Engineer) would see.
The table variable with the LimitKey
, I named it AdjustmentTypeConstants
as I had no clue what else it could be.
How to make the reset buttons
I won’t mention how I animated the Buttons, as I believe the way I choose to do it may be not ideal on how I control the behavior. But it was done with ReactOtter
.
Basically
local ReactOtter = require(CorePackages.Packages.ReactOtter)
Summary
local function SliderImage(theme, adjustmentSliderType, iconSize, otherProps)
local scaleEffectGoal, setScaleEffectGoal = React.useState(1)
local scaleAnimValue, setGoal = ReactOtter.useAnimatedBinding(1)
local function UIScale_Effect(props)
return React.createElement("UIScale", {
Scale = props.Scale
})
end
React.useEffect(function()
setGoal(ReactOtter.ease(scaleEffectGoal, {
duration = 0.05,
easingStyle = Enum.EasingStyle.Quad
}))
end, {scaleEffectGoal})
local ImageSetComponent = React.createElement(ImageSetLabel, {
Size = UDim2.new(0, iconSize, 0, iconSize),
BackgroundTransparency = 1,
Image = asset_cirle_21,
ImageColor3 = AdjustmentTypeConstants[adjustmentSliderType].Color,
ImageTransparency = theme.IconEmphasis.Transparency,
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.new(0.5, 0, 0.5, 0),
[React.Event.MouseButton1Click] = function()
local defaultValue = Constants.DefaultSliderValues[adjustmentSliderType]
otherProps.setSliderValuesCallback(defaultValue, adjustmentSliderType)
otherProps.updateCharacterCallback(defaultValue, adjustmentSliderType)
end,
[React.Event.MouseButton1Down] = function()
setScaleEffectGoal(0.7)
end,
[React.Event.MouseButton1Up] = function()
setScaleEffectGoal(1)
end,
[React.Event.MouseLeave] = function()
setScaleEffectGoal(1)
end,
}, {
Letter = React.createElement("TextLabel", {
Size = UDim2.new(1, -3, 1, -3),
BackgroundTransparency = 1,
Text = AdjustmentTypeConstants[adjustmentSliderType].Text,
TextScaled = true,
FontFace = Constants.FontFace,
TextColor3 = Color3.new(1, 1, 1),
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.new(0.5, 0, 0.5, 0),
ZIndex = 2
}),
UIScale = UIScale_Effect({
Scale = scaleAnimValue
})
});
return React.createElement("Frame", {
BackgroundTransparency = 1,
Size = UDim2.new(0, iconSize, 0, iconSize),
}, ImageSetComponent)
end
First I replaced the ImageSetLabel with this
local ImageSetLabel = UIBlox.Core.ImageSet.ImageSetButton
Because buttons have clicking events.
The part that you want to add to the SliderImage is this.
[React.Event.MouseButton1Click] = function()
local defaultValue = Constants.DefaultSliderValues[adjustmentSliderType]
otherProps.setSliderValuesCallback(defaultValue, adjustmentSliderType)
otherProps.updateCharacterCallback(defaultValue, adjustmentSliderType)
--print(defaultValue, adjustmentSliderType)
end,
- At the end you need to go to
createElement
and pass the props
SliderImage = SliderImage(
Theme,
props.adjustmentSliderType,
mapTokens.smallIconSize,
props
)
Adding the Slider Text
NOTE:
When I created this thread, I didn’t know about props.textInputEnabled
for UIBlox’s SystemSlider component. (Which is a more vanilla way to integrate a text input to the slider)
Nevermind the SliderTextInput uses the same percentage based values by default, which is not what I was aiming for.
If you want to do it through the props.textInputEnabled
way, simply follow the details below.
Expand me for easier way
- At the location where the SystemSlider Component is being created through
createElement
. Within itsprops
simply add this property.
textInputEnabled = true
That’s literally all…
Different way
- Put this somewhere at the top area of the script or something.
local SliderText_padding = 45
- Add this
local function SliderText(theme, adjustmentSliderType, sliderValue, otherProps)
local style = useStyle()
local tokens = style.Tokens
local textFieldStyle = tokens.Component.TextField
local selectionBorderThickness = tokens.Semantic.Stroke.Focus
local iconSize = tokens.Semantic.Icon.Size.Small
local curValue = sliderValue
local textBoxRef = React.useRef(nil)
local selectorLowerAdjustmentLimits = useSelector(selectLowerAdjustmentLimits);
local selectorUpperAdjustmentLimits = useSelector(selectUpperAdjustmentLimits);
return React.createElement("TextBox", {
ref = textBoxRef,
Text = curValue,
[React.Event.FocusLost] = function(enterPressed)
local AdjustmentKey = AdjustmentTypeConstants[adjustmentSliderType].AdjustmentKey;
local LimitKey = AdjustmentTypeConstants[adjustmentSliderType].LimitKey;
local lowerLimit = selectorLowerAdjustmentLimits[AdjustmentKey][LimitKey];
local upperLimit = selectorUpperAdjustmentLimits[AdjustmentKey][LimitKey];
local newValue = tonumber(textBoxRef.current.Text)
-- Cap new value
--newValue = math.max(lowerLimit, math.min(upperLimit, newValue))
-- You can or maybe should use math.clamp instead of that there!!!
newValue = math.clamp(newValue, lowerLimit, upperLimit)
otherProps.setSliderValuesCallback(newValue, adjustmentSliderType)
otherProps.updateCharacterCallback(newValue, adjustmentSliderType)
--print(newValue, adjustmentSliderType)
end,
BackgroundTransparency = 1,
ClearTextOnFocus = false,
Font = textFieldStyle.Base.Field.Typography.Font,
TextColor3 = textFieldStyle.Base.FieldValue.ContentColor.Color3,
TextTransparency = textFieldStyle.Base.FieldValue.ContentColor.Transparency,
TextSize = textFieldStyle.Base.Field.Typography.FontSize - 3,
Size = UDim2.new(0, SliderText_padding, 0, 32),
ClipsDescendants = true,
LayoutOrder = 3,
}, {
React.createElement("UICorner", {
CornerRadius = UDim.new(0, 6)
}),
React.createElement("UIStroke", {
ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
Color = textFieldStyle.Base.Field.BorderColor.Color3,
Thickness = 1,
Transparency = textFieldStyle.Base.Field.BorderColor.Transparency,
}),
})
end
-
Locate this line
Slider = React.createElement(
-
Within that
createElement
function, changewidth
so it matches this
width = UDim.new(
1,
-mapTokens.padding - mapTokens.smallIconSize
- (SliderText_padding - -16)
)
The reason why there's ``-16`` is because of the padding, and I don't know.
- Then within that same
createElement
add
SliderText = SliderText(
Theme, adjustmentSliderType, props.sliderValue, props
)
And that should be it!
This is how you do it.
Conclusion
I am not sure if I should of have used otherProps
to simply pass the props through. You only need the callbacks. And these two functions could have been moved else where.
Why did I not use the Text Field Component from UIBlox?
The reason is…
I didn’t want to modify UIBlox itself, it’s missing props, instead I just copied a portion of the UIBlox Text Component. I guess you could call it “Super Lite Version” of UIBlox’s Text Field Component.
Why did you not do X with the UI?
UIBlox props
are the reason. And for this thread, I solely wanted to modify one file.
These callback functions… I don’t know what to think about them. They function and work, but maybe moving them somewhere else could be interesting.
Final Notes
This is just a sketch and an idea. I doubt anyone at Roblox would make these X Y Z buttons clickable, as it is a hidden feature otherwise. There’s no hint for it.
Instead, I’d put that Undo Button from the top right.
What I actually would do is the following:
- Get rid of the X Y Z labels, and instead move them into the center of the slider circle.
- Now, we have space to add a undo button and text field
e.g. the Slider like so
Additonally, I’d make the slider track fill bar start at the center. You may notice how in the video, the slider values had inconsistency between X Y Z.
Moving one fully to the right, would have said 0.25
while for the other Axis it would have said -0.25
. This makes it a bit confusing, and I believe the solution would be to have the sliders different.
I’d want to experiment with that, but I probably won’t do it in the Universal App. I had to go through severe amount of pain to even get it to run on Studio and the amount of Memory that thing needs with the way on how I did it… is… catastrophic.
I’d also want to experiment with useMemo
.
If you want to reset your position to 0 in vanilla ways, you can enable the following Fast Flags:
-
FFlagAXAASnapSliderToMiddle
, to true -
FIntAXAdjustmentSnapThreshold
, default is 5
But I tried it and… I don’t trust it, I need to see the number.
And these flags are not even where all flags usually get stored at. Yet today that’s another Roblox mystery to me.