diff options
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Slider.cs')
-rw-r--r-- | Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Slider.cs | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Slider.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Slider.cs new file mode 100644 index 0000000..4aad4e8 --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Slider.cs @@ -0,0 +1,450 @@ +using System; +using UnityEngine.Events; +using UnityEngine.EventSystems; + +namespace UnityEngine.UI +{ + [AddComponentMenu("UI/Slider", 33)] + [RequireComponent(typeof(RectTransform))] + public class Slider + : Selectable + , IDragHandler + , IInitializePotentialDragHandler // 拖拽之前 + , ICanvasElement // 编辑器下才会用到 + { + public enum Direction + { + LeftToRight, + RightToLeft, + BottomToTop, + TopToBottom, + } + + [Serializable] + public class SliderEvent : UnityEvent<float> {} + + [SerializeField] + private RectTransform m_FillRect; + public RectTransform fillRect { get { return m_FillRect; } set { if (SetPropertyUtility.SetClass(ref m_FillRect, value)) {UpdateCachedReferences(); UpdateVisuals(); } } } + + [SerializeField] + private RectTransform m_HandleRect; + public RectTransform handleRect { get { return m_HandleRect; } set { if (SetPropertyUtility.SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } } + + [Space] + + [SerializeField] + private Direction m_Direction = Direction.LeftToRight; + public Direction direction { get { return m_Direction; } set { if (SetPropertyUtility.SetStruct(ref m_Direction, value)) UpdateVisuals(); } } + + [SerializeField] + private float m_MinValue = 0; + public float minValue { get { return m_MinValue; } set { if (SetPropertyUtility.SetStruct(ref m_MinValue, value)) { Set(m_Value); UpdateVisuals(); } } } + + [SerializeField] + private float m_MaxValue = 1; + public float maxValue { get { return m_MaxValue; } set { if (SetPropertyUtility.SetStruct(ref m_MaxValue, value)) { Set(m_Value); UpdateVisuals(); } } } + + [SerializeField] + private bool m_WholeNumbers = false; + public bool wholeNumbers { get { return m_WholeNumbers; } set { if (SetPropertyUtility.SetStruct(ref m_WholeNumbers, value)) { Set(m_Value); UpdateVisuals(); } } } + + [SerializeField] + protected float m_Value; + public virtual float value + { + get + { + if (wholeNumbers) + return Mathf.Round(m_Value); + return m_Value; + } + set + { + Set(value); + } + } + + public float normalizedValue + { + get + { + if (Mathf.Approximately(minValue, maxValue)) + return 0; + return Mathf.InverseLerp(minValue, maxValue, value); + } + set + { + this.value = Mathf.Lerp(minValue, maxValue, value); + } + } + + [Space] + + // Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers. + [SerializeField] + private SliderEvent m_OnValueChanged = new SliderEvent(); + public SliderEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } } + + // Private fields + + private Image m_FillImage; + private Transform m_FillTransform; + private RectTransform m_FillContainerRect; + private Transform m_HandleTransform; + private RectTransform m_HandleContainerRect; + + // The offset from handle position to mouse down position + private Vector2 m_Offset = Vector2.zero; + + private DrivenRectTransformTracker m_Tracker; + + // Size of each step. + float stepSize { get { return wholeNumbers ? 1 : (maxValue - minValue) * 0.1f; } } // 1/10十分之一 + + protected Slider() + {} + +#if UNITY_EDITOR + protected override void OnValidate() + { + base.OnValidate(); + + if (wholeNumbers) + { + m_MinValue = Mathf.Round(m_MinValue); + m_MaxValue = Mathf.Round(m_MaxValue); + } + + //Onvalidate is called before OnEnabled. We need to make sure not to touch any other objects before OnEnable is run. + if (IsActive()) + { + UpdateCachedReferences(); + Set(m_Value, false); + // Update rects since other things might affect them even if value didn't change. + UpdateVisuals(); + } + + var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this); + if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying) + CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this); + } + +#endif // if UNITY_EDITOR + + public virtual void Rebuild(CanvasUpdate executing) + { +#if UNITY_EDITOR + if (executing == CanvasUpdate.Prelayout) + onValueChanged.Invoke(value); +#endif + } + + public virtual void LayoutComplete() + {} + + public virtual void GraphicUpdateComplete() + {} + + protected override void OnEnable() + { + base.OnEnable(); + UpdateCachedReferences(); + Set(m_Value, false); + // Update rects since they need to be initialized correctly. + UpdateVisuals(); + } + + protected override void OnDisable() + { + m_Tracker.Clear(); + base.OnDisable(); + } + + protected override void OnDidApplyAnimationProperties() + { + // Has value changed? Various elements of the slider have the old normalisedValue assigned, we can use this to perform a comparison. + // We also need to ensure the value stays within min/max. + m_Value = ClampValue(m_Value); + float oldNormalizedValue = normalizedValue; + if (m_FillContainerRect != null) + { + if (m_FillImage != null && m_FillImage.type == Image.Type.Filled) + oldNormalizedValue = m_FillImage.fillAmount; + else + oldNormalizedValue = (reverseValue ? 1 - m_FillRect.anchorMin[(int)axis] : m_FillRect.anchorMax[(int)axis]); + } + else if (m_HandleContainerRect != null) + oldNormalizedValue = (reverseValue ? 1 - m_HandleRect.anchorMin[(int)axis] : m_HandleRect.anchorMin[(int)axis]); + + UpdateVisuals(); + + if (oldNormalizedValue != normalizedValue) + { + UISystemProfilerApi.AddMarker("Slider.value", this); + onValueChanged.Invoke(m_Value); + } + } + + void UpdateCachedReferences() + { + if (m_FillRect) + { + m_FillTransform = m_FillRect.transform; + m_FillImage = m_FillRect.GetComponent<Image>(); + if (m_FillTransform.parent != null) + m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>(); + } + else + { + m_FillContainerRect = null; + m_FillImage = null; + } + + if (m_HandleRect) + { + m_HandleTransform = m_HandleRect.transform; + if (m_HandleTransform.parent != null) + m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>(); + } + else + { + m_HandleContainerRect = null; + } + } + + float ClampValue(float input) + { + float newValue = Mathf.Clamp(input, minValue, maxValue); + if (wholeNumbers) + newValue = Mathf.Round(newValue); + return newValue; + } + + // Set the valueUpdate the visible Image. + void Set(float input) + { + Set(input, true); + } + + protected virtual void Set(float input, bool sendCallback) + { + // Clamp the input + float newValue = ClampValue(input); + + // If the stepped value doesn't match the last one, it's time to update + if (m_Value == newValue) + return; + + m_Value = newValue; + UpdateVisuals(); + if (sendCallback) + { + UISystemProfilerApi.AddMarker("Slider.value", this); + m_OnValueChanged.Invoke(newValue); + } + } + + protected override void OnRectTransformDimensionsChange() + { + base.OnRectTransformDimensionsChange(); + + //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called. + if (!IsActive()) + return; + + UpdateVisuals(); + } + + enum Axis + { + Horizontal = 0, + Vertical = 1 + } + + Axis axis { get { return (m_Direction == Direction.LeftToRight || m_Direction == Direction.RightToLeft) ? Axis.Horizontal : Axis.Vertical; } } + bool reverseValue { get { return m_Direction == Direction.RightToLeft || m_Direction == Direction.TopToBottom; } } + + // Force-update the slider. Useful if you've changed the properties and want it to update visually. + private void UpdateVisuals() + { + LogHelper.Log("UpdateVisuals"); + +#if UNITY_EDITOR + if (!Application.isPlaying) + UpdateCachedReferences(); +#endif + + m_Tracker.Clear(); + + if (m_FillContainerRect != null) + { + m_Tracker.Add(this, m_FillRect, DrivenTransformProperties.Anchors); + Vector2 anchorMin = Vector2.zero; + Vector2 anchorMax = Vector2.one; + + if (m_FillImage != null && m_FillImage.type == Image.Type.Filled) + { + m_FillImage.fillAmount = normalizedValue; + } + else + { + if (reverseValue) + anchorMin[(int)axis] = 1 - normalizedValue; + else + anchorMax[(int)axis] = normalizedValue; + } + + m_FillRect.anchorMin = anchorMin; + m_FillRect.anchorMax = anchorMax; + } + + if (m_HandleContainerRect != null) + { + m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors); + Vector2 anchorMin = Vector2.zero; + Vector2 anchorMax = Vector2.one; + anchorMin[(int)axis] = anchorMax[(int)axis] = (reverseValue ? (1 - normalizedValue) : normalizedValue); + m_HandleRect.anchorMin = anchorMin; + m_HandleRect.anchorMax = anchorMax; + } + } + + // Update the slider's position based on the mouse. + void UpdateDrag(PointerEventData eventData, Camera cam) + { + RectTransform clickRect = m_HandleContainerRect ?? m_FillContainerRect; + if (clickRect != null && clickRect.rect.size[(int)axis] > 0) + { + Vector2 localCursor; + if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor)) + return; + localCursor -= clickRect.rect.position; + + float val = Mathf.Clamp01((localCursor - m_Offset)[(int)axis] / clickRect.rect.size[(int)axis]); + normalizedValue = (reverseValue ? 1f - val : val); + } + } + + private bool MayDrag(PointerEventData eventData) + { + return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left; + } + + public override void OnPointerDown(PointerEventData eventData) + { + if (!MayDrag(eventData)) + return; + + base.OnPointerDown(eventData); + + m_Offset = Vector2.zero; + if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera)) + { + Vector2 localMousePos; + if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos)) + m_Offset = localMousePos; + } + else + { + // Outside the slider handle - jump to this point instead + UpdateDrag(eventData, eventData.pressEventCamera); + } + } + + public virtual void OnDrag(PointerEventData eventData) + { + LogHelper.Log("OnDrag() " + gameObject.name); + if (!MayDrag(eventData)) + return; + UpdateDrag(eventData, eventData.pressEventCamera); + } + + public override void OnMove(AxisEventData eventData) + { + if (!IsActive() || !IsInteractable()) + { + base.OnMove(eventData); + return; + } + + switch (eventData.moveDir) + { + case MoveDirection.Left: + if (axis == Axis.Horizontal && FindSelectableOnLeft() == null) + Set(reverseValue ? value + stepSize : value - stepSize); + else + base.OnMove(eventData); + break; + case MoveDirection.Right: + if (axis == Axis.Horizontal && FindSelectableOnRight() == null) + Set(reverseValue ? value - stepSize : value + stepSize); + else + base.OnMove(eventData); + break; + case MoveDirection.Up: + if (axis == Axis.Vertical && FindSelectableOnUp() == null) + Set(reverseValue ? value - stepSize : value + stepSize); + else + base.OnMove(eventData); + break; + case MoveDirection.Down: + if (axis == Axis.Vertical && FindSelectableOnDown() == null) + Set(reverseValue ? value + stepSize : value - stepSize); + else + base.OnMove(eventData); + break; + } + } + + public override Selectable FindSelectableOnLeft() + { + if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal) + return null; + return base.FindSelectableOnLeft(); + } + + public override Selectable FindSelectableOnRight() + { + if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal) + return null; + return base.FindSelectableOnRight(); + } + + public override Selectable FindSelectableOnUp() + { + if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical) + return null; + return base.FindSelectableOnUp(); + } + + public override Selectable FindSelectableOnDown() + { + if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical) + return null; + return base.FindSelectableOnDown(); + } + + // + public virtual void OnInitializePotentialDrag(PointerEventData eventData) + { + eventData.useDragThreshold = false; + } + + public void SetDirection(Direction direction, bool includeRectLayouts) + { + Axis oldAxis = axis; + bool oldReverse = reverseValue; + this.direction = direction; + + if (!includeRectLayouts) + return; + + if (axis != oldAxis) + RectTransformUtility.FlipLayoutAxes(transform as RectTransform, true, true); + + if (reverseValue != oldReverse) + RectTransformUtility.FlipLayoutOnAxis(transform as RectTransform, (int)axis, true, true); + } + } +} |