using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UIElements; namespace MuHua { /// /// 滚动视图 /// public class UIScrollView : ModuleUIPanel, UIControl { /// 绑定的画布 public readonly VisualElement canvas; /// 水平滑块 public readonly UIScrollerH horizontal; /// 垂直滑块 public readonly UIScrollerV vertical; /// 值改变时 public event Action ValueChanged; public Vector2 value; public bool isDrag; public Vector3 originalPosition; public Vector3 pointerPosition; public readonly VisualElement Viewport; public readonly VisualElement Container; public readonly VisualElement ScrollerHorizontal; public readonly VisualElement ScrollerVertical; public UIScrollView(VisualElement element, VisualElement canvas) : base(element) { this.canvas = canvas; Viewport = element.Children().FirstOrDefault(e => e.name == "Viewport"); Container = Viewport.Children().FirstOrDefault(e => e.name == "Container"); ScrollerHorizontal = element.Children().FirstOrDefault(e => e.name == "ScrollerHorizontal"); ScrollerVertical = element.Children().FirstOrDefault(e => e.name == "ScrollerVertical"); element.generateVisualContent += ElementGenerateVisualContent; horizontal = new UIScrollerH(ScrollerHorizontal, canvas, UIScrollerH.UIDirection.FromLeftToRight); vertical = new UIScrollerV(ScrollerVertical, canvas, UIScrollerV.UIDirection.FromTopToBottom); // 设置事件 horizontal.ValueChanged += (x) => { UpdateValue(new Vector2(x, value.y)); }; vertical.ValueChanged += (y) => { UpdateValue(new Vector2(value.x, y)); }; Viewport.RegisterCallback(ViewportWheel); Viewport.RegisterCallback(DraggerDown); Viewport.RegisterCallback(DraggerUpOrLeave); // 释放 canvas.RegisterCallback(DraggerUpOrLeave); canvas.RegisterCallback(DraggerUpOrLeave); } /// 解绑事件,防止内存泄漏 public virtual void Dispose() { Viewport.UnregisterCallback(ViewportWheel); Viewport.UnregisterCallback(DraggerDown); Viewport.UnregisterCallback(DraggerUpOrLeave); canvas.UnregisterCallback(DraggerUpOrLeave); canvas.UnregisterCallback(DraggerUpOrLeave); element.generateVisualContent -= ElementGenerateVisualContent; } /// 视图原始更新 private void ElementGenerateVisualContent(MeshGenerationContext context) { float width = Mathf.Clamp01(Viewport.resolvedStyle.width / Container.resolvedStyle.width); horizontal.Dragger.style.width = Length.Percent(width * 100); float height = Mathf.Clamp01(Viewport.resolvedStyle.height / Container.resolvedStyle.height); vertical.Dragger.style.height = Length.Percent(height * 100); } /// 视图滚轮滑动 private void ViewportWheel(WheelEvent evt) { float maxWidth = Viewport.resolvedStyle.width - Container.resolvedStyle.width; float minWidth = Mathf.Min(Viewport.resolvedStyle.width, Container.resolvedStyle.width); float x = evt.delta.x * minWidth / maxWidth; float maxHeight = Viewport.resolvedStyle.height - Container.resolvedStyle.height; float minHeight = Mathf.Min(Viewport.resolvedStyle.height, Container.resolvedStyle.height); float y = evt.delta.y * minHeight / maxHeight; value = value - new Vector2(x, y); UpdateValue(value); } /// 拖拽按下 private void DraggerDown(PointerDownEvent evt) { isDrag = true; originalPosition = Container.transform.position; Vector3 mousePosition = UITool.GetMousePosition(); pointerPosition = new Vector3(mousePosition.x, Screen.height - mousePosition.y); } /// 拖拽滑动 private void Dragger() { Vector3 mousePosition = UITool.GetMousePosition(); Vector3 differ = new Vector3(mousePosition.x, Screen.height - mousePosition.y) - pointerPosition; Vector3 offset = differ + originalPosition; float maxWidth = Viewport.resolvedStyle.width - Container.resolvedStyle.width; float x = offset.x / maxWidth; float maxHeight = Viewport.resolvedStyle.height - Container.resolvedStyle.height; float y = offset.y / maxHeight; UpdateValue(new Vector2(x, y)); } /// 滑动弹性 private void SlidingElasticity() { Vector2 original = value; float maxX = Viewport.resolvedStyle.width < Container.resolvedStyle.width ? 1 : 0; if (value.x < 0) { value.x = Mathf.Lerp(value.x, 0, Time.deltaTime * 10); } if (value.x > maxX) { value.x = Mathf.Lerp(value.x, maxX, Time.deltaTime * 10); } float maxY = Viewport.resolvedStyle.height < Container.resolvedStyle.height ? 1 : 0; if (value.y < 0) { value.y = Mathf.Lerp(value.y, 0, Time.deltaTime * 10); } if (value.y > maxY) { value.y = Mathf.Lerp(value.y, maxY, Time.deltaTime * 10); } if (original != value) { UpdateValue(value); } } /// 鼠标松开或离开 private void DraggerUpOrLeave(EventBase evt) { isDrag = false; } /// 更新状态 public virtual void Update() { horizontal.Update(); vertical.Update(); SlidingElasticity(); if (isDrag) { Dragger(); } } /// 更新值(0-1) public void UpdateValue(Vector2 value, bool send = true) { this.value = value; if (send) { ValueChanged?.Invoke(value); } float maxWidth = Viewport.resolvedStyle.width - Container.resolvedStyle.width; float x = maxWidth * value.x; float maxHeight = Viewport.resolvedStyle.height - Container.resolvedStyle.height; float y = maxHeight * value.y; Container.transform.position = new Vector3(x, y); if (horizontal.value != value.x) { horizontal.UpdateValue(value.x, false); } if (vertical.value != value.y) { vertical.UpdateValue(value.y, false); } } } }