demo
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ReplacedPerson.Runtime
|
||||
{
|
||||
[RequireComponent(typeof(RectTransform), typeof(Button))]
|
||||
public sealed class ReplacedCardDragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
{
|
||||
private Canvas? _canvas;
|
||||
private RectTransform? _ghost;
|
||||
private ReplacedCardMotion? _motion;
|
||||
private Action<Vector2>? _dropAction;
|
||||
private Vector2 _dragStart;
|
||||
private bool _hasDragStart;
|
||||
|
||||
public void Configure(Action<Vector2> dropAction)
|
||||
{
|
||||
_dropAction = dropAction;
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
CleanupGhost();
|
||||
_dragStart = eventData.position;
|
||||
_hasDragStart = true;
|
||||
_canvas = GetComponentInParent<Canvas>()?.rootCanvas;
|
||||
if (_canvas == null) return;
|
||||
_motion = GetComponent<ReplacedCardMotion>();
|
||||
_motion?.SetDragging(true);
|
||||
_ghost = CreateGhost(_canvas.transform);
|
||||
UpdateGhostPosition(eventData);
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
UpdateGhostPosition(eventData);
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
var moved = _hasDragStart && (eventData.position - _dragStart).sqrMagnitude >= 100f;
|
||||
_motion?.SetDragging(false);
|
||||
_motion = null;
|
||||
CleanupGhost();
|
||||
_hasDragStart = false;
|
||||
if (moved && _dropAction != null) _dropAction(eventData.position);
|
||||
else GetComponent<Button>().onClick.Invoke();
|
||||
}
|
||||
|
||||
private RectTransform CreateGhost(Transform canvasRoot)
|
||||
{
|
||||
var sourceRect = (RectTransform)transform;
|
||||
var sourceImage = GetComponent<Image>();
|
||||
var sourceLabel = transform.Find("Label")?.GetComponent<TMP_Text>();
|
||||
var ghostObject = new GameObject("CardDragGhost", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(CanvasGroup));
|
||||
var ghostRect = ghostObject.GetComponent<RectTransform>();
|
||||
ghostRect.SetParent(canvasRoot, false);
|
||||
ghostRect.anchorMin = ghostRect.anchorMax = new Vector2(.5f, .5f);
|
||||
ghostRect.pivot = sourceRect.pivot;
|
||||
ghostRect.sizeDelta = sourceRect.rect.size;
|
||||
ghostRect.localScale = Vector3.one * 1.06f;
|
||||
ghostRect.SetAsLastSibling();
|
||||
|
||||
var ghostImage = ghostObject.GetComponent<Image>();
|
||||
ghostImage.sprite = sourceImage.sprite;
|
||||
ghostImage.type = sourceImage.type;
|
||||
ghostImage.color = sourceImage.color;
|
||||
ghostImage.material = sourceImage.material;
|
||||
ghostImage.raycastTarget = false;
|
||||
var group = ghostObject.GetComponent<CanvasGroup>();
|
||||
group.alpha = .94f;
|
||||
group.blocksRaycasts = false;
|
||||
group.interactable = false;
|
||||
|
||||
if (sourceLabel != null)
|
||||
{
|
||||
var labelObject = new GameObject("Label", typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI));
|
||||
var labelRect = labelObject.GetComponent<RectTransform>();
|
||||
labelRect.SetParent(ghostRect, false);
|
||||
labelRect.anchorMin = Vector2.zero;
|
||||
labelRect.anchorMax = Vector2.one;
|
||||
labelRect.offsetMin = new Vector2(8, 4);
|
||||
labelRect.offsetMax = new Vector2(-8, -4);
|
||||
var label = labelObject.GetComponent<TextMeshProUGUI>();
|
||||
label.font = sourceLabel.font;
|
||||
label.fontSize = sourceLabel.fontSize;
|
||||
label.alignment = sourceLabel.alignment;
|
||||
label.color = sourceLabel.color;
|
||||
label.text = sourceLabel.text;
|
||||
label.enableWordWrapping = sourceLabel.enableWordWrapping;
|
||||
label.raycastTarget = false;
|
||||
}
|
||||
return ghostRect;
|
||||
}
|
||||
|
||||
private void UpdateGhostPosition(PointerEventData eventData)
|
||||
{
|
||||
if (_ghost == null || _canvas == null) return;
|
||||
var canvasRect = (RectTransform)_canvas.transform;
|
||||
var camera = _canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : _canvas.worldCamera;
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, eventData.position, camera, out var localPoint))
|
||||
_ghost.anchoredPosition = localPoint;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_motion?.SetDragging(false);
|
||||
_motion = null;
|
||||
_hasDragStart = false;
|
||||
CleanupGhost();
|
||||
}
|
||||
|
||||
private void CleanupGhost()
|
||||
{
|
||||
if (_ghost != null) Destroy(_ghost.gameObject);
|
||||
_ghost = null;
|
||||
_canvas = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user