2025-09-10 23:01:12 +08:00
|
|
|
|
using System;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
using TMPro;
|
|
|
|
|
using UnityEngine;
|
2025-09-10 23:01:12 +08:00
|
|
|
|
using UnityEngine.EventSystems;
|
2025-09-10 16:21:30 +08:00
|
|
|
|
using UnityEngine.Serialization;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
using ZGame;
|
|
|
|
|
|
|
|
|
|
namespace HK.FUJIFILM
|
|
|
|
|
{
|
2025-09-10 23:01:12 +08:00
|
|
|
|
public class PhotoItemOperation : UIItemBase, IPointerEnterHandler, IPointerExitHandler
|
2025-08-22 09:16:11 +08:00
|
|
|
|
{
|
|
|
|
|
[SerializeField] private Button btnToUp;
|
|
|
|
|
[SerializeField] private Button btnToDown;
|
2025-09-10 16:21:30 +08:00
|
|
|
|
[SerializeField] private Button btnRRotate;
|
|
|
|
|
[SerializeField] private Button btnLRotate;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
[SerializeField] private Button btnDelete;
|
|
|
|
|
[SerializeField] private Button btnClose;
|
2025-09-10 16:21:30 +08:00
|
|
|
|
[SerializeField] private Button btnHCenter;
|
|
|
|
|
[SerializeField] private Button btnVCenter;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
|
|
|
|
|
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");
|
2025-08-22 09:16:11 +08:00
|
|
|
|
btnDelete = GetValue<Button>("btnDelete");
|
|
|
|
|
btnClose = GetValue<Button>("btnClose");
|
2025-09-10 16:21:30 +08:00
|
|
|
|
btnHCenter = GetValue<Button>("btnHCenter");
|
|
|
|
|
btnVCenter = GetValue<Button>("btnVCenter");
|
2025-08-22 09:16:11 +08:00
|
|
|
|
|
|
|
|
|
btnToUp.onClick.AddListener(OnClickbtnToUp);
|
|
|
|
|
btnToDown.onClick.AddListener(OnClickbtnToDown);
|
2025-09-10 16:21:30 +08:00
|
|
|
|
btnRRotate.onClick.AddListener(OnClickbtnRRotate);
|
|
|
|
|
btnLRotate.onClick.AddListener(OnClickbtnLRotate);
|
2025-08-22 09:16:11 +08:00
|
|
|
|
btnDelete.onClick.AddListener(OnClickbtnDelete);
|
2025-09-10 16:21:30 +08:00
|
|
|
|
btnHCenter.onClick.AddListener(OnClickbtnHCenter);
|
|
|
|
|
btnVCenter.onClick.AddListener(OnClickbtnVCenter);
|
2025-08-22 09:16:11 +08:00
|
|
|
|
btnClose.onClick.AddListener(OnClickbtnClose);
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2025-09-10 16:21:30 +08:00
|
|
|
|
canvas = GetComponentInParent<Canvas>();
|
|
|
|
|
_imageRect = transform.GetChild(1).GetComponent<RectTransform>();
|
2025-08-22 09:16:11 +08:00
|
|
|
|
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;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
var args = e as PhotoItemOperationEventArgs;
|
2025-08-27 01:05:19 +08:00
|
|
|
|
if (args == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-22 09:16:11 +08:00
|
|
|
|
if (args.isStart)
|
2025-09-10 16:21:30 +08:00
|
|
|
|
{
|
2025-09-10 23:01:12 +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
|
|
|
|
|
2025-08-22 09:16:11 +08:00
|
|
|
|
Open(args.target);
|
2025-09-10 23:01:12 +08:00
|
|
|
|
isStarting = true;
|
2025-09-10 16:21:30 +08:00
|
|
|
|
}
|
2025-08-22 09:16:11 +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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-22 09:16:11 +08:00
|
|
|
|
#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;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
target.transform.SetSiblingIndex(siblingIndex);
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-10 16:21:30 +08:00
|
|
|
|
private void OnClickbtnRRotate()
|
|
|
|
|
{
|
2025-09-10 23:01:12 +08:00
|
|
|
|
target.transform.localEulerAngles -= new Vector3(0f, 0f, 90f);
|
2025-09-10 16:21:30 +08:00
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnClickbtnLRotate()
|
|
|
|
|
{
|
2025-09-10 23:01:12 +08:00
|
|
|
|
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-08-22 09:16:11 +08:00
|
|
|
|
{
|
2025-09-10 16:21:30 +08:00
|
|
|
|
var rectTransform = target.GetComponent<RectTransform>();
|
|
|
|
|
rectTransform.anchoredPosition = new Vector2(0f, rectTransform.anchoredPosition.y);
|
2025-08-22 09:16:11 +08:00
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnClickbtnDelete()
|
|
|
|
|
{
|
|
|
|
|
GameObject.Destroy(target);
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnClickbtnClose()
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Close()
|
|
|
|
|
{
|
2025-09-10 23:01:12 +08:00
|
|
|
|
isStarting = false;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-22 09:16:11 +08:00
|
|
|
|
target = ta.gameObject;
|
|
|
|
|
canvasGroup.alpha = 1;
|
|
|
|
|
canvasGroup.interactable = true;
|
|
|
|
|
canvasGroup.blocksRaycasts = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2025-09-10 23:01:12 +08:00
|
|
|
|
private void Update()
|
|
|
|
|
{
|
|
|
|
|
if (gameObject.activeSelf && isStarting)
|
|
|
|
|
{
|
|
|
|
|
if (Input.GetMouseButtonDown(0) && !isEntering)
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-22 09:16:11 +08:00
|
|
|
|
public override void OnDispose()
|
|
|
|
|
{
|
|
|
|
|
base.OnDispose();
|
2025-09-10 16:21:30 +08:00
|
|
|
|
EventManager.Instance.Unsubscribe(PhotoItemOperationEventArgs.EventId, PhotoItemOperationEvent);
|
2025-08-22 09:16:11 +08:00
|
|
|
|
|
|
|
|
|
#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);
|
2025-08-22 09:16:11 +08:00
|
|
|
|
btnDelete.onClick.RemoveListener(OnClickbtnDelete);
|
|
|
|
|
btnClose.onClick.RemoveListener(OnClickbtnClose);
|
|
|
|
|
|
|
|
|
|
btnToUp = null;
|
|
|
|
|
btnToDown = null;
|
2025-09-10 16:21:30 +08:00
|
|
|
|
btnRRotate = null;
|
2025-08-22 09:16:11 +08:00
|
|
|
|
btnDelete = null;
|
|
|
|
|
btnClose = null;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
2025-09-10 23:01:12 +08:00
|
|
|
|
|
|
|
|
|
private bool isEntering = false;
|
|
|
|
|
private bool isStarting = false;
|
|
|
|
|
|
|
|
|
|
public void OnPointerEnter(PointerEventData eventData)
|
|
|
|
|
{
|
|
|
|
|
isEntering = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnPointerExit(PointerEventData eventData)
|
|
|
|
|
{
|
|
|
|
|
isEntering = false;
|
|
|
|
|
}
|
2025-08-22 09:16:11 +08:00
|
|
|
|
}
|
|
|
|
|
}
|