using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace Superlazy.UI { public class SLUIScrollRect : SLUIComponent, IBeginDragHandler, IEndDragHandler, IDragHandler { public bool snap = false; public float itemSize; public string indexBind; public string stateBind; private ScrollRect scrollRect; private RectTransform container; private bool snapping; private Vector2 snapTargetPosition; private bool dragging = false; private int index = -1; // 나중에 휘리릭용으로 사용할 예정 //private Vector2 positionOnDragStart = Vector3.zero; protected override void Validate() { scrollRect = gameObject.GetComponent(); } protected override void Init() { container = scrollRect.content; } protected override void Enable() { if (snap) { snapping = false; dragging = false; index = -1; if (indexBind != string.Empty) { SLGame.AddNotify(bindParent.BindPath.CombinePath(indexBind), OnChangeIndex); OnChangeIndex(); container.anchoredPosition = snapTargetPosition; } else { container.anchoredPosition = Vector2.zero; } if (stateBind != string.Empty) { SLGame.SessionGet(bindParent.BindPath).Set(stateBind, "Idle"); } } } protected override void Disable() { if (snap) { snapping = false; dragging = false; index = -1; if (indexBind != string.Empty) { SLGame.RemoveNotify(bindParent.BindPath.CombinePath(indexBind), OnChangeIndex); } if (stateBind != string.Empty) { SLGame.SessionGet(bindParent.BindPath).Set(stateBind, false); } } } private void OnChangeIndex() { if (snap == false) return; var newIndex = SLGame.SessionGet(bindParent.BindPath).Get(indexBind); if (newIndex == false && index == -1) return; // 삭제 관련 예외 if (index == newIndex) return; index = newIndex; snapping = true; // anchoredPosition은 -로 가기때문에 인덱스 자체는 -로 세팅해야함 // 나중에는 확장가능성 생각해서 추가 개선 snapTargetPosition = scrollRect.horizontal ? new Vector2(-newIndex * itemSize, container.anchoredPosition.y) : new Vector2(container.anchoredPosition.x, -newIndex * itemSize); if (stateBind != string.Empty) { SLGame.SessionGet(bindParent.BindPath).Set(stateBind, "Snapping"); } } public void ResetPage() { if (scrollRect.horizontal) { scrollRect.horizontalNormalizedPosition = 0; } else { scrollRect.verticalNormalizedPosition = 0; } } private void LateUpdate() { if (snapping) { scrollRect.StopMovement(); container.anchoredPosition = Vector2.Lerp(container.anchoredPosition, snapTargetPosition, 0.5f); if (Vector3.Distance(container.anchoredPosition, snapTargetPosition) < 5f) { container.anchoredPosition = snapTargetPosition; snapping = false; if (stateBind != string.Empty) { SLGame.SessionGet(bindParent.BindPath).Set(stateBind, "Idle"); } } } } public void OnBeginDrag(PointerEventData eventData) { if (snap == false) return; //positionOnDragStart = eventData.position; } public void OnEndDrag(PointerEventData eventData) { if (snap == false) return; dragging = false; if (bindParent.BindPath != string.Empty) { // 바인딩 패스가 있다면 값을 바꿔서 OnChange를 불리게하는쪽으로 일원화 index = -1; // anchoredPosition은 -로 가기때문에 인덱스 자체는 -로 세팅해야함 // 나중에는 확장가능성 생각해서 추가 개선 if (scrollRect.horizontal) { SLGame.SessionGet(bindParent.BindPath).Set(indexBind, Mathf.Clamp(-Mathf.RoundToInt(container.anchoredPosition.x / itemSize), 0, container.sizeDelta.x / itemSize)); } else { SLGame.SessionGet(bindParent.BindPath).Set(indexBind, Mathf.Clamp(Mathf.RoundToInt(container.anchoredPosition.y / itemSize), 0, container.sizeDelta.y / itemSize)); } } else { // 별도의 바인딩패스를 사용하지 않는 구성 snapping = true; snapTargetPosition = scrollRect.horizontal ? new Vector2(Mathf.Clamp(Mathf.Round(container.anchoredPosition.x / itemSize) * itemSize, -container.sizeDelta.x, 0), container.anchoredPosition.y) : new Vector2(container.anchoredPosition.x, Mathf.Clamp(Mathf.Round(container.anchoredPosition.y / itemSize) * itemSize, 0, container.anchoredPosition.y)); } } public void OnDrag(PointerEventData eventData) { if (snap == false) return; snapping = false; if (dragging == false) { OnBeginDrag(eventData); dragging = true; SLGame.SessionGet(bindParent.BindPath).Set(stateBind, "Dragging"); } } public void StartScreenChange() { } } }