Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: Arcanor on February 22, 2014, 11:14:32 PM

Title: UISlider OnValueChange events
Post by: Arcanor on February 22, 2014, 11:14:32 PM
I've got a UISlider, set to have some number of discrete steps.  When I drag the slider, why am I getting multiple OnValueChange events triggering, even if the drag doesn't actually change the UISlider's value to a new step?  How can I keep those events from triggering in all cases where the value hasn't actually changed?

Thanks!
Title: Re: UISlider OnValueChange events
Post by: ArenMook on February 23, 2014, 12:19:37 PM
The steps affect how the slider's value is retrieved, but the actual stored value of the slider may not match. The OnChange notification tells you that the internal value changed. Whether it affected the retrieved step-affected value is different.
Title: Re: UISlider OnValueChange events
Post by: Arcanor on February 23, 2014, 12:25:36 PM
Thanks.  Okay, so then how can I only trigger events when the value steps up?  I don't want events happening for irrelevant changes.
Title: Re: UISlider OnValueChange events
Post by: ArenMook on February 23, 2014, 12:45:22 PM
You retrieve the step-affected value via UIProgressBar.value, and whether it actually changed or not shouldn't matter. Why does it matter in your case?
Title: Re: UISlider OnValueChange events
Post by: Arcanor on February 23, 2014, 01:54:39 PM
It matters because I'm using the slider to control a character avatar editor.  Every time the value changes I need to rebuild the avatar from its many various components, which is expensive.

I tried using the UIProgressBar.value as you suggested, but it still updates the same number of times.

I still don't understand why the value change event is triggered in this case.  The idea of a stepped value on the control implies that if the value doesn't change the event shouldn't be triggered.
Title: Re: UISlider OnValueChange events
Post by: ArenMook on February 23, 2014, 06:04:42 PM
Change UIProgressBar.value function to this and it won't:
  1.         public float value
  2.         {
  3.                 get
  4.                 {
  5.                         if (numberOfSteps > 1) return Mathf.Round(mValue * (numberOfSteps - 1)) / (numberOfSteps - 1);
  6.                         return mValue;
  7.                 }
  8.                 set
  9.                 {
  10.                         float val = Mathf.Clamp01(value);
  11.  
  12.                         if (mValue != val)
  13.                         {
  14.                                 float before = this.value;
  15.                                 mValue = val;
  16.  
  17.                                 if (NGUITools.GetActive(this))
  18.                                 {
  19.                                         if (before != this.value)
  20.                                         {
  21.                                                 if (EventDelegate.IsValid(onChange))
  22.                                                 {
  23.                                                         current = this;
  24.                                                         EventDelegate.Execute(onChange);
  25.                                                         current = null;
  26.                                                 }
  27.                                                 ForceUpdate();
  28.                                         }
  29. #if UNITY_EDITOR
  30.                                         if (!Application.isPlaying)
  31.                                                 NGUITools.SetDirty(this);
  32. #endif
  33.                                 }
  34.                         }
  35.                 }
  36.         }
Title: Re: UISlider OnValueChange events
Post by: Arcanor on February 23, 2014, 09:29:47 PM
Thanks Michael.  Your code almost worked, but failed due to floating point compare error.  Rounding fixed it.  I figured that since there can't be more than 20 steps, it was safe enough to compare after multiplying the floats by 1000 and then casting to int.  Here's the updated code FYI:

  1.     public float value
  2.     {
  3.         get
  4.         {
  5.             if (numberOfSteps > 1) return Mathf.Round(mValue * (numberOfSteps - 1)) / (numberOfSteps - 1);
  6.             return mValue;
  7.         }
  8.         set
  9.         {
  10.             float val = Mathf.Clamp01(value);
  11.  
  12.             if (mValue != val)
  13.             {
  14.                 int before = (int)Mathf.Round(this.value * 1000);
  15.                 mValue = val;
  16.  
  17.                 if (NGUITools.GetActive(this))
  18.                 {
  19.                     if (before != Mathf.Round(this.value * 1000))
  20.                     {
  21.                         if (EventDelegate.IsValid(onChange))
  22.                         {
  23.                             current = this;
  24.                             EventDelegate.Execute(onChange);
  25.                             current = null;
  26.                         }
  27.                         ForceUpdate();
  28.                     }
  29. #if UNITY_EDITOR
  30.                     if (!Application.isPlaying)
  31.                         NGUITools.SetDirty(this);
  32. #endif
  33.                 }
  34.             }
  35.         }
  36.     }
  37.