一、组件功能概述
ViewportConstraint
是一个基于世界坐标的UI边界约束组件,主要功能包括:
- 将UI元素限制在父容器范围内
- 支持自定义内边距(padding)
- 可独立控制水平和垂直方向的约束
二、实现原理
1. 边界计算(世界坐标)
使用GetWorldCorners
方法获取四个顶点的世界坐标
2. 约束逻辑
如果元素左边界超出了容器左边界,则该元素需要往右移:
右移距离 = 容器左边界 - 元素左边界
将元素向右移动一定距离
三、代码
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 限制指定元素在显示区域内显示
/// </summary>
public class ViewportConstraint : MonoSingleton<ViewportConstraint>
{
string TAG = "[ViewportConstraint]";
[Header("容器")]
public RectTransform parentContainer;
[Header("内边距")]
public float padding = 30f;
[Header("约束元素")]
public List<RectTransform> elements = new List<RectTransform>();
[Header("约束方向")]
public bool constrainHorizontal = true;
public bool constrainVertical = true;
public void Refresh()
{
Debug.Log(TAG + "Refresh");
foreach (var target in elements)
{
Vector3[] parentCorners = new Vector3[4];
parentContainer.GetWorldCorners(parentCorners);
Vector3[] objCorners = new Vector3[4];
target.GetWorldCorners(objCorners);
if (constrainHorizontal)
{
// 计算显示区域
float displayLeft = parentCorners[0].x + padding;
float displayRight = parentCorners[2].x - padding;
// 计算子物体左右边界
float objLeft = objCorners[0].x;
float objRight = objCorners[2].x;
Vector3 pos = target.position;
// 左边越界
if (objLeft < displayLeft) pos.x += displayLeft - objLeft;
// 右边越界
else if (objRight > displayRight) pos.x += displayRight - objRight;
target.position = pos;
}
if(constrainVertical)
{
// 计算显示区域
float displayBottom = parentCorners[0].y + padding;
float displayTop = parentCorners[1].y - padding;
// 计算子物体上下边界
float objBottom = objCorners[0].y;
float objTop = objCorners[1].y;
Vector3 pos = target.position;
// 底部越界
if (objBottom < displayBottom) pos.y += displayBottom - objBottom;
// 顶部越界
else if (objTop > displayTop) pos.y += displayTop - objTop;
target.position = pos;
}
}
}
//注:目标物体须设定为锚点居中。
}