文章目录[x]
- 0.1:另外一种简版只有拖动和缩放
项目中有个需求,控制视频矩阵输出到大屏幕上各个区域,里面的难点是各个区域大小位置可以自由编辑。想到类似很多程序界面也是这样的逻辑就查阅相关资料,找到了可以实现一下效果的项目。
Demo:http://webgl.horse7.cn/MDI
地址:https://github.com/Reavenk/UIDock_Dev
文章:https://pixeleuphoria.com/blog/index.php/notes-on-docking-splitter-auis/
抱歉,只有登录并在本文发表评论才能阅读隐藏内容
另外一种简版只有拖动和缩放
1.建三个脚本CursorManager .cs 、UIResize.cs、UIEdgeRectangle.cs
using UnityEngine; using System.Collections.Generic; /// <summary> /// 鼠标光标类型枚举 /// </summary> public enum CursorType { None, UpDown,//上下箭头 LeftRight,//左右箭头 LeftOblique,//左斜箭头 RightOblique//右斜箭头 } public class CursorManager : MonoBehaviour { public static CursorManager instance; private Dictionary<CursorType, Texture2D> dicCursors = new Dictionary<CursorType, Texture2D>(); private void Awake() { instance = this; } /// <summary> /// 加载鼠标光标保存到字典 /// </summary> public void LoadCursor() { string[] cursors = System.Enum.GetNames(typeof(CursorType)); for (int i = 0; i < cursors.Length; i++) { Texture2D sprite = Resources.Load<Texture2D>("cursor/" + cursors[i]); CursorType type = (CursorType)System.Enum.Parse(typeof(CursorType), cursors[i]);//根据字符串名转换为对应枚举类型 if (!dicCursors.ContainsKey(type)) { dicCursors.Add(type, sprite); } } } /// <summary> /// 根据枚举设置不同的鼠标光标 /// </summary> /// <param name="type"></param> public void SetCursor(CursorType type) { if (dicCursors.ContainsKey(type)) { //因为这里的光标图片大小是32*32像素的,所以需要设置切换光标后鼠标位置为该图片中心位置 //即偏移为(16,16),避免在UI边缘检测时出现误差 Cursor.SetCursor(dicCursors[type], new Vector2(16, 16), CursorMode.Auto); } } //恢复默认光标 public void SetDefaultCursor() { Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto); } }
using UnityEngine; //UI分成9宫格 各个边缘枚举 public enum UIEdge { None, Up, Down, Left, Right, TopRightCorner, BottomRightCorner, TopLeftCorner, BottomLeftCorner } public static class UIEdgeRectangle { public static float areaPixel = 10.0f;//边缘检测区域大小 private static Vector3[] corners = new Vector3[4]; /// <summary> /// UI边缘检测算法,获取UI边缘枚举 /// </summary> /// <param name="mousePos">鼠标点</param> /// <param name="rect">UI矩形框</param> /// <returns></returns> public static UIEdge GetUIEdge(Vector2 mousePos, RectTransform rect) { UIEdge uiEdge = UIEdge.None;//默认是None类型:表示中心区域 rect.GetLocalCorners(corners);//获取UI矩形四个边缘角的局部坐标 //上方矩形区域点 var up0 = new Vector2(corners[1].x + areaPixel, corners[1].y - areaPixel);//与左边矩形区域共用 var up1 = new Vector2(corners[1].x + areaPixel, corners[1].y); var up2 = new Vector2(corners[2].x - areaPixel, corners[2].y); var up3 = new Vector2(corners[2].x - areaPixel, corners[2].y - areaPixel);//与右边矩形区域共用 //下方矩形区域点 var down0 = new Vector2(corners[0].x + areaPixel, corners[0].y); var down1 = new Vector2(corners[0].x + areaPixel, corners[0].y + areaPixel);//与左边矩形区域共用 var down2 = new Vector2(corners[3].x - areaPixel, corners[3].y + areaPixel);//与右边矩形区域共用 var down3 = new Vector2(corners[3].x - areaPixel, corners[3].y); //左边矩形区域点 var left0 = new Vector2(corners[0].x, corners[0].y + areaPixel); var left1 = new Vector2(corners[1].x, corners[1].y - areaPixel); //右边矩形区域点 var right0 = new Vector2(corners[2].x, corners[2].y - areaPixel); var right1 = new Vector2(corners[3].x, corners[3].y + areaPixel); //判断鼠标位置处于那个区域 if (IsPointInRectangle(up0, up1, up2, up3, mousePos)) { uiEdge = UIEdge.Up;//鼠标点在up0、up1、up2和up3组成的矩形区域时返回枚举类型up:表示上方 } else if (IsPointInRectangle(down0, down1, down2, down3, mousePos)) { uiEdge = UIEdge.Down;//鼠标点在down0、down1、down2和down3组成的矩形区域时返回枚举类型down:表示下方 } else if (IsPointInRectangle(down1, left0, left1, up0, mousePos)) { uiEdge = UIEdge.Left;//鼠标点在down1、left0、left1和up0组成的矩形区域时返回枚举类型left:表示左边 } else if (IsPointInRectangle(up3, right0, right1, down2, mousePos)) { uiEdge = UIEdge.Right;//鼠标点在up3、right0、right1和down2组成的矩形区域时返回枚举类型right:表示下方 } else if (IsPointInRectangle(up3, up2, corners[2], right0, mousePos)) { uiEdge = UIEdge.TopRightCorner;//鼠标点在up3、up2、corners[2]和right0组成的矩形区域时返回枚举类型TopRightCorner:表示下方 } else if (IsPointInRectangle(down2, right1, corners[3], down3, mousePos)) { uiEdge = UIEdge.BottomRightCorner;//鼠标点在down2、right1、corners[3]和down3组成的矩形区域时返回枚举类型BottomRightCorner:表示下方 } else if (IsPointInRectangle(left1, corners[1], up1, up0, mousePos)) { uiEdge = UIEdge.TopLeftCorner;//鼠标点在left1、corners[1]、up1和up0组成的矩形区域时返回枚举类型TopLeftCorner:表示下方 } else if (IsPointInRectangle(corners[0], left0, down1, down0, mousePos)) { uiEdge = UIEdge.BottomLeftCorner;//鼠标点在corners[0]、left1、down1和down0组成的矩形区域时返回枚举类型BottomLeftCorner:表示下方 } return uiEdge; } // 计算两个向量的叉积 public static float Cross(Vector2 a, Vector2 b) { return a.x * b.y - b.x * a.y; } // 判断点E是否在ABCD组成的矩形框内 public static bool IsPointInRectangle(Vector2 A, Vector2 B, Vector2 C, Vector2 D, Vector2 E) { //计算E与ABCD矩形的叉积 bool value = Cross(A - B, A - E) * Cross(C - D, C - E) >= 0 && Cross(A - D, A - E) * Cross(C - B, C - E) >= 0; return value; } }
using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; /// <summary> /// UI拖拽拉伸 /// </summary> public class UIResize : MonoBehaviour, IDragHandler, IPointerExitHandler,IBeginDragHandler,IPointerDownHandler,IPointerEnterHandler { private Image img;//拖拽的对象 public Camera uicam;//渲染UI的相机 private RectTransform rect;//拖拽对象的矩形对象 private UIEdge currentUiEdge;//当前鼠标所在UI的边缘枚举 public float MinWidth = 100;//最小宽度 public float MinHeight = 100;//最小高度 private bool inRect;//是否处于rect内 private void Start() { CursorManager.instance.LoadCursor();//初始化加载鼠标光标 img = GetComponent<Image>(); rect = img.GetComponent<RectTransform>(); } /// <summary> /// 鼠标移出UI,恢复默认光标 /// </summary> /// <param name="eventData"></param> public void OnPointerExit(PointerEventData eventData) { CursorManager.instance.SetDefaultCursor(); inRect = false; } public void OnPointerEnter(PointerEventData eventData) { inRect = true; } public void OnBeginDrag(PointerEventData eventData) { } public void OnBeginDrag(PointerEventData eventData) { } /// <summary> /// 拖拽过程中,根据鼠标所在边缘区域动态修改该UI图片的右上偏移offsetMax或左下偏移offsetMin /// </summary> /// <param name="eventData"></param> public void OnDrag(PointerEventData eventData) { if (rect.sizeDelta.x < MinWidth) { rect.sizeDelta = new Vector2(MinWidth,rect.sizeDelta.y); return; } if(rect.sizeDelta.y < MinHeight) { rect.sizeDelta = new Vector2(rect.sizeDelta.x, MinHeight); return; } switch (currentUiEdge) { case UIEdge.None: rect.anchoredPosition += eventData.delta; break; case UIEdge.Up://UI上方 rect.offsetMax = new Vector2(rect.offsetMax.x, rect.offsetMax.y + eventData.delta.y); break; case UIEdge.Down://UI下方 rect.offsetMin = new Vector2(rect.offsetMin.x, rect.offsetMin.y + eventData.delta.y); break; case UIEdge.Left://UI左边 rect.offsetMin = new Vector2(rect.offsetMin.x + eventData.delta.x, rect.offsetMin.y); break; case UIEdge.Right://UI右边 rect.offsetMax = new Vector2(rect.offsetMax.x + eventData.delta.x, rect.offsetMax.y); break; case UIEdge.TopRightCorner://UI右上角 rect.offsetMax = rect.offsetMax + eventData.delta; break; case UIEdge.BottomRightCorner://UI右下角 rect.offsetMax = new Vector2(rect.offsetMax.x + eventData.delta.x, rect.offsetMax.y); rect.offsetMin = new Vector2(rect.offsetMin.x, rect.offsetMin.y + eventData.delta.y); break; case UIEdge.TopLeftCorner://UI左上角 rect.offsetMax = new Vector2(rect.offsetMax.x, rect.offsetMax.y + eventData.delta.y); rect.offsetMin = new Vector2(rect.offsetMin.x + eventData.delta.x, rect.offsetMin.y); break; case UIEdge.BottomLeftCorner://UI左下角 rect.offsetMin = rect.offsetMin + eventData.delta; break; } } private void Update() { if (!inRect) return; if (RectTransformUtility.RectangleContainsScreenPoint(rect, Input.mousePosition, uicam)) { Vector2 mousePos; //将鼠标的屏幕位置转为在该UI图片下的ui坐标 RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, Input.mousePosition, uicam, out mousePos); //进行UI边缘检测,判断鼠标位置在UI边缘的哪个位置,返回其边缘类型枚举 currentUiEdge = UIEdgeRectangle.GetUIEdge(mousePos, rect); switch (currentUiEdge)//根据边缘类型的情况切换鼠标光标 { case UIEdge.None: CursorManager.instance.SetDefaultCursor(); break; case UIEdge.Up: CursorManager.instance.SetCursor(CursorType.UpDown); break; case UIEdge.Down: CursorManager.instance.SetCursor(CursorType.UpDown); break; case UIEdge.Left: CursorManager.instance.SetCursor(CursorType.LeftRight); break; case UIEdge.Right: CursorManager.instance.SetCursor(CursorType.LeftRight); break; case UIEdge.TopRightCorner: CursorManager.instance.SetCursor(CursorType.RightOblique); break; case UIEdge.BottomRightCorner: CursorManager.instance.SetCursor(CursorType.LeftOblique); break; case UIEdge.TopLeftCorner: CursorManager.instance.SetCursor(CursorType.LeftOblique); break; case UIEdge.BottomLeftCorner: CursorManager.instance.SetCursor(CursorType.RightOblique); break; } } } }
1.把UIResize.cs挂载到带有RectTransform的物体上就可以了,为了美观我创建了一个Panel,然后又在下面创建了一些图片和文本(与要实现的功能无关)。
2.把CursorManager.cs挂载任意位置,能执行Awake就可以了。
3.导入用到的Cursor图片。
4.运行后就可以缩放和拖拽移动这个Panel了。
ps:EventSystem属性Threshold需要设的小一些,防止鼠标已经移除检测区域后才触发OnDrag(默认检测区域宽度为10,可以修改)。