using UnityEngine;
///
/// 把两个纹理以缝合的方式显示的组件,需要下面有两个UITexture节点
///
[ExecuteInEditMode]
public class UISutureTexture : MonoBehaviour
{
//原始图片宽度和高度 比例默认是: h/w = 2.3
public int OrgImageW = 1984;
public int OrgImageH = 862;
//分割的两个图片分别宽度
public int PartImageW = 1024;
//中间重叠的宽度
public int OverlapW = 64;
//图片展示的宽度比例
public float wfactor;
//最外层控制大小的box
private UIWidget _box;
//左边的图片组件
private UITexture _left;
//右边的图片组件
private UITexture _right;
//左纹理
public Texture2D _leftTex;
//右纹理
public Texture2D _rightTex;
//组件深度
private int _depth;
private void OnEnable()
{
OnInit(transform);
}
private void OnDisable()
{
}
private void Start()
{
OnInit(transform);
}
private void OnValidate()
{
RefreshUI();
}
public void SetDepth(int depth)
{
_depth = depth;
RefreshUI();
}
public void SetTexture(UISutureTextureData data)
{
SetTexture(data.Left, data.Right);
}
//设置当前组件纹理
public void SetTexture(Texture2D left, Texture2D right)
{
_leftTex = left;
_rightTex = right;
RefreshUI();
OnBoxDimensionsChanged();
}
//清理当前组件上的纹理
public void ResetTexture()
{
_leftTex = null;
_rightTex = null;
if(_left != null) _left.mainTexture = null;
if (_right != null) _right.mainTexture = null;
}
//脚本初始化
private void OnInit(Transform trans)
{
if (_box == null)
{
_box = trans.GetComponent();
if (trans.childCount == 0)
{
CreateNode(trans, "Left");
CreateNode(trans, "Right");
}
else if (trans.childCount == 1)
{
CreateNode(trans, "Right");
}
_left = RequireComponent(trans.GetChild(0));
_right = RequireComponent(trans.GetChild(1));
_left.SetAnchor(_box.transform);
_right.SetAnchor(_box.transform);
_left.updateAnchors = UIRect.AnchorUpdate.OnUpdate;
_right.updateAnchors = UIRect.AnchorUpdate.OnUpdate;
_box.onChange = OnBoxDimensionsChanged;
_depth = _box.depth;
}
RefreshUI();
OnBoxDimensionsChanged();
}
private void CreateNode(Transform parent,string name)
{
GameObject go = new GameObject(name);
go.layer = parent.gameObject.layer;
go.transform.parent = parent;
go.transform.localPosition = Vector3.zero;
go.transform.localEulerAngles = Vector3.zero;
go.transform.localScale = Vector3.one;
}
//刷新UI
private void RefreshUI()
{
if (_box != null)
{
_box.depth = _depth;
if (_left != null)
{
_left.depth = _depth;
_left.mainTexture = _leftTex;
}
if (_right != null)
{
_right.depth = _depth;
_right.mainTexture = _rightTex;
}
}
}
//box的大小改变时回调处理
private void OnBoxDimensionsChanged()
{
try
{
if (_left != null && _right != null && _box != null)
{
wfactor = GetWidthClipScale(OrgImageW, OrgImageH, _box.width, _box.height);
var v = GetPartWRect(OrgImageW, PartImageW, wfactor);
float ol = GetScreenOverlapLen(OrgImageW, OverlapW, _box.width, wfactor) * 0.5f;
_left.uvRect = new Rect(v.x, 0f, v.y, 1f);
_right.uvRect = new Rect(v.z, 0f, v.w, 1f);
_left.leftAnchor.Set(0, 0);
_left.rightAnchor.Set(0.5f, ol);
_left.bottomAnchor.Set(0, 0);
_left.topAnchor.Set(1, 0);
_left.UpdateAnchors();
//针对小数部分,来进行调整
float frac = ol - Mathf.Floor(ol);
//如果大于0.5表示被误差大于1个像素.
if (frac >= 0.5)
{
//把右边的图片向左位移1个像素
ol = ol - 1;
}
_right.leftAnchor.Set(0.5f, -ol);
_right.rightAnchor.Set(1, 0);
_right.bottomAnchor.Set(0, 0);
_right.topAnchor.Set(1, 0);
_right.UpdateAnchors();
}
}
catch(System.Exception ex)
{
Debug.LogException(ex);
}
}
#region//静态方法
private static T RequireComponent(Transform trans)
where T : Component
{
T result = trans.GetComponent();
if (result == null)
{
result = trans.gameObject.AddComponent();
}
return result;
}
///
/// 根据屏幕的宽高比,以图片高为基准对图片宽度进行比例切割
///
///
///
/// 图片宽度被剪切后的比例
public static float GetWidthClipScale(float ImageW, float ImageH, float ScreenW, int ScreenH)
{
float wfactor = (ScreenW * ImageH) / (ScreenH * ImageW);
return wfactor > 1 ? 1f : wfactor;
}
///
/// 根据原始图片的宽度,以及分割后中间重叠的长度,获取图片在屏幕上的重叠长度,关于如何切割请看示例在本类的最后.
///
/// 原始图片的长度
/// 图片分割后中间重叠的长度
/// 屏幕的宽度
/// 图片宽度被剪切后的比例
///
public static float GetScreenOverlapLen(float OrgImageW, float ImageOverlapLen, float ScreenW, float Wfactor)
{
return ((ScreenW * ImageOverlapLen)) / ((OrgImageW * Wfactor));
}
///
/// 根据原始图片的宽度和子图片的宽度,以及原始赌片被剪切的比例,来获得两个两个部分的偏移和缩放 ,关于如何切割请看示例在本类的最后.
/// 注意:这里的计算图片的偏移和剪切都是以原始图片中心点为锚点的.
///
///
///
///
///
public static Vector4 GetPartWRect(float OrgImageW, float PartImageW, float Wfactor)
{
//首先计算左边图片的偏移比例
float leftOffset = OrgImageW * (1 - Wfactor) * 0.5f / PartImageW;
//左边展示的宽度比例
float leftClipScale = 1 - leftOffset;
//右边图片的偏移比例
float rightOffset = 0f;
//右边图片的宽度比例
float rightClipScale = leftClipScale;
return new Vector4(leftOffset, leftClipScale, rightOffset, rightClipScale);
}
/*
* 这个示例中:
* 原始图片宽度: OrgImageW : 1984
* 切割后的宽度: ImageW:1024
* 重叠部分的宽度: ImageOverlapLen:64
*
|<--------1984-------->|
|----------------------|
| |
| |
| |
|----------------------|
|<---1024--->|
|---------|--|---------|
| | | |
| | | |
| | | |
|---------|--|---------|
|<---1024--->|
|64|
*/
#endregion
}