ugui ui相对位置的计算,以及如何把ui限制在屏幕内
来源:互联网 发布:经期自慰 知乎 编辑:程序博客网 时间:2024/05/16 14:42
今天写关于ui位置的计算,举个例子:在我之前做的项目中背包的物品都可以点出一个属性面板,这个属性面板的左上角最齐图标的右下角,如图(红是物品图标,白是属性面板)
原理:计算出两个ui的包围盒就可以算出【白image】相对于【红image】的偏差多少坐标,然后用【红image】的position+偏差的坐标赋值给【白image】的世界坐标
如上图的方式,我这边举个例子(【红】的右下角对齐【白】的左上角)
【白】position.x =【红】position.x +【红】包围盒extents.x+【白】包围盒extents.x
【白】position.y =【红】position.x -【红】包围盒extents.y -【白】包围盒extents.y
这样就可以求出【白】的position,这里只给出一种情况,其他情况可以看下面代码
//枚举8个方向public enum UGUISide{ Bottom, BottomLeft, BottomRight, Left, Right, Top, TopLeft, TopRight,}public class MathEx{ /// <summary> /// src用描点对齐tar的描点,tar确定src的位置 /// </summary> /// <param name="src"></param> /// <param name="srcSide"></param> /// <param name="tar"></param> /// <param name="tarSide"></param> /// <param name="area"></param> public static void AnchorTo(RectTransform src, UGUISide srcSide, RectTransform tar, UGUISide tarSide, Transform canvas) { if (null == tar || tar == src) { return; } //计算src的包围盒 Bounds srcBounds = RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, src); //计算tar的包围盒 Bounds tarBounds = RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, tar); Vector2 srcOffset = GetBoundsOffset(srcBounds, srcSide);//计算描点的偏移量 Vector2 tarOffset = GetBoundsOffset(tarBounds, tarSide);//计算描点的偏移量 Vector2 tarCenter = tarBounds.center; //计算src相对于tar的位置 src.anchoredPosition = (tarCenter - tarOffset + srcOffset); } } //8个方向偏移值的计算 public static Vector2 GetBoundsOffset(Bounds bounds, UGUISide side) { Vector2 offset = Vector2.zero; switch (side) { case UGUISide.Bottom: offset.y = bounds.extents.y; break; case UGUISide.BottomLeft: offset.x = bounds.extents.x; offset.y = bounds.extents.y; break; case UGUISide.BottomRight: offset.x = -bounds.extents.x; offset.y = bounds.extents.y; break; case UGUISide.Left: offset.x = bounds.extents.x; break; case UGUISide.Right: offset.x = -bounds.extents.x; break; case UGUISide.Top: offset.y = -bounds.extents.y; break; case UGUISide.TopLeft: offset.x = bounds.extents.x; offset.y = -bounds.extents.y; break; case UGUISide.TopRight: offset.x = -bounds.extents.x; offset.y = -bounds.extents.y; break; } return offset; }
包围盒计算:RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, ui)两个参数都是Transform。【包围盒的中心点是从屏幕中心作为原点计算出来的】
位置计算比较简单我觉得看看代码就知道,不过如果物品图标右边对齐屏幕右边,这样计算就会超出屏幕,不过我想要的效果就如下图
这里就涉及到ugui的屏幕大小,知道ugui屏幕大小就知道它是否超出屏幕。如果超出屏幕,可以计算靠边位置。
ugui的屏幕大小与屏幕大小有点区别,不同的ui缩放模式就有ugui屏幕大小不同
现在讲解一下不同ui缩放模式,怎么计算ugui屏幕大小
二、在不同Ui Scale Mode下屏幕的rect的计算,以【屏幕中心为原点】(上面说了ui包围盒按照屏幕中心作为原点计算的)
1.Constant Pixel Size
这种模式下屏幕分辨率多大,ugui屏幕就多大
rect = new Rect(-Screen.width / 2, -Screen.height / 2, Screen.width , Screen.height);
2.Scale With Screen Size
match为1,就是高度适应,
Reference Resolution设置为960*640,因为美术出图都是按照这个分辨率
这样设置无论那种分辨率,ugui屏幕的高度都是640,所以根据屏幕Height和ugui屏幕的Height算出比例,来计算ugui屏幕的Width
rect = new Rect(-Screen.width / 2, -Screen.height / 2, Screen.width , Screen.height); float scale = CanvasScaler.matchWidthOrHeight == 1 ? CanvaScaler.referenceResolution.y / (float)Screen.height : CanvaScaler.referenceResolution.x / (float)Screen.width;rect = new Rect(rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);
第三种就不算,重点是第二种,用得最多还是第二种
三、区域比较
直接上代码,第一个参数就是【白】,第二个参数就是ugui屏幕的rect,第三个是画布
代码比较简单,我就不一一说明。
public static bool SetUIArea(RectTransform target, Rect area, Transform canvas) { Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, target); if (null == area) { return false; } Vector2 delta = default(Vector2); if (bounds.center.x - bounds.extents.x < area.x)//target超出area的左边框 { delta.x += Mathf.Abs(bounds.center.x - bounds.extents.x - area.x); } else if (bounds.center.x + bounds.extents.x > area.width / 2)//target超出area的右边框 { delta.x -= Mathf.Abs(bounds.center.x + bounds.extents.x - area.width / 2); } if (bounds.center.y - bounds.extents.y < area.y)//target超出area上边框 { delta.y += Mathf.Abs(bounds.center.y - bounds.extents.y - area.y); } else if (bounds.center.y + bounds.extents.y > area.height / 2)//target超出area的下边框 { delta.y -= Mathf.Abs(bounds.center.y + bounds.extents.y - area.height / 2); } //加上偏移位置算出在屏幕内的坐标 target.anchoredPosition += delta; return delta != default(Vector2); }
最后我这边上完整代码
using UnityEngine;using System.Collections;public enum UGUISide{ Bottom, BottomLeft, BottomRight, Left, Right, Top, TopLeft, TopRight,}public class MathEx{ /// <summary> /// src用描点对齐tar的描点,tar确定src的位置 /// </summary> /// <param name="src"></param> /// <param name="srcSide"></param> /// <param name="tar"></param> /// <param name="tarSide"></param> /// <param name="area"></param> public static void AnchorTo(RectTransform src, UGUISide srcSide, RectTransform tar, UGUISide tarSide,Transform canvas) { if (null == tar || tar == src) { return; } Bounds srcBounds = RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, src);//计算src的包围盒 Bounds tarBounds = RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, tar);//计算tar的包围盒 Vector2 srcOffset = GetBoundsOffset(srcBounds, srcSide);//计算描点的偏移量 Vector2 tarOffset = GetBoundsOffset(tarBounds, tarSide);//计算描点的偏移量 Vector2 tarCenter = tarBounds.center; //计算src相对于tar的位置 src.anchoredPosition = (tarCenter - tarOffset + srcOffset); } /// <summary> /// 注意rect中心点在中间 /// </summary> /// <param name="target"></param> /// <param name="area"></param> /// <returns></returns> public static bool SetUIArea(RectTransform target, Rect area, Transform canvas) { Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(canvas, target); if (null == area) { return false; } Vector2 delta = default(Vector2); if (bounds.center.x - bounds.extents.x < area.x)//target超出area的左边框 { delta.x += Mathf.Abs(bounds.center.x - bounds.extents.x - area.x); } else if (bounds.center.x + bounds.extents.x > area.width / 2)//target超出area的右边框 { delta.x -= Mathf.Abs(bounds.center.x + bounds.extents.x - area.width / 2); } if (bounds.center.y - bounds.extents.y < area.y)//target超出area上边框 { delta.y += Mathf.Abs(bounds.center.y - bounds.extents.y - area.y); } else if (bounds.center.y + bounds.extents.y > area.height / 2)//target超出area的下边框 { delta.y -= Mathf.Abs(bounds.center.y + bounds.extents.y - area.height / 2); } //加上偏移位置算出在屏幕内的坐标 target.anchoredPosition += delta; return delta != default(Vector2); } public static Vector2 GetBoundsOffset(Bounds bounds, UGUISide side) { Vector2 offset = Vector2.zero; switch (side) { case UGUISide.Bottom: offset.y = bounds.extents.y; break; case UGUISide.BottomLeft: offset.x = bounds.extents.x; offset.y = bounds.extents.y; break; case UGUISide.BottomRight: offset.x = -bounds.extents.x; offset.y = bounds.extents.y; break; case UGUISide.Left: offset.x = bounds.extents.x; break; case UGUISide.Right: offset.x = -bounds.extents.x; break; case UGUISide.Top: offset.y = -bounds.extents.y; break; case UGUISide.TopLeft: offset.x = bounds.extents.x; offset.y = -bounds.extents.y; break; case UGUISide.TopRight: offset.x = -bounds.extents.x; offset.y = -bounds.extents.y; break; } return offset; }
测试脚本
using UnityEngine;using System.Collections;using System.Data;using Mono.Data.Sqlite;using UnityEngine.UI;using DG.Tweening;public class Test : MonoBehaviour{ public RectTransform rt1; public RectTransform rt2; private Rect rect; CanvasScaler canvaScaler; void Awake() { canvaScaler = GetComponent<CanvasScaler>(); rect = new Rect(-Screen.width / 2, -Screen.height / 2, Screen.width , Screen.height); float scale = canvaScaler.matchWidthOrHeight == 1 ? canvaScaler.referenceResolution.y / (float)Screen.height : canvaScaler.referenceResolution.x / (float)Screen.width; rect = new Rect(rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale); } void Update() { if (null == rt1 || null == rt2) { return; } MathEx.AnchorTo(rt1, UGUISide.TopLeft, rt2, UGUISide.BottomRight, transform); MathEx.SetUIArea(rt1, rect, transform); }}
测试结构
这样子就可以把ui限制在某个区域内。
下一期分享,世界坐标转屏幕坐标,不用设置描点为左下角,也可以做。以及拖拽坐标的计算
- ugui ui相对位置的计算,以及如何把ui限制在屏幕内
- unity3d ugui中如何获取ui控件位置?或者说如何将ugui中ui控件(组件)的坐标转化为屏幕坐标或canvas坐标(大坑)?
- UGUI 如何检测UI的双击
- UI之把一个控件在屏幕内做任意拖拽并得到时时坐标
- ugui 点击在ui和非ui的判断
- UGUI的UI自动填充整个屏幕的脚本
- 在UGUI中如何防止鼠标点穿UI
- UGUI如何判断鼠标是否在UI上
- ugui与ngui如何检测是否点击在UI上
- IOS界面UI设计10之屏幕适配UITarbar、柱状图、相对位置
- UGUI如何在UI与UI直接穿插粒子特效和模型
- UGUI让模型显示在UI前面的设置
- UGUI播放UI特效以及解决特效与UI的层级问题
- UGUI 如何判断鼠标停在UI上
- Unity UGUI 是否点击在UI上
- 【Unity3D ugui】UI特效的位置自适应及调整层次关系的一种解决方案
- UGUI Unity内建UI系统的认识和一些问题的解决方案
- 【UGUI】UGUI 防止UI穿透
- Linux—命令效率大于拖拖拽拽
- 数据库之基础2
- equals、HashCode与实体类的设计
- Deep Learning(深度学习)学习笔记整理
- centos7.0装搜狗拼音 sougou
- ugui ui相对位置的计算,以及如何把ui限制在屏幕内
- Android 编辑框增加圆角边框
- npm使用介绍
- Java高级部分容器重点总结下
- C#定时器的实现
- UIControl类控件(二)
- [leetcode 280] Wiggle Sort
- 51NOD 1305 Pairwise Sum and Divide
- 快速排序