드래그 어긋나는거 수정

This commit is contained in:
logonkhi
2025-11-18 18:14:53 +09:00
parent f58b456ccb
commit fa774babea
43 changed files with 6819 additions and 358 deletions

View File

@@ -12,6 +12,7 @@ namespace SHI.modal
{
[SerializeField, Range(0.0f, 0.5f)] private float minLeftWeight = 0.1f;
[SerializeField, Range(0.5f, 1.0f)] private float maxLeftWeight = 0.9f;
[SerializeField] private bool useActualWidthForHandle = true; // 실제 패널 폭 기준 위치 보정
private RectTransform _left;
private RectTransform _right;
@@ -47,6 +48,7 @@ namespace SHI.modal
RefreshPosition();
}
/// <inheritdoc />
public void OnBeginDrag(PointerEventData eventData)
{
@@ -54,6 +56,23 @@ namespace SHI.modal
if (_handleRect != null) _handleY = _handleRect.anchoredPosition.y;
}
/// <summary>
/// 부모 RectTransform pivot을 고려한 작업 영역 좌/우 경계 계산.
/// </summary>
private void GetWorkArea(out float minX, out float maxX, out float leftOffset)
{
minX = maxX = leftOffset = 0f;
if (_parent == null) return;
float width = _parent.rect.width;
var pivot = _parent.pivot; // (0..1)
float pivotOrigin = -width * pivot.x; // local 좌표계에서 좌측 경계
leftOffset = 0f;
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
leftOffset = _leftFixedPanel.rect.width; // 고정 패널 폭만큼 이동
minX = pivotOrigin + leftOffset;
maxX = pivotOrigin + width; // 우측 경계 (handle 중심 좌표)
}
/// <inheritdoc />
public void OnDrag(PointerEventData eventData)
{
@@ -61,66 +80,80 @@ namespace SHI.modal
Vector2 local;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_parent, eventData.position, eventData.pressEventCamera, out local))
return;
float width = _parent.rect.width;
if (width <= 0f) return;
// 좌측 고정 패널(보이는 경우)의 폭만큼 좌측 경계를 오른쪽으로 이동
float leftOffset = 0f;
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
{
leftOffset = _leftFixedPanel.rect.width;
}
float minX, maxX, leftOffset;
GetWorkArea(out minX, out maxX, out leftOffset);
float minX = -width * 0.5f + leftOffset; // 작업 영역 좌측 경계
float maxX = width * 0.5f; // 작업 영역 우측 경계
// 현재 포인터 위치를 작업 영역 비율[0..1]로 변환 후 범위 제한
// 드래그 포인터를 작업 영역으로 정규화하여 [0..1] 비율 t 산출
float t = Mathf.InverseLerp(minX, maxX, local.x);
t = Mathf.Clamp01(t);
// LayoutElement 비율 (가변 범위)
// 가변 비율 계산 (minLeftWeight~maxLeftWeight 범위)
float leftWeight = Mathf.Lerp(minLeftWeight, maxLeftWeight, t);
float rightWeight = Mathf.Max(0.0001f, 1f - leftWeight);
_leftLayout.flexibleWidth = leftWeight;
_rightLayout.flexibleWidth = rightWeight;
// 스플리터 핸들도 같은 좌표계에서 이동
if (_handleRect != null)
// 레이아웃 즉시 반영 후 실제 폭 기준 위치 재계산
Canvas.ForceUpdateCanvases();
UpdateHandlePositionFromActualWidths(minX, maxX);
}
/// <summary>
/// 실제 패널 폭을 사용해 핸들 위치를 경계선(왼쪽 패널 오른쪽 끝)에 정렬.
/// 레이아웃 그룹 padding/spacing, 고정 패널 폭을 모두 반영.
/// </summary>
private void UpdateHandlePositionFromActualWidths(float minX, float maxX)
{
if (_handleRect == null || _parent == null || _left == null) return;
if (!useActualWidthForHandle)
{
float clampedX = Mathf.Lerp(minX, maxX, Mathf.InverseLerp(minLeftWeight, maxLeftWeight, leftWeight));
_handleRect.anchoredPosition = new Vector2(clampedX, _handleY);
// 기존 비율 방식 (보정 없이)
float totalFlex = Mathf.Max(0.0001f, _leftLayout.flexibleWidth + _rightLayout.flexibleWidth);
float leftWeight = Mathf.Clamp01(_leftLayout.flexibleWidth / totalFlex);
float normalized = Mathf.InverseLerp(minLeftWeight, maxLeftWeight, Mathf.Clamp(leftWeight, minLeftWeight, maxLeftWeight));
float xRatio = Mathf.Lerp(minX, maxX, normalized);
_handleRect.anchoredPosition = new Vector2(xRatio, _handleY);
return;
}
// 고정 패널 폭 + 가변 왼쪽 패널 실제 폭 = 경계 픽셀
float fixedWidth = (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf) ? _leftFixedPanel.rect.width : 0f;
float variableLeftWidth = _left.rect.width; // 레이아웃 적용 후 실제 계산된 폭
// 부모 pivot 기반 local 좌표 좌측 경계
float widthParent = _parent.rect.width;
float origin = -widthParent * _parent.pivot.x;
float boundaryX = origin + fixedWidth + variableLeftWidth;
// 핸들 자체 폭 중앙 정렬 (핸들 pivot이 중앙이라고 가정)
// 경계 근처에서 과도한 이동 방지 (clamp)
float halfHandle = _handleRect.rect.width * 0.5f;
float minCenter = origin + fixedWidth + halfHandle; // 최소 중앙: 고정 패널 끝 + 반 핸들
float maxCenter = origin + widthParent - halfHandle; // 최대 중앙: 부모 우측 - 반 핸들
float centerX = Mathf.Clamp(boundaryX, minCenter, maxCenter);
_handleRect.anchoredPosition = new Vector2(centerX, _handleY);
}
/// <summary>
/// 현재 레이아웃 상태에 맞게 드래그 핸들의 위치를 동기화합니다.
/// (레이아웃/가시성 변경 이후 호출 권장)
/// </summary>
public void RefreshPosition()
{
if (_parent == null || _handleRect == null || _leftLayout == null || _rightLayout == null)
return;
if (_parent == null || _handleRect == null || _leftLayout == null || _rightLayout == null) return;
float width = _parent.rect.width;
if (width <= 0f) return;
float leftOffset = 0f;
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
leftOffset = _leftFixedPanel.rect.width;
float minX, maxX, leftOffset;
GetWorkArea(out minX, out maxX, out leftOffset);
float minX = -width * 0.5f + leftOffset;
float maxX = width * 0.5f;
float totalFlex = Mathf.Max(0.0001f, _leftLayout.flexibleWidth + _rightLayout.flexibleWidth);
float leftWeight = Mathf.Clamp01(_leftLayout.flexibleWidth / totalFlex);
leftWeight = Mathf.Clamp(leftWeight, minLeftWeight, maxLeftWeight);
if (_handleRect != null)
{
_handleRect.anchoredPosition = new Vector2(Mathf.Lerp(minX, maxX, Mathf.InverseLerp(minLeftWeight, maxLeftWeight, leftWeight)), _handleY);
}
Canvas.ForceUpdateCanvases();
UpdateHandlePositionFromActualWidths(minX, maxX);
}
private void LateUpdate()
{
bool nowActive = _leftFixedPanel != null && _leftFixedPanel.gameObject.activeInHierarchy;

View File

@@ -480,7 +480,7 @@ namespace SHI.modal
if (!EnsureUIDocument()) return;
var rt = GetComponent<RectTransform>(); if (rt == null) return;
var canvas = GetComponentInParent<Canvas>();
Camera cam = null;
Camera? cam = null;
if (canvas != null)
{
if (canvas.renderMode == RenderMode.ScreenSpaceCamera || canvas.renderMode == RenderMode.WorldSpace)
@@ -505,7 +505,7 @@ namespace SHI.modal
// React to RectTransform size changes
private void OnRectTransformDimensionsChange()
{
{
SyncContainerSize();
SyncContainerPosition();
}