FM/Assets/Scripts/FUJIFILM/UI/Item/PhotoItemOperation.cs

294 lines
10 KiB
C#
Raw Normal View History

using System;
using UnityEngine.UI;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
2025-09-10 16:21:30 +08:00
using UnityEngine.Serialization;
using ZGame;
namespace HK.FUJIFILM
{
public class PhotoItemOperation : UIItemBase, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] private Button btnToUp;
[SerializeField] private Button btnToDown;
2025-09-10 16:21:30 +08:00
[SerializeField] private Button btnRRotate;
[SerializeField] private Button btnLRotate;
[SerializeField] private Button btnDelete;
[SerializeField] private Button btnClose;
2025-09-10 16:21:30 +08:00
[SerializeField] private Button btnHCenter;
[SerializeField] private Button btnVCenter;
CanvasGroup canvasGroup;
[SerializeField] private GameObject target;
public override void OnInit()
{
base.OnInit();
#region AutoGen_Init
btnToUp = GetValue<Button>("btnToUp");
btnToDown = GetValue<Button>("btnToDown");
2025-09-10 16:21:30 +08:00
btnRRotate = GetValue<Button>("btnRRotate");
btnLRotate = GetValue<Button>("btnLRotate");
btnDelete = GetValue<Button>("btnDelete");
btnClose = GetValue<Button>("btnClose");
2025-09-10 16:21:30 +08:00
btnHCenter = GetValue<Button>("btnHCenter");
btnVCenter = GetValue<Button>("btnVCenter");
btnToUp.onClick.AddListener(OnClickbtnToUp);
btnToDown.onClick.AddListener(OnClickbtnToDown);
2025-09-10 16:21:30 +08:00
btnRRotate.onClick.AddListener(OnClickbtnRRotate);
btnLRotate.onClick.AddListener(OnClickbtnLRotate);
btnDelete.onClick.AddListener(OnClickbtnDelete);
2025-09-10 16:21:30 +08:00
btnHCenter.onClick.AddListener(OnClickbtnHCenter);
btnVCenter.onClick.AddListener(OnClickbtnVCenter);
btnClose.onClick.AddListener(OnClickbtnClose);
#endregion
2025-09-10 16:21:30 +08:00
canvas = GetComponentInParent<Canvas>();
_imageRect = transform.GetChild(1).GetComponent<RectTransform>();
canvasGroup = GetComponent<CanvasGroup>();
Close();
EventManager.Instance.Subscribe(PhotoItemOperationEventArgs.EventId, PhotoItemOperationEvent);
}
private void PhotoItemOperationEvent(object sender, GameEventArgs e)
{
2025-09-10 16:21:30 +08:00
// return;
var args = e as PhotoItemOperationEventArgs;
2025-08-27 01:05:19 +08:00
if (args == null)
{
return;
}
if (args.isStart)
2025-09-10 16:21:30 +08:00
{
// // 1. 获取鼠标点击的屏幕坐标
// Vector2 clickScreenPos = Input.mousePosition;
//
// // 2. 应用偏移量(让 Image 位置更灵活)
// clickScreenPos += clickOffset;
//
// // 3. (可选)限制 Image 在屏幕内
// if (clampToScreen)
// {
// clickScreenPos = ClampPosToScreen(clickScreenPos);
// }
//
// // 4. 根据 Canvas 模式,设置 Image 最终位置
// SetImagePosition(clickScreenPos);
2025-09-10 16:21:30 +08:00
Open(args.target);
isStarting = true;
2025-09-10 16:21:30 +08:00
}
else
Close();
}
2025-09-10 16:21:30 +08:00
Canvas canvas;
private RectTransform _imageRect;
[SerializeField] int screenMargin = 10;
[SerializeField] bool clampToScreen = true;
[SerializeField] Vector2 clickOffset = Vector2.zero;
/// <summary>
/// 限制位置在屏幕内,防止 Image 超出视野
/// </summary>
/// <param name="originalPos">原始点击位置</param>
/// <returns>限制后的位置</returns>
private Vector2 ClampPosToScreen(Vector2 originalPos)
{
// 计算 Image 自身的实际尺寸(考虑缩放)
Vector2 imageRealSize = new Vector2(
_imageRect.rect.width * Mathf.Abs(_imageRect.localScale.x),
_imageRect.rect.height * Mathf.Abs(_imageRect.localScale.y)
);
// 计算屏幕可显示的边界(留空 margin
float minX = screenMargin + (imageRealSize.x / 2); // 左边界(加 Image 半宽,避免左半部分超出)
float maxX = Screen.width - screenMargin - (imageRealSize.x / 2); // 右边界
float minY = screenMargin + (imageRealSize.y / 2); // 下边界
float maxY = Screen.height - screenMargin - (imageRealSize.y / 2); // 上边界
// 限制位置在边界内
return new Vector2(
Mathf.Clamp(originalPos.x, minX, maxX),
Mathf.Clamp(originalPos.y, minY, maxY)
);
}
/// <summary>
/// 根据 Canvas 渲染模式,设置 Image 到目标位置
/// </summary>
/// <param name="targetScreenPos">目标屏幕坐标</param>
private void SetImagePosition(Vector2 targetScreenPos)
{
switch (canvas.renderMode)
{
// 1. 最常用Screen Space - Overlay 模式(直接用屏幕坐标)
case RenderMode.ScreenSpaceOverlay:
_imageRect.position = targetScreenPos;
break;
// 2. Screen Space - Camera 模式(需通过相机转换坐标)
case RenderMode.ScreenSpaceCamera:
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvas.GetComponent<RectTransform>(), // Canvas 的 RectTransform
targetScreenPos, // 目标屏幕位置
canvas.worldCamera, // Canvas 关联的相机
out Vector2 canvasLocalPos // 转换后的 Canvas 局部坐标
))
{
_imageRect.localPosition = canvasLocalPos;
}
break;
// 3. World Space 模式UI 作为3D物体需转换为世界坐标
case RenderMode.WorldSpace:
if (RectTransformUtility.ScreenPointToWorldPointInRectangle(
_imageRect, // Image 自身的 RectTransform
targetScreenPos, // 目标屏幕位置
canvas.worldCamera, // Canvas 关联的相机
out Vector3 worldPos // 转换后的世界坐标
))
{
// 保持 Image 的 Z 轴位置不变(避免前后层叠问题)
worldPos.z = _imageRect.position.z;
_imageRect.position = worldPos;
}
break;
}
}
#region AutoGen_Method
private void OnClickbtnToUp()
{
var parent = target.transform.parent;
target.transform.SetSiblingIndex(parent.childCount - 1);
Close();
}
private void OnClickbtnToDown()
{
2025-09-10 16:21:30 +08:00
var index = target.transform.GetSiblingIndex() - 1;
var siblingIndex = index >= 0 ? index : 0;
target.transform.SetSiblingIndex(siblingIndex);
Close();
}
2025-09-10 16:21:30 +08:00
private void OnClickbtnRRotate()
{
target.transform.localEulerAngles -= new Vector3(0f, 0f, 90f);
2025-09-10 16:21:30 +08:00
Close();
}
private void OnClickbtnLRotate()
{
target.transform.localEulerAngles += new Vector3(0f, 0f, 90f);
2025-09-10 16:21:30 +08:00
Close();
}
private void OnClickbtnVCenter()
{
var rectTransform = target.GetComponent<RectTransform>();
rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, 0f);
Close();
}
private void OnClickbtnHCenter()
{
2025-09-10 16:21:30 +08:00
var rectTransform = target.GetComponent<RectTransform>();
rectTransform.anchoredPosition = new Vector2(0f, rectTransform.anchoredPosition.y);
Close();
}
private void OnClickbtnDelete()
{
GameObject.Destroy(target);
Close();
}
private void OnClickbtnClose()
{
Close();
}
void Close()
{
isStarting = false;
target = null;
canvasGroup.alpha = 0;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
}
void Open(Transform ta)
{
2025-08-27 01:05:19 +08:00
if (ta == null)
{
return;
}
target = ta.gameObject;
canvasGroup.alpha = 1;
canvasGroup.interactable = true;
canvasGroup.blocksRaycasts = true;
}
#endregion
private void Update()
{
if (gameObject.activeSelf && isStarting)
{
if (Input.GetMouseButtonDown(0) && !isEntering)
{
Close();
}
}
}
public override void OnDispose()
{
base.OnDispose();
2025-09-10 16:21:30 +08:00
EventManager.Instance.Unsubscribe(PhotoItemOperationEventArgs.EventId, PhotoItemOperationEvent);
#region AutoGen_Dispose
btnToUp.onClick.RemoveListener(OnClickbtnToUp);
btnToDown.onClick.RemoveListener(OnClickbtnToDown);
2025-09-10 16:21:30 +08:00
btnRRotate.onClick.RemoveListener(OnClickbtnRRotate);
btnLRotate.onClick.RemoveListener(OnClickbtnLRotate);
btnDelete.onClick.RemoveListener(OnClickbtnDelete);
btnClose.onClick.RemoveListener(OnClickbtnClose);
btnToUp = null;
btnToDown = null;
2025-09-10 16:21:30 +08:00
btnRRotate = null;
btnDelete = null;
btnClose = null;
#endregion
}
private bool isEntering = false;
private bool isStarting = false;
public void OnPointerEnter(PointerEventData eventData)
{
isEntering = true;
}
public void OnPointerExit(PointerEventData eventData)
{
isEntering = false;
}
}
}