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 }