12 [AddComponentMenu(
"UI/Extensions/Range Slider", 34)]
14 [RequireComponent(typeof(RectTransform))]
15 public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
22 private RectTransform m_FillRect;
24 public RectTransform
FillRect {
get {
return m_FillRect; }
set {
if (SetClass(ref m_FillRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
27 private RectTransform m_LowHandleRect;
29 public RectTransform
LowHandleRect {
get {
return m_LowHandleRect; }
set {
if (SetClass(ref m_LowHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
32 private RectTransform m_HighHandleRect;
34 public RectTransform
HighHandleRect {
get {
return m_HighHandleRect; }
set {
if (SetClass(ref m_HighHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
39 private float m_MinValue = 0;
41 public float MinValue {
get {
return m_MinValue; }
set {
if (SetStruct(ref m_MinValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
45 private float m_MaxValue = 1;
47 public float MaxValue {
get {
return m_MaxValue; }
set {
if (SetStruct(ref m_MaxValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
50 private bool m_WholeNumbers =
false;
52 public bool WholeNumbers {
get {
return m_WholeNumbers; }
set {
if (SetStruct(ref m_WholeNumbers, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
55 private float m_LowValue;
62 return Mathf.Round(m_LowValue);
91 private float m_HighValue;
98 return Mathf.Round(m_HighValue);
132 SetHigh(high,
false);
138 private RangeSliderEvent m_OnValueChanged =
new RangeSliderEvent();
147 private enum InteractionState
155 private InteractionState interactionState = InteractionState.None;
157 private Image m_FillImage;
158 private Transform m_FillTransform;
159 private RectTransform m_FillContainerRect;
160 private Transform m_HighHandleTransform;
161 private RectTransform m_HighHandleContainerRect;
162 private Transform m_LowHandleTransform;
163 private RectTransform m_LowHandleContainerRect;
166 private Vector2 m_LowOffset = Vector2.zero;
168 private Vector2 m_HighOffset = Vector2.zero;
170 private DrivenRectTransformTracker m_Tracker;
173 private bool m_DelayedUpdateVisuals =
false;
182 protected override void OnValidate()
188 m_MinValue = Mathf.Round(m_MinValue);
189 m_MaxValue = Mathf.Round(m_MaxValue);
194 UpdateCachedReferences();
195 SetLow(m_LowValue,
false);
196 SetHigh(m_HighValue,
false);
198 m_DelayedUpdateVisuals =
true;
201 if (!
UnityEditor.PrefabUtility.IsPartOfPrefabAsset(
this) && !Application.isPlaying)
203 CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(
this);
208 public virtual void Rebuild(CanvasUpdate executing)
211 if (executing == CanvasUpdate.Prelayout)
230 public static bool SetClass<T>(ref T currentValue, T newValue) where T :
class
232 if ((currentValue ==
null && newValue ==
null) || (currentValue !=
null && currentValue.Equals(newValue)))
235 currentValue = newValue;
239 public static bool SetStruct<T>(ref T currentValue, T newValue) where T :
struct
241 if (currentValue.Equals(newValue))
244 currentValue = newValue;
251 UpdateCachedReferences();
270 if (m_DelayedUpdateVisuals)
272 m_DelayedUpdateVisuals =
false;
279 base.OnDidApplyAnimationProperties();
282 void UpdateCachedReferences()
284 if (m_FillRect && m_FillRect != (RectTransform)transform)
286 m_FillTransform = m_FillRect.transform;
287 m_FillImage = m_FillRect.GetComponent<
Image>();
288 if (m_FillTransform.parent !=
null)
289 m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>();
294 m_FillContainerRect =
null;
298 if (m_HighHandleRect && m_HighHandleRect != (RectTransform)transform)
300 m_HighHandleTransform = m_HighHandleRect.transform;
301 if (m_HighHandleTransform.parent !=
null)
302 m_HighHandleContainerRect = m_HighHandleTransform.parent.GetComponent<RectTransform>();
306 m_HighHandleRect =
null;
307 m_HighHandleContainerRect =
null;
310 if (m_LowHandleRect && m_LowHandleRect != (RectTransform)transform)
312 m_LowHandleTransform = m_LowHandleRect.transform;
313 if (m_LowHandleTransform.parent !=
null)
315 m_LowHandleContainerRect = m_LowHandleTransform.parent.GetComponent<RectTransform>();
320 m_LowHandleRect =
null;
321 m_LowHandleContainerRect =
null;
325 void SetLow(
float input)
330 protected virtual void SetLow(
float input,
bool sendCallback)
336 newValue = Mathf.Round(newValue);
340 if (m_LowValue == newValue)
343 m_LowValue = newValue;
347 UISystemProfilerApi.AddMarker(
"RangeSlider.lowValue",
this);
348 m_OnValueChanged.Invoke(newValue,
HighValue);
352 void SetHigh(
float input)
354 SetHigh(input,
true);
357 protected virtual void SetHigh(
float input,
bool sendCallback)
363 newValue = Mathf.Round(newValue);
367 if (m_HighValue == newValue)
370 m_HighValue = newValue;
374 UISystemProfilerApi.AddMarker(
"RangeSlider.highValue",
this);
375 m_OnValueChanged.Invoke(
LowValue, newValue);
382 base.OnRectTransformDimensionsChange();
393 private void UpdateVisuals()
396 if (!Application.isPlaying)
397 UpdateCachedReferences();
402 if (m_FillContainerRect !=
null)
404 m_Tracker.Add(
this, m_FillRect, DrivenTransformProperties.Anchors);
405 Vector2 anchorMin = Vector2.zero;
406 Vector2 anchorMax = Vector2.one;
413 m_FillRect.anchorMin = anchorMin;
414 m_FillRect.anchorMax = anchorMax;
417 if (m_LowHandleContainerRect !=
null)
419 m_Tracker.Add(
this, m_LowHandleRect, DrivenTransformProperties.Anchors);
420 Vector2 anchorMin = Vector2.zero;
421 Vector2 anchorMax = Vector2.one;
423 m_LowHandleRect.anchorMin = anchorMin;
424 m_LowHandleRect.anchorMax = anchorMax;
427 if (m_HighHandleContainerRect !=
null)
429 m_Tracker.Add(
this, m_HighHandleRect, DrivenTransformProperties.Anchors);
430 Vector2 anchorMin = Vector2.zero;
431 Vector2 anchorMax = Vector2.one;
433 m_HighHandleRect.anchorMin = anchorMin;
434 m_HighHandleRect.anchorMax = anchorMax;
439 void UpdateDrag(PointerEventData eventData, Camera cam)
446 switch (interactionState)
448 case InteractionState.Low:
449 NormalizedLowValue = CalculateDrag(eventData, cam, m_LowHandleContainerRect, m_LowOffset);
451 case InteractionState.High:
452 NormalizedHighValue = CalculateDrag(eventData, cam, m_HighHandleContainerRect, m_HighOffset);
454 case InteractionState.Bar:
456 CalculateBarDrag(eventData, cam);
458 case InteractionState.None:
463 private float CalculateDrag(PointerEventData eventData, Camera cam, RectTransform containerRect, Vector2 offset)
465 RectTransform clickRect = containerRect ?? m_FillContainerRect;
466 if (clickRect !=
null && clickRect.rect.size[0] > 0)
469 if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
473 localCursor -= clickRect.rect.position;
475 float val = Mathf.Clamp01((localCursor - offset)[0] / clickRect.rect.size[0]);
482 private void CalculateBarDrag(PointerEventData eventData, Camera cam)
484 RectTransform clickRect = m_FillContainerRect;
485 if (clickRect !=
null && clickRect.rect.size[0] > 0)
488 if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
492 localCursor -= clickRect.rect.position;
502 float val = Mathf.Clamp01((localCursor)[0] / clickRect.rect.size[0]);
504 float delta = val - mid;
522 private bool MayDrag(PointerEventData eventData)
524 return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
529 if (!MayDrag(eventData))
534 m_LowOffset = m_HighOffset = Vector2.zero;
535 Vector2 localMousePos;
536 if (m_HighHandleRect !=
null && RectTransformUtility.RectangleContainsScreenPoint(m_HighHandleRect, eventData.position, eventData.enterEventCamera))
539 if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HighHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
541 m_HighOffset = localMousePos;
543 interactionState = InteractionState.High;
544 if (transition == Transition.ColorTint)
546 targetGraphic = m_HighHandleRect.GetComponent<Graphic>();
549 else if (m_LowHandleRect !=
null && RectTransformUtility.RectangleContainsScreenPoint(m_LowHandleRect, eventData.position, eventData.enterEventCamera))
552 if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_LowHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
554 m_LowOffset = localMousePos;
556 interactionState = InteractionState.Low;
557 if (transition == Transition.ColorTint)
559 targetGraphic = m_LowHandleRect.GetComponent<Graphic>();
565 UpdateDrag(eventData, eventData.pressEventCamera);
566 interactionState = InteractionState.Bar;
567 if (transition == Transition.ColorTint)
569 targetGraphic = m_FillImage;
572 base.OnPointerDown(eventData);
575 public virtual void OnDrag(PointerEventData eventData)
577 if (!MayDrag(eventData))
581 UpdateDrag(eventData, eventData.pressEventCamera);
586 base.OnPointerUp(eventData);
587 interactionState = InteractionState.None;
590 public override void OnMove(AxisEventData eventData)
597 eventData.useDragThreshold =
false;
System.Drawing.Image Image
override void OnDidApplyAnimationProperties()
virtual void OnInitializePotentialDrag(PointerEventData eventData)
override void OnRectTransformDimensionsChange()
override void OnDisable()
virtual void Rebuild(CanvasUpdate executing)
virtual void SetLow(float input, bool sendCallback)
RangeSliderEvent OnValueChanged
static bool SetClass< T >(ref T currentValue, T newValue)
virtual void SetValueWithoutNotify(float low, float high)
Set the value of the slider without invoking onValueChanged callback.
RectTransform HighHandleRect
RectTransform LowHandleRect
float NormalizedHighValue
override void OnPointerUp(PointerEventData eventData)
override void OnPointerDown(PointerEventData eventData)
virtual void GraphicUpdateComplete()
See ICanvasElement.GraphicUpdateComplete
virtual void SetHigh(float input, bool sendCallback)
static bool SetStruct< T >(ref T currentValue, T newValue)
virtual void OnDrag(PointerEventData eventData)
override void OnMove(AxisEventData eventData)
virtual void LayoutComplete()
See ICanvasElement.LayoutComplete
virtual void Update()
Update the rect based on the delayed update visuals. Got around issue of calling sendMessage from onV...
Credit Erdener Gonenc - @PixelEnvision.