173 lines
6.5 KiB
C#
173 lines
6.5 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace UVC.UI.List.Draggable
|
|
{
|
|
/// <summary>
|
|
/// 드래그 중 화면 가장자리에서 자동으로 스크롤하는 기능을 제공합니다.
|
|
/// ScrollRect와 함께 사용되어 긴 리스트에서도 드래그 앤 드롭이 가능하게 합니다.
|
|
///
|
|
/// 필수 설정:
|
|
/// 1. ScrollRect 컴포넌트가 있는 GameObject에 추가합니다.
|
|
///
|
|
/// Inspector 설정:
|
|
/// - Scroll Zone Height: 자동 스크롤이 시작되는 영역의 높이 (픽셀)
|
|
/// - Scroll Speed: 스크롤 속도
|
|
///
|
|
/// 사용 예시:
|
|
/// scrollHandler.EnableAutoScroll(true); // 자동 스크롤 시작
|
|
/// scrollHandler.EnableAutoScroll(false); // 자동 스크롤 중지
|
|
/// </summary>
|
|
[RequireComponent(typeof(ScrollRect))]
|
|
public class ScrollRectHandler : MonoBehaviour
|
|
{
|
|
[Header("자동 스크롤 설정")]
|
|
[SerializeField]
|
|
[Tooltip("화면 가장자리에서 이 거리(픽셀) 안에 마우스가 있으면 자동 스크롤이 시작됩니다")]
|
|
private float scrollZoneHeight = 50f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("자동 스크롤 속도 (픽셀/초)")]
|
|
private float scrollSpeed = 600f;
|
|
|
|
// ScrollRect 컴포넌트 참조
|
|
private ScrollRect? scrollRect;
|
|
|
|
// 자동 스크롤 코루틴 참조
|
|
private Coroutine? autoScrollCoroutine;
|
|
|
|
/// <summary>
|
|
/// 컴포넌트 초기화
|
|
/// </summary>
|
|
void Awake()
|
|
{
|
|
scrollRect = GetComponent<ScrollRect>();
|
|
|
|
if (scrollRect == null)
|
|
{
|
|
Debug.LogError($"[ScrollRectHandler] ScrollRect 컴포넌트를 찾을 수 없습니다! - {gameObject.name}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 자동 스크롤을 활성화하거나 비활성화합니다
|
|
/// </summary>
|
|
/// <param name="enable">true: 활성화, false: 비활성화</param>
|
|
public void EnableAutoScroll(bool enable)
|
|
{
|
|
if (scrollRect == null) return;
|
|
|
|
if (enable)
|
|
{
|
|
// 드래그 중에는 ScrollRect의 기본 드래그를 비활성화합니다
|
|
scrollRect.enabled = false;
|
|
|
|
// 자동 스크롤 코루틴을 시작합니다
|
|
if (autoScrollCoroutine == null)
|
|
{
|
|
autoScrollCoroutine = StartCoroutine(AutoScrollRoutine());
|
|
//Debug.Log("[ScrollRectHandler] 자동 스크롤 시작");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ScrollRect를 다시 활성화합니다
|
|
scrollRect.enabled = true;
|
|
|
|
// 자동 스크롤 코루틴을 중지합니다
|
|
if (autoScrollCoroutine != null)
|
|
{
|
|
StopCoroutine(autoScrollCoroutine);
|
|
autoScrollCoroutine = null;
|
|
//Debug.Log("[ScrollRectHandler] 자동 스크롤 중지");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 자동 스크롤을 처리하는 코루틴
|
|
/// 마우스가 화면 가장자리에 있을 때 스크롤을 자동으로 움직입니다
|
|
/// </summary>
|
|
private IEnumerator AutoScrollRoutine()
|
|
{
|
|
if (scrollRect == null) yield break;
|
|
|
|
var scrollTransform = scrollRect.GetComponent<RectTransform>();
|
|
if (scrollTransform == null) yield break;
|
|
|
|
// 스크롤 영역의 모서리 좌표를 저장할 배열
|
|
Vector3[] corners = new Vector3[4];
|
|
|
|
while (true)
|
|
{
|
|
// ScrollRect의 월드 좌표 모서리를 가져옵니다
|
|
// corners[0]: 왼쪽 아래, corners[1]: 왼쪽 위, corners[2]: 오른쪽 위, corners[3]: 오른쪽 아래
|
|
scrollTransform.GetWorldCorners(corners);
|
|
|
|
float mouseY = Input.mousePosition.y;
|
|
float topY = corners[1].y; // 위쪽 가장자리 Y 좌표
|
|
float bottomY = corners[0].y; // 아래쪽 가장자리 Y 좌표
|
|
float scrollDelta = 0f;
|
|
|
|
// 마우스가 위쪽 가장자리 근처에 있으면 위로 스크롤
|
|
if (mouseY > topY - scrollZoneHeight && mouseY <= topY)
|
|
{
|
|
// 가장자리에 가까울수록 빠르게 스크롤
|
|
float normalizedDistance = (topY - mouseY) / scrollZoneHeight;
|
|
scrollDelta = scrollSpeed * (1f - normalizedDistance) * Time.deltaTime;
|
|
|
|
//Debug.Log($"[ScrollRectHandler] 위로 스크롤 중... 속도: {scrollDelta}");
|
|
}
|
|
// 마우스가 아래쪽 가장자리 근처에 있으면 아래로 스크롤
|
|
else if (mouseY < bottomY + scrollZoneHeight && mouseY >= bottomY)
|
|
{
|
|
// 가장자리에 가까울수록 빠르게 스크롤
|
|
float normalizedDistance = (mouseY - bottomY) / scrollZoneHeight;
|
|
scrollDelta = -scrollSpeed * (1f - normalizedDistance) * Time.deltaTime;
|
|
|
|
//Debug.Log($"[ScrollRectHandler] 아래로 스크롤 중... 속도: {scrollDelta}");
|
|
}
|
|
|
|
// 스크롤 적용
|
|
if (Mathf.Abs(scrollDelta) > 0.01f)
|
|
{
|
|
// 스크롤 델타를 정규화된 값으로 변환 (0~1 범위)
|
|
float normalized = scrollDelta / scrollRect.content.rect.height;
|
|
|
|
// 새로운 스크롤 위치 계산 (0~1 범위로 제한)
|
|
scrollRect.verticalNormalizedPosition = Mathf.Clamp01(
|
|
scrollRect.verticalNormalizedPosition + normalized
|
|
);
|
|
}
|
|
|
|
// 다음 프레임까지 대기
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 자동 스크롤이 활성화되어 있는지 확인합니다
|
|
/// </summary>
|
|
/// <returns>자동 스크롤이 활성화되어 있으면 true</returns>
|
|
public bool IsAutoScrolling()
|
|
{
|
|
return autoScrollCoroutine != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 컴포넌트가 비활성화될 때 자동 스크롤을 중지합니다
|
|
/// </summary>
|
|
void OnDisable()
|
|
{
|
|
EnableAutoScroll(false);
|
|
}
|
|
}
|
|
}
|