using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UIElements; namespace MuHua { /// /// 滚动视图 - 垂直 /// public class UIScrollViewV : ModuleUIPanel, IDisposable { /// 绑定的画布 public readonly VisualElement canvas; /// 元素方向 public readonly UIDirection direction; /// 垂直滑块 public readonly UIScrollerV vertical; /// 值改变时 public event Action ValueChanged; /// /// 方向 /// public enum UIDirection { FromTopToBottom = 0, FromBottomToTop = 1, } public float value; public bool isDrag; public Vector3 originalPosition; public Vector3 pointerPosition; public readonly VisualElement Viewport; public readonly VisualElement Container; public readonly VisualElement ScrollerVertical; public UIScrollViewV(VisualElement element, VisualElement canvas, UIDirection direction = UIDirection.FromTopToBottom) : base(element) { this.canvas = canvas; this.direction = direction; Viewport = element.Children().FirstOrDefault(e => e.name == "Viewport"); Container = Viewport.Children().FirstOrDefault(e => e.name == "Container"); ScrollerVertical = element.Children().FirstOrDefault(e => e.name == "ScrollerVertical"); if (direction == UIDirection.FromTopToBottom) { vertical = new UIScrollerV(ScrollerVertical, canvas, UIScrollerV.UIDirection.FromTopToBottom); } if (direction == UIDirection.FromBottomToTop) { vertical = new UIScrollerV(ScrollerVertical, canvas, UIScrollerV.UIDirection.FromBottomToTop); } // 设置事件 vertical.ValueChanged += (y) => { UpdateValue(y); }; Viewport.RegisterCallback(ViewportWheel); Viewport.RegisterCallback(DraggerDown); Viewport.RegisterCallback(DraggerUpOrLeave); Viewport.style.flexDirection = direction == UIDirection.FromTopToBottom ? FlexDirection.Column : FlexDirection.ColumnReverse; // 释放 canvas.RegisterCallback(DraggerUpOrLeave); canvas.RegisterCallback(DraggerUpOrLeave); // 视图原始更新 element.generateVisualContent += ElementGenerateVisualContent; } /// 解绑事件,防止内存泄漏 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 height = Mathf.Clamp01(Viewport.resolvedStyle.height / Container.resolvedStyle.height); vertical.Dragger.style.height = Length.Percent(height * 100); } /// 滚轮滑动 private void ViewportWheel(WheelEvent evt) { float wheel = Mathf.Clamp(evt.delta.y, -1, 1); UpdateValue(value - wheel); } /// 拖拽按下 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 maxHeight = Viewport.resolvedStyle.height - Container.resolvedStyle.height; float y = offset.y / maxHeight; y *= direction == UIDirection.FromTopToBottom ? 1 : -1; UpdateValue(y); } /// 滑动弹性 private void SlidingElasticity() { float original = value; float max = Viewport.resolvedStyle.height < Container.resolvedStyle.height ? 1 : 0; if (value < 0) { value = Mathf.Lerp(value, 0, Time.deltaTime * 10); } if (value > max) { value = Mathf.Lerp(value, max, Time.deltaTime * 10); } if (original != value) { UpdateValue(value); } } /// 鼠标松开或离开 private void DraggerUpOrLeave(EventBase evt) { isDrag = false; } /// 更新状态 public virtual void Update() { vertical.Update(); SlidingElasticity(); if (isDrag) { Dragger(); } } /// 更新值(0-1) public virtual void UpdateValue(float value, bool send = true) { this.value = value; if (send) { ValueChanged?.Invoke(value); } float maxHeight = Viewport.resolvedStyle.height - Container.resolvedStyle.height; float position = maxHeight * value; position *= direction == UIDirection.FromTopToBottom ? 1 : -1; Container.transform.position = new Vector3(0, position); if (vertical.value != value) { vertical.UpdateValue(value, false); } } } }