- Home /
UI Slider: how to tell if value changed by user rather than a script?
I have a slider that I am changing in code, as a timeline scrubber that moves as the timeline is "played". When the user clicks on the slider, it stops tracking the timeline playback, and adjusts with the mouse input. When user lets go, the timeline jumps to the new slider location and playback continues from there.
With the old OnGUI system, you could easily tell if the user was interacting with the UI:
GUI.HorizontalSlider(new Rect(0f, 70f, Screen.width, 70f), sliderValue, 0, sliderMaxLength);
if(GUI.changed == true)
{
// Do something
}
However, as recommended by the docs, I am trying to use the new canvas/panel based UI. I like how I can easily composite the layout visually, anchoring things relative to panels, etc. Also easily customizing the look with the inspectors.
So how do I tell when the user is interacting with the slider? There is an onValueChanged event to which I can register a callback, but that gets called even when the value of the slider is changed by the script.
Thanks.
Answer by ripridehi · Apr 23, 2015 at 04:09 PM
I found a solution, based on this answer: If button highlighted by @DoTA_KAMIKADzE
I added this script to my slider components:
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class UISelectHandler : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
private bool isSelected;
public bool IsSelected
{
get {return isSelected; }
}
public void OnPointerDown(PointerEventData eventData)
{
isSelected = true;
}
public void OnPointerUp(PointerEventData eventData)
{
isSelected = false;
}
}
Then in my UIHandler script, I do this on startup:
Slider sliderScrubber;
UISelectHandler scrubberSelect;
bool isScrubberSelectedPrev;
void Start ()
{
sliderScrubber = panel.GetComponentInChildren<Slider>();
scrubberSelect = sliderScrubber.GetComponentInChildren<UISelectHandler>();
}
Now if the user does a mouse down anywhere in the slider, it reports it is "selected", until the user releases the mouse button.
// If the slider is actively selected, do nothing here,
// just let the user drag the slider around until they release it.
if(!scrubberSelect.IsSelected)
{
if(isScrubberSelectedPrev)
{
// Edge event, user has just released the mouse button.
// Set the timeline value to match the slider position.
timelineValue = sliderScrubber.value;
}
else
{
// Not selected, slider follows the timeline.
sliderScrubber.value = timelineValue;
}
}
isScrubberSelectedPrev = scrubberSelect.IsSelected;
Awesome example, I am sure others will benefit from it as well, thanks for sharing!
Answer by boysenberry · Apr 23, 2015 at 09:08 PM
I think this post answers your question. Basically the new UI uses Raycasting, so you'll be looking for OnPointerUp type of events I believe. Still digging in myself.
I would also suggest reading up on the info here.
I hope that helps.
Yup, OnPointerUp does the trick, thanks. I posted an answer to my own question, but it took a while to show up (below) - not enough karma points yet.
Answer by irreversal95 · Mar 19 at 08:51 AM
I know this is old but for a more simple method. Create a bool that becomes true when the slider value is being changed in code(Mines = loadingValues) and then false once the code is finished. Then the function that responds to the value change just needs to check whether the bool is true or not.
below is the code changing the slider value and setting the bool true as an example
loadingValues = true; musicSlider.value = CurrentGame.current.PlayerSaveData.playerSettings.musicVolume; Debug.Log(CurrentGame.current.PlayerSaveData.playerSettings.musicVolume); soundEffectsSlider.value = CurrentGame.current.PlayerSaveData.playerSettings.SoundEffectsVolume; Debug.Log(CurrentGame.current.PlayerSaveData.playerSettings.SoundEffectsVolume); npcJibberishSlider.value = CurrentGame.current.PlayerSaveData.playerSettings.NPCTalkVolume; Debug.Log(CurrentGame.current.PlayerSaveData.playerSettings.NPCTalkVolume); loadingValues = false;
now below is the function that's triggered when the value changes. It will only change if it is changes by a user.
if(loadingValues == false)
{
CurrentGame.current.PlayerSaveData.playerSettings.manualSettings = true;
CurrentGame.current.PlayerSaveData.playerSettings.musicVolume = musicSlider.value;
if (JukeBox.currentJukeBoxSong != null)
{
JukeBox.currentJukeBoxSong.audioSource.volume = musicSlider.value;
}
CurrentGame.current.PlayerSaveData.playerSettings.NPCTalkVolume = npcJibberishSlider.value;
CurrentGame.current.PlayerSaveData.playerSettings.SoundEffectsVolume = soundEffectsSlider.value;
}
Your answer
