NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/UI/DirectDragHandler.cs

373 lines
10 KiB
C#
Raw Normal View History

2025-05-13 15:12:46 +08:00
using System;
using UnityEngine;
using UnityEngine.UI;
public class DirectDragHandler : MonoBehaviour
{
[Tooltip("是否在拖拽时限制移动范围")]
public bool restrictMovement = false;
[Tooltip("拖拽范围限制(如果启用限制)")]
public RectTransform movementBounds;
[Tooltip("是否锁定垂直方向移动")]
public bool lockVertical = false;
[Tooltip("是否锁定水平方向移动")]
public bool lockHorizontal = false;
[Tooltip("拖拽时是否改变视觉效果")]
public bool changeDragAppearance = true;
[Tooltip("拖拽时的缩放")]
public Vector3 dragScale = new Vector3(1.1f, 1.1f, 1.1f);
// 原始位置和缩放
private Vector3 originalPosition;
private Vector3 originalScale;
private RectTransform rectTransform;
2025-05-13 19:51:22 +08:00
private float scaleFactor;
2025-05-13 15:12:46 +08:00
// 拖拽状态
private bool isDragging = false;
2025-06-12 14:42:46 +08:00
[SerializeField]
2025-05-13 15:12:46 +08:00
private ButtonUpDrag buttonUpDrag;
private ScrollRect parentScrollRect;
/// <summary>
/// 检测拖拽位置是否可以放置
/// </summary>
private Func<Vector2, bool> checkValidFunction;
private Action onStartDrag;
private Action onEndDrag;
/// <summary>
/// 接收原始位置并返回调整后位置的函数
/// </summary>
private Func<Vector2, Vector2> positionAdjuster;
/// <summary>
/// 处理成功放置逻辑的函数
/// </summary>
private Action<Vector2> placementHandler;
/// <summary>
/// 处理拖拽过程中检测的函数
/// </summary>
private Action<Vector2> dragUpdateHandler;
2025-07-30 16:45:51 +08:00
/// <summary>
/// 拖拽按下事件处理器
/// </summary>
private Action onPointDownHandler;
/// <summary>
/// 拖拽松开事件处理器
/// </summary>
private Action onPointUpHandler;
/// <summary>
/// 取消长按事件处理器
/// </summary>
private Action onCancelLongPress;
2025-07-30 16:45:51 +08:00
2025-05-13 15:12:46 +08:00
/// <summary>
/// 是否启用拖拽功能
/// </summary>
private bool isDraggableEnabled = true;
/// <summary>是否处于长按已触发后的拖拽中(供外部与 ScrollRect 锁定等逻辑配合)。</summary>
public bool IsDragging => isDragging;
2025-05-13 15:12:46 +08:00
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
if (buttonUpDrag == null)
{
Debug.LogError("DirectDragHandler需要ButtonUpDrag组件!");
return;
}
// 注册长按事件
buttonUpDrag.AddLongPress(OnStartDrag);
buttonUpDrag.AddLongPressCancel(OnLongPressCancel);
2025-07-30 16:45:51 +08:00
buttonUpDrag.AddPointerDown(OnPointDown);
buttonUpDrag.AddPointerUp(OnPointUp);
2025-05-13 15:12:46 +08:00
}
public void Init(Func<Vector2, bool> checkValidFunction, Action onStartDrag, Action onEndDrag)
{
this.checkValidFunction = checkValidFunction;
this.onStartDrag = onStartDrag;
this.onEndDrag = onEndDrag;
2025-05-30 14:37:04 +08:00
// 查找父级ScrollRect
parentScrollRect = GetComponentInParent<ScrollRect>();
2025-05-13 15:12:46 +08:00
}
/// <summary>
/// 设置位置调整处理器
/// </summary>
/// <param name="positionAdjuster">接收原始位置并返回调整后位置的函数</param>
public void SetPositionAdjuster(Func<Vector2, Vector2> positionAdjuster)
{
this.positionAdjuster = positionAdjuster;
}
/// <summary>
/// 设置成功放置处理器
/// </summary>
/// <param name="placementHandler">处理成功放置逻辑的函数</param>
public void SetPlacementHandler(Action<Vector2> placementHandler)
{
this.placementHandler = placementHandler;
}
/// <summary>
/// 设置拖拽过程中的位置检测处理器
/// </summary>
/// <param name="dragUpdateHandler">在拖拽过程中处理位置检测的函数</param>
public void SetDragUpdateHandler(Action<Vector2> dragUpdateHandler)
{
this.dragUpdateHandler = dragUpdateHandler;
}
2025-07-30 16:45:51 +08:00
public void SetPointDownHandler(Action pointDownCallback, Action pointUpCallback)
{
this.onPointDownHandler = pointDownCallback;
this.onPointUpHandler = pointUpCallback;
}
/// <summary>
/// 设置取消长按处理器
/// </summary>
/// <param name="cancelLongPress"></param>
public void SetLongPressCancel(Action cancelLongPress)
{
this.onCancelLongPress = cancelLongPress;
}
/// <summary>
/// 长按蓄力阶段:触点移出该 Rect 的屏幕范围时取消长按(由 ButtonUpDrag 处理)。
/// </summary>
public void SetLongPressCancelBounds(RectTransform bounds)
{
if (buttonUpDrag != null)
buttonUpDrag.SetLongPressCancelBounds(bounds);
}
2025-05-13 15:12:46 +08:00
/// <summary>
/// 启用或禁用拖拽功能
/// </summary>
public void SetDraggable(bool draggable)
{
this.isDraggableEnabled = draggable;
}
2025-07-30 16:45:51 +08:00
private void OnPointDown()
{
onPointDownHandler?.Invoke();
}
private void OnPointUp()
{
onPointUpHandler?.Invoke();
}
private void OnLongPressCancel()
{
onCancelLongPress?.Invoke();
}
2025-05-13 15:12:46 +08:00
private void OnStartDrag()
{
if (!isDraggableEnabled)
return;
// 开始拖拽
isDragging = true;
2026-01-09 12:49:36 +08:00
scaleFactor = UIRoot.Instance.UINormalCanvas.GetComponent<RectTransform>().sizeDelta.x / Screen.width;
2025-05-13 15:12:46 +08:00
// 如果在ScrollRect中则暂时禁用它
if (parentScrollRect is not null)
2025-05-13 15:12:46 +08:00
{
parentScrollRect.enabled = false;
}
originalPosition = rectTransform.position;
originalScale = rectTransform.localScale;
// 改变外观(如果启用)
if (changeDragAppearance)
{
rectTransform.localScale = dragScale;
}
// 注册移动和结束拖拽事件
InputManager.Instance.OnFingerMoveUI += UpdateDragPosition;
InputManager.Instance.OnFingerUpUI += EndDrag;
onStartDrag?.Invoke();
}
private void UpdateDragPosition(Vector2 delta)
{
if (!isDragging || !isDraggableEnabled)
return;
// 计算新位置(考虑偏移)
2025-05-13 19:51:22 +08:00
Vector2 newPosition = rectTransform.anchoredPosition + delta * scaleFactor;
2025-05-13 15:12:46 +08:00
// 应用方向锁定和边界限制逻辑...
// 使用自定义位置调整器(如果有)
if (positionAdjuster != null)
{
newPosition = positionAdjuster(newPosition);
}
// 更新位置
rectTransform.anchoredPosition = newPosition;
// 调用拖拽更新处理器
dragUpdateHandler?.Invoke(rectTransform.position);
}
private void EndDrag(Vector2 position)
{
if (!isDragging)
return;
isDragging = false;
// 恢复原始外观
if (changeDragAppearance)
{
rectTransform.localScale = originalScale;
}
// 处理拖拽结束逻辑
HandleDragEnd(rectTransform.position);//position
// 重新启用ScrollRect
if (parentScrollRect is not null)
2025-05-13 15:12:46 +08:00
{
parentScrollRect.enabled = true;
}
// 清理事件监听
InputManager.Instance.OnFingerMoveUI -= UpdateDragPosition;
InputManager.Instance.OnFingerUpUI -= EndDrag;
onEndDrag?.Invoke();
}
private void HandleDragEnd(Vector2 position)
{
// 在这里实现放置逻辑
bool validPlacement = CheckValidPlacement(position);
if (validPlacement)
{
// 有效放置,执行相应逻辑
FinalizeItemPlacement(position);
}
}
private bool CheckValidPlacement(Vector2 position)
{
// 实现放置检测逻辑
// 这里只是示例,你需要根据具体需求实现
// 示例:使用射线检测
//var results = new System.Collections.Generic.List<UnityEngine.EventSystems.RaycastResult>();
//var eventData = new UnityEngine.EventSystems.PointerEventData(UnityEngine.EventSystems.EventSystem.current);
//eventData.position = position;
//UnityEngine.EventSystems.EventSystem.current.RaycastAll(eventData, results);
//
//foreach (var result in results)
//{
// // 检查是否是有效的放置目标
// // 例如:检查是否有特定的组件或标签
// if (result.gameObject.CompareTag("DropZone"))
// {
// return true;
// }
//}
//
// 默认返回true允许在任何位置放置
// 如果需要更严格的控制改为return false;
//return true;
if (checkValidFunction != null)
{
return checkValidFunction(position);
}
return false;
}
private void FinalizeItemPlacement(Vector2 position)
{
if (placementHandler != null)
{
placementHandler(position);
}
}
private void ReturnToOriginalPosition()
{
// 返回原始位置
// 可以使用动画或直接设置
// 直接设置:
// rectTransform.position = originalPosition;
// 使用动画效果:
//StartCoroutine(AnimateReturn());
rectTransform.position = originalPosition;
}
private System.Collections.IEnumerator AnimateReturn()
{
float duration = 0.3f;
float elapsed = 0f;
Vector3 startPos = rectTransform.position;
while (elapsed < duration)
{
rectTransform.position = Vector3.Lerp(startPos, originalPosition, elapsed / duration);
elapsed += Time.deltaTime;
yield return null;
}
rectTransform.position = originalPosition;
}
private void OnDestroy()
{
// 清理事件监听
if (InputManager.Instance != null)
{
InputManager.Instance.OnFingerMoveUI -= UpdateDragPosition;
InputManager.Instance.OnFingerUp -= EndDrag;
InputManager.Instance.OnFingerUpUI -= EndDrag;
}
}
// 可选:提供公共方法以在外部重置位置
public void ResetPosition()
{
rectTransform.position = originalPosition;
}
// 可选:提供公共方法以更新原始位置(例如在布局变化后)
public void UpdateOriginalPosition()
{
originalPosition = rectTransform.position;
}
}