123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- using UnityEngine;
- using UnityEngine.UI;
- using UnityEngine.EventSystems;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
- public class AdvancedImageViewer : MonoBehaviour,
- IBeginDragHandler, IDragHandler, IEndDragHandler,
- IScrollHandler, IPointerClickHandler
- {
- [Header("Zoom Settings")]
- [Range(0.1f, 0.5f)] public float minZoom = 0.3f;
- [Range(2f, 10f)] public float maxZoom = 4f;
- [Range(0.01f, 0.2f)] public float zoomSpeed = 0.1f;
- [Range(0.001f, 0.05f)] public float touchZoomSpeed = 0.01f;
-
- [Header("Move Settings")]
- [Range(0.5f, 2f)] public float moveSpeed = 1f;
- [Range(0.01f, 0.3f)] public float elasticFactor = 0.1f;
-
- [Header("References")]
- public RectTransform imageRect;
- public RectTransform contentRect;
-
- private Vector2 lastDragPosition;
- private float currentZoom = 1f;
- private Vector2 initialAnchoredPosition;
- private Vector2 initialSizeDelta;
-
- private float lastTapTime;
- private const float DoubleTapTime = 0.3f;
- private bool isDragging;
- private Vector2 velocity;
- private const float friction = 0.95f;
- private void OnEnable()
- {
- Screen.orientation = ScreenOrientation.LandscapeLeft;
- Screen.autorotateToLandscapeLeft = false;
- Screen.autorotateToLandscapeRight = false;
- Screen.autorotateToPortrait = false;
- Screen.autorotateToPortraitUpsideDown = false;
- Initialize();
- }
- private void OnDisable()
- {
-
- Screen.orientation = ScreenOrientation.Portrait;
- Screen.autorotateToLandscapeLeft = false;
- Screen.autorotateToLandscapeRight = false;
- Screen.autorotateToPortrait = false;
- Screen.autorotateToPortraitUpsideDown = false;
- }
- private void Initialize()
- {
- if (imageRect == null) imageRect = GetComponent<RectTransform>();
- if (contentRect == null) contentRect = transform.parent.GetComponent<RectTransform>();
-
- initialAnchoredPosition = imageRect.anchoredPosition;
- initialSizeDelta = imageRect.sizeDelta;
- currentZoom = 1f;
- imageRect.localScale = Vector3.one;
- }
- private void Update()
- {
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- {
-
- if (currentZoom != 1f)
- {
- currentZoom = 1f;
- imageRect.localScale = Vector3.one;
- imageRect.anchoredPosition = initialAnchoredPosition;
- }
- return;
- }
- #endif
- HandleTouchZoom();
- ApplyInertia();
- }
- private void HandleTouchZoom()
- {
- if (Input.touchCount == 2)
- {
- Touch touchZero = Input.GetTouch(0);
- Touch touchOne = Input.GetTouch(1);
- if (touchZero.phase == TouchPhase.Moved || touchOne.phase == TouchPhase.Moved)
- {
- Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
- Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
- float prevDistance = Vector2.Distance(touchZeroPrevPos, touchOnePrevPos);
- float currentDistance = Vector2.Distance(touchZero.position, touchOne.position);
- float difference = currentDistance - prevDistance;
- ZoomImage(1 + difference * touchZoomSpeed, (touchZero.position + touchOne.position) / 2);
- }
- isTwo=true;
- }
- else if(Input.touchCount == 0)
- {
- isTwo=false;
- }
- }
- private void ApplyInertia()
- {
- if (!isDragging && velocity.magnitude > 0.1f)
- {
- imageRect.anchoredPosition += velocity * Time.deltaTime;
- velocity *= friction;
- ClampImagePosition();
- }
- else
- {
- velocity = Vector2.zero;
- }
- }
- public void OnBeginDrag(PointerEventData eventData)
- {
- if (Input.touchCount > 1) return;
-
- isDragging = true;
- lastDragPosition = eventData.position;
- }
- public void OnDrag(PointerEventData eventData)
- {
- if (Input.touchCount > 1 || currentZoom <= 1f) return;
-
- Vector2 delta = eventData.position - lastDragPosition;
- imageRect.anchoredPosition += delta * moveSpeed;
- velocity = delta * moveSpeed;
- lastDragPosition = eventData.position;
-
- ClampImagePosition();
- }
- public void OnEndDrag(PointerEventData eventData)
- {
- isDragging = false;
- }
- public void OnScroll(PointerEventData eventData)
- {
- float scrollDelta = eventData.scrollDelta.y;
- float zoomFactor = 1f + scrollDelta * zoomSpeed;
- ZoomImage(zoomFactor, eventData.position);
- }
- bool isTwo=false;
- public void OnPointerClick(PointerEventData eventData)
- {
- if (eventData.clickCount == 2)
- {
- HandleDoubleTap(eventData.position);
- }
- else if (eventData.clickCount == 1&&!isTwo)
- {
- float currentTime = Time.time;
- if (currentTime - lastTapTime < DoubleTapTime)
- {
- HandleDoubleTap(eventData.position);
- }
- lastTapTime = currentTime;
- }
- }
- private void HandleDoubleTap(Vector2 position)
- {
- if (currentZoom > 1f)
- {
- ResetView();
- }
- else
- {
- ZoomImage(2f, position);
- }
- }
- private void ZoomImage(float zoomFactor, Vector2 zoomCenter)
- {
- float newZoom = currentZoom * zoomFactor;
- newZoom = Mathf.Clamp(newZoom, minZoom, maxZoom);
-
- RectTransformUtility.ScreenPointToLocalPointInRectangle(
- imageRect,
- zoomCenter,
- null,
- out Vector2 localPoint);
-
- Vector2 pivotOffset = (Vector2)imageRect.pivot - new Vector2(0.5f, 0.5f);
- Vector2 offset = localPoint * (newZoom - currentZoom);
-
- imageRect.localScale = Vector3.one * newZoom;
-
- currentZoom = newZoom;
-
- ClampImagePosition();
- }
- private void ClampImagePosition()
- {
- if (currentZoom <= 1f)
- {
- imageRect.anchoredPosition = initialAnchoredPosition;
- return;
- }
- Vector3[] corners = new Vector3[4];
- imageRect.GetWorldCorners(corners);
-
- if (contentRect == null) return;
-
- Vector3[] contentCorners = new Vector3[4];
- contentRect.GetWorldCorners(contentCorners);
-
- float imageWidth = (corners[2].x - corners[0].x)*imageRect.localScale.x;
- float imageHeight = (corners[2].y - corners[0].y)*imageRect.localScale.x;
-
- float contentWidth = contentCorners[2].x - contentCorners[0].x;
- float contentHeight = contentCorners[2].y - contentCorners[0].y;
-
- float minX = contentWidth - imageWidth;
- float maxX = 0+ imageWidth;
- float minY = contentHeight - imageHeight;
- float maxY = 0+ imageHeight;
-
- Vector3 pos = imageRect.localPosition;
- pos.x = Mathf.Clamp(pos.x, minX, maxX);
- pos.y = Mathf.Clamp(pos.y, minY, maxY);
-
-
- if (pos.x != imageRect.localPosition.x || pos.y != imageRect.localPosition.y)
- {
- velocity = Vector2.zero;
- imageRect.localPosition = Vector3.Lerp(imageRect.localPosition, pos, elasticFactor);
- }
- else
- {
- imageRect.localPosition = pos;
- }
- }
- public void ResetView()
- {
- currentZoom = 1f;
- imageRect.localScale = Vector3.one;
- imageRect.anchoredPosition = initialAnchoredPosition;
- velocity = Vector2.zero;
- }
- #if UNITY_EDITOR
- private void OnValidate()
- {
- if (EditorApplication.isPlayingOrWillChangePlaymode) return;
-
- if (imageRect == null) imageRect = GetComponent<RectTransform>();
- if (contentRect == null && transform.parent != null)
- contentRect = transform.parent.GetComponent<RectTransform>();
-
- initialAnchoredPosition = imageRect.anchoredPosition;
- initialSizeDelta = imageRect.sizeDelta;
- }
- #endif
- }
|