597 lines
20 KiB
C#
597 lines
20 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
using UnityEngine.EventSystems;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.IO;
|
|||
|
|
namespace Kill.UI
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
public class AvatarSelection : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
[Header("UI Elements")]
|
|||
|
|
public Button selectPhotoButton;
|
|||
|
|
public RawImage avatarPreview;
|
|||
|
|
public GameObject cropCanvas; // 用于裁剪的全屏Canvas
|
|||
|
|
public RawImage cropImagePreview;
|
|||
|
|
public RectTransform cropArea;
|
|||
|
|
public Button confirmCropButton;
|
|||
|
|
public Button cancelCropButton;
|
|||
|
|
|
|||
|
|
[Header("Avatar Settings")]
|
|||
|
|
[Tooltip("生成头像的尺寸(宽高相等)")]
|
|||
|
|
public int avatarSize = 100;
|
|||
|
|
|
|||
|
|
private Texture2D selectedImage;
|
|||
|
|
private Vector2 startPoint;
|
|||
|
|
private Vector2 endPoint;
|
|||
|
|
private bool isSelecting = false;
|
|||
|
|
private RectTransform cropImageRectTransform;
|
|||
|
|
private CropAreaHandler cropAreaHandler;
|
|||
|
|
|
|||
|
|
void Start()
|
|||
|
|
{
|
|||
|
|
// 初始化按钮事件
|
|||
|
|
if (selectPhotoButton != null)
|
|||
|
|
selectPhotoButton.onClick.AddListener(SelectPhotoFromGallery);
|
|||
|
|
|
|||
|
|
if (confirmCropButton != null)
|
|||
|
|
confirmCropButton.onClick.AddListener(ConfirmCrop);
|
|||
|
|
|
|||
|
|
if (cancelCropButton != null)
|
|||
|
|
cancelCropButton.onClick.AddListener(CancelCrop);
|
|||
|
|
|
|||
|
|
// 隐藏裁剪界面
|
|||
|
|
if (cropCanvas != null)
|
|||
|
|
cropCanvas.SetActive(false);
|
|||
|
|
|
|||
|
|
// 获取裁剪图像的RectTransform
|
|||
|
|
if (cropImagePreview != null)
|
|||
|
|
cropImageRectTransform = cropImagePreview.GetComponent<RectTransform>();
|
|||
|
|
|
|||
|
|
// 为裁剪区域添加处理组件
|
|||
|
|
if (cropArea != null)
|
|||
|
|
{
|
|||
|
|
cropAreaHandler = cropArea.gameObject.AddComponent<CropAreaHandler>();
|
|||
|
|
cropAreaHandler.Initialize(this, cropImageRectTransform);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 从相册选择照片
|
|||
|
|
/// </summary>
|
|||
|
|
public void SelectPhotoFromGallery()
|
|||
|
|
{
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
// 在编辑器中测试时,加载一个默认图片
|
|||
|
|
string testImagePath = UnityEditor.EditorUtility.OpenFilePanel("Select Image", "", "jpg,png,jpeg");
|
|||
|
|
if (!string.IsNullOrEmpty(testImagePath))
|
|||
|
|
{
|
|||
|
|
byte[] fileData = File.ReadAllBytes(testImagePath);
|
|||
|
|
selectedImage = new Texture2D(2, 2);
|
|||
|
|
selectedImage.LoadImage(fileData);
|
|||
|
|
ShowCropInterface(selectedImage);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#else
|
|||
|
|
// 使用NativeGallery插件从相册选择图片
|
|||
|
|
bool permission = NativeGallery.CheckPermission(NativeGallery.PermissionType.Read, NativeGallery.MediaType.Image);
|
|||
|
|
if (permission)
|
|||
|
|
{
|
|||
|
|
PickImage();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
NativeGallery.RequestPermissionAsync((perm) =>
|
|||
|
|
{
|
|||
|
|
if (perm == NativeGallery.Permission.Granted)
|
|||
|
|
{
|
|||
|
|
PickImage();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("没有获得相册访问权限");
|
|||
|
|
}
|
|||
|
|
}, NativeGallery.PermissionType.Read, NativeGallery.MediaType.Image);
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void PickImage()
|
|||
|
|
{
|
|||
|
|
NativeGallery.GetImageFromGallery((path) =>
|
|||
|
|
{
|
|||
|
|
if (path != null)
|
|||
|
|
{
|
|||
|
|
// 加载选中的图片,并确保纹理是可读的
|
|||
|
|
selectedImage = NativeGallery.LoadImageAtPath(path, -1, false); // 设置 markTextureNonReadable 为 false
|
|||
|
|
if (selectedImage != null)
|
|||
|
|
{
|
|||
|
|
ShowCropInterface(selectedImage);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogError("无法加载选定的图片");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}, "选择一张图片");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 显示裁剪界面
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="image">要裁剪的图片</param>
|
|||
|
|
private void ShowCropInterface(Texture2D image)
|
|||
|
|
{
|
|||
|
|
if (cropCanvas != null && cropImagePreview != null)
|
|||
|
|
{
|
|||
|
|
cropImagePreview.texture = image;
|
|||
|
|
cropCanvas.SetActive(true);
|
|||
|
|
|
|||
|
|
// 调整图片显示大小以适应屏幕并保持原图比例
|
|||
|
|
FitImageToScreen(image);
|
|||
|
|
|
|||
|
|
// 重置裁剪区域
|
|||
|
|
if (cropAreaHandler != null)
|
|||
|
|
{
|
|||
|
|
cropAreaHandler.ResetCropArea();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 调整图片大小以适应屏幕并保持原图比例,同时确保不超过cropCanvas的大小
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="image">要调整的图片</param>
|
|||
|
|
private void FitImageToScreen(Texture2D image)
|
|||
|
|
{
|
|||
|
|
if (cropImageRectTransform == null) return;
|
|||
|
|
|
|||
|
|
// 获取cropCanvas的RectTransform
|
|||
|
|
RectTransform canvasRect = cropCanvas.GetComponent<RectTransform>();
|
|||
|
|
if (canvasRect == null) return;
|
|||
|
|
|
|||
|
|
// 计算可用空间(考虑到一些边距)
|
|||
|
|
float maxWidth = canvasRect.rect.width * 0.9f;
|
|||
|
|
float maxHeight = canvasRect.rect.height * 0.7f;
|
|||
|
|
|
|||
|
|
// 计算图片比例
|
|||
|
|
float imageRatio = (float)image.width / image.height;
|
|||
|
|
|
|||
|
|
// 根据图片比例调整尺寸
|
|||
|
|
float width, height;
|
|||
|
|
if (imageRatio > 1) // 宽图
|
|||
|
|
{
|
|||
|
|
width = Mathf.Min(maxWidth, image.width);
|
|||
|
|
height = width / imageRatio;
|
|||
|
|
|
|||
|
|
// 检查高度是否超出限制
|
|||
|
|
if (height > maxHeight)
|
|||
|
|
{
|
|||
|
|
height = maxHeight;
|
|||
|
|
width = height * imageRatio;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else // 高图或正方形
|
|||
|
|
{
|
|||
|
|
height = Mathf.Min(maxHeight, image.height);
|
|||
|
|
width = height * imageRatio;
|
|||
|
|
|
|||
|
|
// 检查宽度是否超出限制
|
|||
|
|
if (width > maxWidth)
|
|||
|
|
{
|
|||
|
|
width = maxWidth;
|
|||
|
|
height = width / imageRatio;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置尺寸
|
|||
|
|
cropImageRectTransform.sizeDelta = new Vector2(width, height);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 确认裁剪
|
|||
|
|
/// </summary>
|
|||
|
|
public void ConfirmCrop()
|
|||
|
|
{
|
|||
|
|
if (selectedImage == null || cropArea == null || cropImageRectTransform == null)
|
|||
|
|
{
|
|||
|
|
CancelCrop();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算在原图中的裁剪坐标
|
|||
|
|
Rect cropRect = CalculateCropRect();
|
|||
|
|
|
|||
|
|
if (cropRect.width <= 0 || cropRect.height <= 0)
|
|||
|
|
{
|
|||
|
|
CancelCrop();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建新的指定尺寸的纹理
|
|||
|
|
Texture2D croppedTexture = CropTexture(selectedImage, cropRect);
|
|||
|
|
|
|||
|
|
// 检查裁剪纹理是否小于目标尺寸,并决定使用哪种缩放算法
|
|||
|
|
Texture2D resizedTexture;
|
|||
|
|
if (croppedTexture.width < avatarSize || croppedTexture.height < avatarSize)
|
|||
|
|
{
|
|||
|
|
// 如果裁剪区域小于目标尺寸,使用高质量的双线性插值算法
|
|||
|
|
resizedTexture = ResizeTextureWithBilinear(croppedTexture, avatarSize, avatarSize);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 否则使用普通缩放
|
|||
|
|
resizedTexture = ResizeTexture(croppedTexture, avatarSize, avatarSize);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示结果
|
|||
|
|
if (avatarPreview != null)
|
|||
|
|
{
|
|||
|
|
avatarPreview.texture = resizedTexture;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 隐藏裁剪界面
|
|||
|
|
if (cropCanvas != null)
|
|||
|
|
{
|
|||
|
|
cropCanvas.SetActive(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Debug.Log("头像裁剪完成,尺寸: " + avatarSize + "x" + avatarSize);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 计算在原图中的裁剪区域
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>裁剪区域</returns>
|
|||
|
|
private Rect CalculateCropRect()
|
|||
|
|
{
|
|||
|
|
if (cropArea == null || cropImageRectTransform == null || selectedImage == null)
|
|||
|
|
return new Rect(0, 0, 0, 0);
|
|||
|
|
|
|||
|
|
// 获取裁剪区域在图片中的相对位置
|
|||
|
|
Rect cropAreaRect = cropAreaHandler.GetCropRect();
|
|||
|
|
|
|||
|
|
// 获取图片显示区域的世界角点
|
|||
|
|
Vector3[] imageCorners = new Vector3[4];
|
|||
|
|
cropImageRectTransform.GetWorldCorners(imageCorners);
|
|||
|
|
|
|||
|
|
// 获取裁剪区域的世界角点
|
|||
|
|
Vector3[] cropAreaCorners = new Vector3[4];
|
|||
|
|
cropArea.GetWorldCorners(cropAreaCorners);
|
|||
|
|
|
|||
|
|
// 计算裁剪区域在图片中的UV坐标
|
|||
|
|
float uMin = Mathf.InverseLerp(imageCorners[0].x, imageCorners[2].x, cropAreaCorners[0].x);
|
|||
|
|
float uMax = Mathf.InverseLerp(imageCorners[0].x, imageCorners[2].x, cropAreaCorners[2].x);
|
|||
|
|
float vMin = Mathf.InverseLerp(imageCorners[0].y, imageCorners[2].y, cropAreaCorners[0].y);
|
|||
|
|
float vMax = Mathf.InverseLerp(imageCorners[0].y, imageCorners[2].y, cropAreaCorners[2].y);
|
|||
|
|
|
|||
|
|
// 转换为像素坐标
|
|||
|
|
int x = Mathf.RoundToInt(uMin * selectedImage.width);
|
|||
|
|
int y = Mathf.RoundToInt(vMin * selectedImage.height);
|
|||
|
|
int width = Mathf.RoundToInt((uMax - uMin) * selectedImage.width);
|
|||
|
|
int height = Mathf.RoundToInt((vMax - vMin) * selectedImage.height);
|
|||
|
|
|
|||
|
|
// 确保不超过图片边界
|
|||
|
|
x = Mathf.Clamp(x, 0, selectedImage.width);
|
|||
|
|
y = Mathf.Clamp(y, 0, selectedImage.height);
|
|||
|
|
width = Mathf.Clamp(width, 0, selectedImage.width - x);
|
|||
|
|
height = Mathf.Clamp(height, 0, selectedImage.height - y);
|
|||
|
|
|
|||
|
|
return new Rect(x, y, width, height);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 裁剪纹理
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="texture">原纹理</param>
|
|||
|
|
/// <param name="rect">裁剪区域</param>
|
|||
|
|
/// <returns>裁剪后的纹理</returns>
|
|||
|
|
private Texture2D CropTexture(Texture2D texture, Rect rect)
|
|||
|
|
{
|
|||
|
|
int x = Mathf.RoundToInt(rect.x);
|
|||
|
|
int y = Mathf.RoundToInt(rect.y);
|
|||
|
|
int width = Mathf.RoundToInt(rect.width);
|
|||
|
|
int height = Mathf.RoundToInt(rect.height);
|
|||
|
|
|
|||
|
|
// 确保是正方形
|
|||
|
|
int size = Mathf.Min(width, height);
|
|||
|
|
|
|||
|
|
Color[] pixels = texture.GetPixels(x, y, size, size);
|
|||
|
|
Texture2D croppedTexture = new Texture2D(size, size, TextureFormat.RGBA32, false);
|
|||
|
|
croppedTexture.SetPixels(pixels);
|
|||
|
|
croppedTexture.Apply();
|
|||
|
|
|
|||
|
|
return croppedTexture;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 调整纹理大小(普通质量)
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="texture">原纹理</param>
|
|||
|
|
/// <param name="targetWidth">目标宽度</param>
|
|||
|
|
/// <param name="targetHeight">目标高度</param>
|
|||
|
|
/// <returns>调整大小后的纹理</returns>
|
|||
|
|
private Texture2D ResizeTexture(Texture2D texture, int targetWidth, int targetHeight)
|
|||
|
|
{
|
|||
|
|
// 创建渲染纹理
|
|||
|
|
RenderTexture renderTexture = new RenderTexture(targetWidth, targetHeight, 24);
|
|||
|
|
RenderTexture.active = renderTexture;
|
|||
|
|
|
|||
|
|
// 绘制原纹理到渲染纹理
|
|||
|
|
Graphics.Blit(texture, renderTexture);
|
|||
|
|
|
|||
|
|
// 从渲染纹理创建新的纹理
|
|||
|
|
Texture2D resizedTexture = new Texture2D(targetWidth, targetHeight, TextureFormat.RGBA32, false);
|
|||
|
|
resizedTexture.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0);
|
|||
|
|
resizedTexture.Apply();
|
|||
|
|
|
|||
|
|
// 清理
|
|||
|
|
RenderTexture.active = null;
|
|||
|
|
|
|||
|
|
return resizedTexture;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 使用双线性插值算法调整纹理大小(高质量)
|
|||
|
|
/// 当源纹理小于目标尺寸时使用,以获得更好的图像质量
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="texture">原纹理</param>
|
|||
|
|
/// <param name="targetWidth">目标宽度</param>
|
|||
|
|
/// <param name="targetHeight">目标高度</param>
|
|||
|
|
/// <returns>调整大小后的纹理</returns>
|
|||
|
|
private Texture2D ResizeTextureWithBilinear(Texture2D texture, int targetWidth, int targetHeight)
|
|||
|
|
{
|
|||
|
|
Color[] originalPixels = texture.GetPixels();
|
|||
|
|
int originalWidth = texture.width;
|
|||
|
|
int originalHeight = texture.height;
|
|||
|
|
|
|||
|
|
Color[] newPixels = new Color[targetWidth * targetHeight];
|
|||
|
|
|
|||
|
|
float xRatio = (float)originalWidth / targetWidth;
|
|||
|
|
float yRatio = (float)originalHeight / targetHeight;
|
|||
|
|
|
|||
|
|
for (int y = 0; y < targetHeight; y++)
|
|||
|
|
{
|
|||
|
|
for (int x = 0; x < targetWidth; x++)
|
|||
|
|
{
|
|||
|
|
// 计算在原始图像中的位置
|
|||
|
|
float px = x * xRatio;
|
|||
|
|
float py = y * yRatio;
|
|||
|
|
|
|||
|
|
// 获取相邻的四个像素
|
|||
|
|
int x1 = (int)Mathf.Floor(px);
|
|||
|
|
int y1 = (int)Mathf.Floor(py);
|
|||
|
|
int x2 = Mathf.Min(x1 + 1, originalWidth - 1);
|
|||
|
|
int y2 = Mathf.Min(y1 + 1, originalHeight - 1);
|
|||
|
|
|
|||
|
|
// 计算权重
|
|||
|
|
float fx = px - x1;
|
|||
|
|
float fy = py - y1;
|
|||
|
|
float w1 = (1 - fx) * (1 - fy);
|
|||
|
|
float w2 = fx * (1 - fy);
|
|||
|
|
float w3 = (1 - fx) * fy;
|
|||
|
|
float w4 = fx * fy;
|
|||
|
|
|
|||
|
|
// 获取四个像素的颜色
|
|||
|
|
Color c1 = originalPixels[y1 * originalWidth + x1];
|
|||
|
|
Color c2 = originalPixels[y1 * originalWidth + x2];
|
|||
|
|
Color c3 = originalPixels[y2 * originalWidth + x1];
|
|||
|
|
Color c4 = originalPixels[y2 * originalWidth + x2];
|
|||
|
|
|
|||
|
|
// 双线性插值
|
|||
|
|
Color finalColor = c1 * w1 + c2 * w2 + c3 * w3 + c4 * w4;
|
|||
|
|
newPixels[y * targetWidth + x] = finalColor;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Texture2D resizedTexture = new Texture2D(targetWidth, targetHeight, TextureFormat.RGBA32, false);
|
|||
|
|
resizedTexture.SetPixels(newPixels);
|
|||
|
|
resizedTexture.Apply();
|
|||
|
|
|
|||
|
|
return resizedTexture;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 取消裁剪
|
|||
|
|
/// </summary>
|
|||
|
|
public void CancelCrop()
|
|||
|
|
{
|
|||
|
|
if (cropCanvas != null)
|
|||
|
|
{
|
|||
|
|
cropCanvas.SetActive(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Debug.Log("取消裁剪");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public RectTransform GetCropImageRectTransform()
|
|||
|
|
{
|
|||
|
|
return cropImageRectTransform;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public RectTransform GetCropCanvasRectTransform()
|
|||
|
|
{
|
|||
|
|
if (cropCanvas != null)
|
|||
|
|
{
|
|||
|
|
return cropCanvas.GetComponent<RectTransform>();
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 裁剪区域处理组件
|
|||
|
|
/// </summary>
|
|||
|
|
public class CropAreaHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerDownHandler
|
|||
|
|
{
|
|||
|
|
private AvatarSelection avatarSelection;
|
|||
|
|
private RectTransform cropArea;
|
|||
|
|
private RectTransform cropImageRectTransform;
|
|||
|
|
private Vector2 lastPointerPosition;
|
|||
|
|
private Vector2 dragStartPosition;
|
|||
|
|
private float MIN_CROP_SIZE = 50f;
|
|||
|
|
private bool isScaling = false; // 添加标志位,用于在缩放时屏蔽移动操作
|
|||
|
|
|
|||
|
|
public void Initialize(AvatarSelection avatarSelection, RectTransform cropImageRectTransform)
|
|||
|
|
{
|
|||
|
|
this.avatarSelection = avatarSelection;
|
|||
|
|
this.cropImageRectTransform = cropImageRectTransform;
|
|||
|
|
cropArea = GetComponent<RectTransform>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ResetCropArea()
|
|||
|
|
{
|
|||
|
|
if (cropArea == null || cropImageRectTransform == null) return;
|
|||
|
|
|
|||
|
|
// 设置默认裁剪区域为图片显示区域的正方形,并确保不小于图片尺寸的一半
|
|||
|
|
float defaultSize = Mathf.Min(cropImageRectTransform.rect.width, cropImageRectTransform.rect.height);
|
|||
|
|
MIN_CROP_SIZE =defaultSize/2.0f;
|
|||
|
|
cropArea.sizeDelta = new Vector2(defaultSize, defaultSize);
|
|||
|
|
cropArea.anchoredPosition = Vector2.zero;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public Rect GetCropRect()
|
|||
|
|
{
|
|||
|
|
if (cropArea == null) return new Rect(0, 0, 0, 0);
|
|||
|
|
|
|||
|
|
// 获取世界角点以获得准确的边界
|
|||
|
|
Vector3[] corners = new Vector3[4];
|
|||
|
|
cropArea.GetWorldCorners(corners);
|
|||
|
|
|
|||
|
|
// 返回基于屏幕坐标的矩形
|
|||
|
|
return new Rect(
|
|||
|
|
corners[0].x,
|
|||
|
|
corners[0].y,
|
|||
|
|
corners[2].x - corners[0].x,
|
|||
|
|
corners[2].y - corners[0].y
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnPointerDown(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
// 只有在非缩放状态下才允许移动
|
|||
|
|
if (!isScaling)
|
|||
|
|
{
|
|||
|
|
lastPointerPosition = eventData.position;
|
|||
|
|
dragStartPosition = cropArea.anchoredPosition;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
// 只有在非缩放状态下才允许移动
|
|||
|
|
if (!isScaling)
|
|||
|
|
{
|
|||
|
|
lastPointerPosition = eventData.position;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnDrag(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
// 只有在非缩放状态下才允许移动
|
|||
|
|
if (cropArea == null || cropImageRectTransform == null || isScaling) return;
|
|||
|
|
|
|||
|
|
Vector2 currentPointerPosition = eventData.position;
|
|||
|
|
Vector2 deltaPosition = currentPointerPosition - lastPointerPosition;
|
|||
|
|
|
|||
|
|
// 移动裁剪区域
|
|||
|
|
cropArea.anchoredPosition += deltaPosition;
|
|||
|
|
|
|||
|
|
// 限制裁剪区域在图片范围内
|
|||
|
|
ConstrainCropArea();
|
|||
|
|
|
|||
|
|
lastPointerPosition = currentPointerPosition;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnEndDrag(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
// 只有在非缩放状态下才处理拖拽结束
|
|||
|
|
if (!isScaling)
|
|||
|
|
{
|
|||
|
|
// 拖拽结束时确保裁剪区域仍在有效范围内
|
|||
|
|
ConstrainCropArea();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ConstrainCropArea()
|
|||
|
|
{
|
|||
|
|
if (cropArea == null || cropImageRectTransform == null) return;
|
|||
|
|
|
|||
|
|
// 获取图片显示区域的边界
|
|||
|
|
Rect imageRect = cropImageRectTransform.rect;
|
|||
|
|
Vector2 imageSize = new Vector2(imageRect.width, imageRect.height);
|
|||
|
|
|
|||
|
|
// 获取裁剪区域边界
|
|||
|
|
Vector2 cropSize = cropArea.sizeDelta;
|
|||
|
|
|
|||
|
|
// 计算最大偏移量,确保裁剪区域不会超出图片边界
|
|||
|
|
float maxXOffset = (imageSize.x - cropSize.x) / 2;
|
|||
|
|
float maxYOffset = (imageSize.y - cropSize.y) / 2;
|
|||
|
|
|
|||
|
|
// 限制裁剪区域位置
|
|||
|
|
Vector2 newPosition = cropArea.anchoredPosition;
|
|||
|
|
newPosition.x = Mathf.Clamp(newPosition.x, -maxXOffset, maxXOffset);
|
|||
|
|
newPosition.y = Mathf.Clamp(newPosition.y, -maxYOffset, maxYOffset);
|
|||
|
|
|
|||
|
|
cropArea.anchoredPosition = newPosition;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加缩放功能
|
|||
|
|
void Update()
|
|||
|
|
{
|
|||
|
|
if (cropArea == null) return;
|
|||
|
|
|
|||
|
|
// 处理双指缩放(移动端)
|
|||
|
|
if (Input.touchCount == 2)
|
|||
|
|
{
|
|||
|
|
isScaling = true; // 设置缩放标志
|
|||
|
|
|
|||
|
|
Touch touchZero = Input.GetTouch(0);
|
|||
|
|
Touch touchOne = Input.GetTouch(1);
|
|||
|
|
|
|||
|
|
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
|
|||
|
|
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
|
|||
|
|
|
|||
|
|
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
|
|||
|
|
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
|
|||
|
|
|
|||
|
|
float deltaMagnitudeDiff = touchDeltaMag - prevTouchDeltaMag;
|
|||
|
|
|
|||
|
|
ResizeCropArea(deltaMagnitudeDiff * 0.5f);
|
|||
|
|
}
|
|||
|
|
// 处理鼠标滚轮缩放(PC端)
|
|||
|
|
else if (Input.mouseScrollDelta.y != 0)
|
|||
|
|
{
|
|||
|
|
isScaling = true; // 设置缩放标志
|
|||
|
|
ResizeCropArea(Input.mouseScrollDelta.y * 10f);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 没有缩放操作时,重置标志
|
|||
|
|
isScaling = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ResizeCropArea(float deltaSize)
|
|||
|
|
{
|
|||
|
|
if (cropArea == null || cropImageRectTransform == null) return;
|
|||
|
|
|
|||
|
|
// 获取当前尺寸
|
|||
|
|
Vector2 currentSize = cropArea.sizeDelta;
|
|||
|
|
|
|||
|
|
// 计算新尺寸
|
|||
|
|
Vector2 newSize = new Vector2(
|
|||
|
|
currentSize.x + deltaSize,
|
|||
|
|
currentSize.y + deltaSize
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 保持正方形并确保在有效范围内
|
|||
|
|
float maxSize = Mathf.Min(cropImageRectTransform.rect.width, cropImageRectTransform.rect.height);
|
|||
|
|
float finalSize = Mathf.Clamp(newSize.x, MIN_CROP_SIZE, maxSize);
|
|||
|
|
cropArea.sizeDelta = new Vector2(finalSize, finalSize);
|
|||
|
|
|
|||
|
|
// 调整位置以保持在图片范围内
|
|||
|
|
ConstrainCropArea();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|