#region Copyright RenGuiYou. All rights reserved. //===================================================== // NeatlyFrameWork // Author: RenGuiyou // Feedback: mailto:750539605@qq.com //===================================================== #endregion using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.Sprites; namespace Neatly.UI { public sealed class NImage : NImageBase, ISerializationCallbackReceiver, ILayoutElement { [SerializeField] private bool m_SupportRtl; //X = left, Y = bottom, Z = right, W = top. private static Dictionary PaddingConfig { get { return NeatlyUI.PaddingConfig; } } #region Type枚举 public enum Type { Simple, Sliced, Tiled, Filled } public enum FillMethod { Horizontal, Vertical, Radial90, Radial180, Radial360, } public enum OriginHorizontal { Left, Right, } public enum OriginVertical { Bottom, Top, } public enum Origin90 { BottomLeft, TopLeft, TopRight, BottomRight, } public enum Origin180 { Bottom, Left, Top, Right, } public enum Origin360 { Bottom, Right, Top, Left, } #endregion [SerializeField] private Type m_Type = Type.Simple; public Type type { get { return m_Type; } set { if (SetPropertyUtility.SetStruct(ref m_Type, value)) SetVerticesDirty(); } } #region Fill SerializeField [SerializeField] private bool m_FillCenter = true; public bool fillCenter { get { return m_FillCenter; } set { if (SetPropertyUtility.SetStruct(ref m_FillCenter, value)) SetVerticesDirty(); } } /// Filling method for filled sprites. [SerializeField] private FillMethod m_FillMethod = FillMethod.Radial360; public FillMethod fillMethod { get { return m_FillMethod; } set { if (SetPropertyUtility.SetStruct(ref m_FillMethod, value)) { SetVerticesDirty(); m_FillOrigin = 0; } } } /// Amount of the Image shown. 0-1 range with 0 being nothing shown, and 1 being the full Image. [Range(0, 1)] [SerializeField] private float m_FillAmount = 1.0f; public float fillAmount { get { return m_FillAmount; } set { if (SetPropertyUtility.SetStruct(ref m_FillAmount, Mathf.Clamp01(value))) SetVerticesDirty(); } } /// Whether the Image should be filled clockwise (true) or counter-clockwise (false). [SerializeField] private bool m_FillClockwise = true; public bool fillClockwise { get { return m_FillClockwise; } set { if (SetPropertyUtility.SetStruct(ref m_FillClockwise, value)) SetVerticesDirty(); } } /// Controls the origin point of the Fill process. Value means different things with each fill method. [SerializeField] private int m_FillOrigin; public int fillOrigin { get { return m_FillOrigin; } set { if (SetPropertyUtility.SetStruct(ref m_FillOrigin, value)) SetVerticesDirty(); } } #endregion public bool hasBorder { get { if (activeSprite != null) { Vector4 v = activeSprite.border; return v.sqrMagnitude > 0f; } return false; } } public float pixelsPerUnit { get { float spritePixelsPerUnit = 100; if (activeSprite) spritePixelsPerUnit = activeSprite.pixelsPerUnit; float referencePixelsPerUnit = 100; if (canvas) referencePixelsPerUnit = canvas.referencePixelsPerUnit; return spritePixelsPerUnit / referencePixelsPerUnit; } } #if UNITY_EDITOR protected override void OnValidate() { base.OnValidate(); if (!UseSpritePacker && !string.IsNullOrEmpty(m_SpriteName)) { UIUtility.SetImageSprite(this, m_SpriteName); } } #endif #region 序列化、布局接口的函数继承 public void OnBeforeSerialize() { } public void OnAfterDeserialize() { if (m_FillOrigin < 0) m_FillOrigin = 0; else if (m_FillMethod == FillMethod.Horizontal && m_FillOrigin > 1) m_FillOrigin = 0; else if (m_FillMethod == FillMethod.Vertical && m_FillOrigin > 1) m_FillOrigin = 0; else if (m_FillOrigin > 3) m_FillOrigin = 0; m_FillAmount = Mathf.Clamp(m_FillAmount, 0f, 1f); } public void CalculateLayoutInputHorizontal() { } public void CalculateLayoutInputVertical() { } public float minWidth { get { return 0; } } public float preferredWidth { get { if (activeSprite == null) return 0; if (type == Type.Sliced || type == Type.Tiled) return DataUtility.GetMinSize(activeSprite).x / pixelsPerUnit; return activeSprite.rect.size.x / pixelsPerUnit; } } public float flexibleWidth { get { return -1; } } public float minHeight { get { return 0; } } public float preferredHeight { get { if (activeSprite == null) return 0; if (type == Type.Sliced || type == Type.Tiled) return DataUtility.GetMinSize(activeSprite).y / pixelsPerUnit; return activeSprite.rect.size.y / pixelsPerUnit; } } public float flexibleHeight { get { return -1; } } public int layoutPriority { get { return 0; } } #endregion #region Image绘制 protected override void OnPopulateMesh(VertexHelper toFill) { if (activeSprite == null) { base.OnPopulateMesh(toFill); return; } switch (type) { case Type.Simple: GenerateSimpleSprite(toFill); break; case Type.Sliced: GenerateSlicedSprite(toFill); break; case Type.Tiled: GenerateTiledSprite(toFill); break; case Type.Filled: GenerateFilledSprite(toFill); break; } } //绘制Sprite Simple模式 void GenerateSimpleSprite(VertexHelper vh) { Vector4 v = GetDrawingDimensions(); var uv = (activeSprite != null) ? DataUtility.GetOuterUV(activeSprite) : Vector4.zero; var color32 = color; vh.Clear(); if (Application.isPlaying && NeatlyUI.IsRtlAction != null && m_SupportRtl && NeatlyUI.IsRtlAction()) { vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.z, uv.y)); vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.z, uv.w)); vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.x, uv.w)); vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.x, uv.y)); } else { vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y)); vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w)); vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w)); vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y)); } vh.AddTriangle(0, 1, 2); vh.AddTriangle(2, 3, 0); } static readonly Vector2[] s_VertScratch = new Vector2[4]; static readonly Vector2[] s_UVScratch = new Vector2[4]; private void GenerateSlicedSprite(VertexHelper toFill) { if (!hasBorder) { GenerateSimpleSprite(toFill); return; } Vector4 outer, inner, border; if (activeSprite != null) { outer = DataUtility.GetOuterUV(activeSprite); inner = DataUtility.GetInnerUV(activeSprite); border = activeSprite.border; } else { outer = Vector4.zero; inner = Vector4.zero; border = Vector4.zero; } Rect rect = GetPixelAdjustedRect(); border = GetAdjustedBorders(border / pixelsPerUnit, rect); Vector4 v = GetSlicedDiamons(); if (Application.isPlaying && NeatlyUI.IsRtlAction != null && m_SupportRtl && NeatlyUI.IsRtlAction()) { border = new Vector4(border.z, border.y, border.x, border.w); outer = new Vector4(outer.z, outer.y, outer.x, outer.w); inner = new Vector4(inner.z, inner.y, inner.x, inner.w); } s_VertScratch[0] = new Vector2(v.x, v.y); s_VertScratch[3] = new Vector2(v.z, v.w); s_VertScratch[1].x = border.x + s_VertScratch[0].x; s_VertScratch[1].y = border.y + s_VertScratch[0].y; s_VertScratch[2].x = s_VertScratch[3].x - border.z; s_VertScratch[2].y = s_VertScratch[3].y - border.w; s_UVScratch[0] = new Vector2(outer.x, outer.y); s_UVScratch[1] = new Vector2(inner.x, inner.y); s_UVScratch[2] = new Vector2(inner.z, inner.w); s_UVScratch[3] = new Vector2(outer.z, outer.w); toFill.Clear(); for (int x = 0; x < 3; ++x) { int x2 = x + 1; for (int y = 0; y < 3; ++y) { if (!fillCenter && x == 1 && y == 1) continue; int y2 = y + 1; AddQuad(toFill, new Vector2(s_VertScratch[x].x, s_VertScratch[y].y), new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y), color, new Vector2(s_UVScratch[x].x, s_UVScratch[y].y), new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y)); } } } void GenerateTiledSprite(VertexHelper toFill) { Vector4 outer, inner, border; Vector2 spriteSize; if (activeSprite != null) { outer = DataUtility.GetOuterUV(activeSprite); inner = DataUtility.GetInnerUV(activeSprite); border = activeSprite.border; spriteSize = activeSprite.rect.size; } else { outer = Vector4.zero; inner = Vector4.zero; border = Vector4.zero; spriteSize = Vector2.one * 100; } Rect rect = GetPixelAdjustedRect(); float tileWidth = (spriteSize.x - border.x - border.z) / pixelsPerUnit; float tileHeight = (spriteSize.y - border.y - border.w) / pixelsPerUnit; border = GetAdjustedBorders(border / pixelsPerUnit, rect); var uvMin = new Vector2(inner.x, inner.y); var uvMax = new Vector2(inner.z, inner.w); // var v = UIVertex.simpleVert; // v.color = color; // Min to max max range for tiled region in coordinates relative to lower left corner. float xMin = border.x; float xMax = rect.width - border.z; float yMin = border.y; float yMax = rect.height - border.w; toFill.Clear(); var clipped = uvMax; // if either with is zero we cant tile so just assume it was the full width. if (tileWidth <= 0) tileWidth = xMax - xMin; if (tileHeight <= 0) tileHeight = yMax - yMin; if (m_FillCenter) { for (float y1 = yMin; y1 < yMax; y1 += tileHeight) { float y2 = y1 + tileHeight; if (y2 > yMax) { clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); y2 = yMax; } clipped.x = uvMax.x; for (float x1 = xMin; x1 < xMax; x1 += tileWidth) { float x2 = x1 + tileWidth; if (x2 > xMax) { clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); x2 = xMax; } AddQuad(toFill, new Vector2(x1, y1) + rect.position, new Vector2(x2, y2) + rect.position, color, uvMin, clipped); } } } if (hasBorder) { clipped = uvMax; for (float y1 = yMin; y1 < yMax; y1 += tileHeight) { float y2 = y1 + tileHeight; if (y2 > yMax) { clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); y2 = yMax; } AddQuad(toFill, new Vector2(0, y1) + rect.position, new Vector2(xMin, y2) + rect.position, color, new Vector2(outer.x, uvMin.y), new Vector2(uvMin.x, clipped.y)); AddQuad(toFill, new Vector2(xMax, y1) + rect.position, new Vector2(rect.width, y2) + rect.position, color, new Vector2(uvMax.x, uvMin.y), new Vector2(outer.z, clipped.y)); } // Bottom and top tiled border clipped = uvMax; for (float x1 = xMin; x1 < xMax; x1 += tileWidth) { float x2 = x1 + tileWidth; if (x2 > xMax) { clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); x2 = xMax; } AddQuad(toFill, new Vector2(x1, 0) + rect.position, new Vector2(x2, yMin) + rect.position, color, new Vector2(uvMin.x, outer.y), new Vector2(clipped.x, uvMin.y)); AddQuad(toFill, new Vector2(x1, yMax) + rect.position, new Vector2(x2, rect.height) + rect.position, color, new Vector2(uvMin.x, uvMax.y), new Vector2(clipped.x, outer.w)); } // Corners AddQuad(toFill, new Vector2(0, 0) + rect.position, new Vector2(xMin, yMin) + rect.position, color, new Vector2(outer.x, outer.y), new Vector2(uvMin.x, uvMin.y)); AddQuad(toFill, new Vector2(xMax, 0) + rect.position, new Vector2(rect.width, yMin) + rect.position, color, new Vector2(uvMax.x, outer.y), new Vector2(outer.z, uvMin.y)); AddQuad(toFill, new Vector2(0, yMax) + rect.position, new Vector2(xMin, rect.height) + rect.position, color, new Vector2(outer.x, uvMax.y), new Vector2(uvMin.x, outer.w)); AddQuad(toFill, new Vector2(xMax, yMax) + rect.position, new Vector2(rect.width, rect.height) + rect.position, color, new Vector2(uvMax.x, uvMax.y), new Vector2(outer.z, outer.w)); } } static void AddQuad(VertexHelper vertexHelper, Vector3[] quadPositions, Color32 color, Vector3[] quadUVs) { int startIndex = vertexHelper.currentVertCount; for (int i = 0; i < 4; ++i) vertexHelper.AddVert(quadPositions[i], color, quadUVs[i]); vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax) { int startIndex = vertexHelper.currentVertCount; vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y)); vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y)); vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y)); vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y)); vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } Vector4 GetAdjustedBorders(Vector4 border, Rect rect) { for (int axis = 0; axis <= 1; axis++) { // If the rect is smaller than the combined borders, then there's not room for the borders at their normal size. // In order to avoid artefacts with overlapping borders, we scale the borders down to fit. float combinedBorders = border[axis] + border[axis + 2]; if (rect.size[axis] < combinedBorders && combinedBorders != 0) { float borderScaleRatio = rect.size[axis] / combinedBorders; border[axis] *= borderScaleRatio; border[axis + 2] *= borderScaleRatio; } } return border; } /// /// Generate vertices for a filled Image. /// private static readonly Vector3[] s_Xy = new Vector3[4]; private static readonly Vector3[] s_Uv = new Vector3[4]; void GenerateFilledSprite(VertexHelper toFill) { toFill.Clear(); if (m_FillAmount < 0.001f) return; Vector4 v = GetDrawingDimensions(); Vector4 outer = activeSprite != null ? DataUtility.GetOuterUV(activeSprite) : Vector4.zero; float tx0 = outer.x; float ty0 = outer.y; float tx1 = outer.z; float ty1 = outer.w; // Horizontal and vertical filled sprites are simple -- just end the Image prematurely if (m_FillMethod == FillMethod.Horizontal || m_FillMethod == FillMethod.Vertical) { if (fillMethod == FillMethod.Horizontal) { float fill = (tx1 - tx0) * m_FillAmount; if (m_FillOrigin == 1) { v.x = v.z - (v.z - v.x) * m_FillAmount; tx0 = tx1 - fill; } else { v.z = v.x + (v.z - v.x) * m_FillAmount; tx1 = tx0 + fill; } } else if (fillMethod == FillMethod.Vertical) { float fill = (ty1 - ty0) * m_FillAmount; if (m_FillOrigin == 1) { v.y = v.w - (v.w - v.y) * m_FillAmount; ty0 = ty1 - fill; } else { v.w = v.y + (v.w - v.y) * m_FillAmount; ty1 = ty0 + fill; } } } s_Xy[0] = new Vector2(v.x, v.y); s_Xy[1] = new Vector2(v.x, v.w); s_Xy[2] = new Vector2(v.z, v.w); s_Xy[3] = new Vector2(v.z, v.y); s_Uv[0] = new Vector2(tx0, ty0); s_Uv[1] = new Vector2(tx0, ty1); s_Uv[2] = new Vector2(tx1, ty1); s_Uv[3] = new Vector2(tx1, ty0); { if (m_FillAmount < 1f && m_FillMethod != FillMethod.Horizontal && m_FillMethod != FillMethod.Vertical) { if (fillMethod == FillMethod.Radial90) { if (RadialCut(s_Xy, s_Uv, m_FillAmount, m_FillClockwise, m_FillOrigin)) AddQuad(toFill, s_Xy, color, s_Uv); } else if (fillMethod == FillMethod.Radial180) { for (int side = 0; side < 2; ++side) { float fx0, fx1, fy0, fy1; int even = m_FillOrigin > 1 ? 1 : 0; if (m_FillOrigin == 0 || m_FillOrigin == 2) { fy0 = 0f; fy1 = 1f; if (side == even) { fx0 = 0f; fx1 = 0.5f; } else { fx0 = 0.5f; fx1 = 1f; } } else { fx0 = 0f; fx1 = 1f; if (side == even) { fy0 = 0.5f; fy1 = 1f; } else { fy0 = 0f; fy1 = 0.5f; } } s_Xy[0].x = Mathf.Lerp(v.x, v.z, fx0); s_Xy[1].x = s_Xy[0].x; s_Xy[2].x = Mathf.Lerp(v.x, v.z, fx1); s_Xy[3].x = s_Xy[2].x; s_Xy[0].y = Mathf.Lerp(v.y, v.w, fy0); s_Xy[1].y = Mathf.Lerp(v.y, v.w, fy1); s_Xy[2].y = s_Xy[1].y; s_Xy[3].y = s_Xy[0].y; s_Uv[0].x = Mathf.Lerp(tx0, tx1, fx0); s_Uv[1].x = s_Uv[0].x; s_Uv[2].x = Mathf.Lerp(tx0, tx1, fx1); s_Uv[3].x = s_Uv[2].x; s_Uv[0].y = Mathf.Lerp(ty0, ty1, fy0); s_Uv[1].y = Mathf.Lerp(ty0, ty1, fy1); s_Uv[2].y = s_Uv[1].y; s_Uv[3].y = s_Uv[0].y; float val = m_FillClockwise ? fillAmount * 2f - side : m_FillAmount * 2f - (1 - side); if (RadialCut(s_Xy, s_Uv, Mathf.Clamp01(val), m_FillClockwise, ((side + m_FillOrigin + 3) % 4))) { AddQuad(toFill, s_Xy, color, s_Uv); } } } else if (fillMethod == FillMethod.Radial360) { for (int corner = 0; corner < 4; ++corner) { float fx0, fx1, fy0, fy1; if (corner < 2) { fx0 = 0f; fx1 = 0.5f; } else { fx0 = 0.5f; fx1 = 1f; } if (corner == 0 || corner == 3) { fy0 = 0f; fy1 = 0.5f; } else { fy0 = 0.5f; fy1 = 1f; } s_Xy[0].x = Mathf.Lerp(v.x, v.z, fx0); s_Xy[1].x = s_Xy[0].x; s_Xy[2].x = Mathf.Lerp(v.x, v.z, fx1); s_Xy[3].x = s_Xy[2].x; s_Xy[0].y = Mathf.Lerp(v.y, v.w, fy0); s_Xy[1].y = Mathf.Lerp(v.y, v.w, fy1); s_Xy[2].y = s_Xy[1].y; s_Xy[3].y = s_Xy[0].y; s_Uv[0].x = Mathf.Lerp(tx0, tx1, fx0); s_Uv[1].x = s_Uv[0].x; s_Uv[2].x = Mathf.Lerp(tx0, tx1, fx1); s_Uv[3].x = s_Uv[2].x; s_Uv[0].y = Mathf.Lerp(ty0, ty1, fy0); s_Uv[1].y = Mathf.Lerp(ty0, ty1, fy1); s_Uv[2].y = s_Uv[1].y; s_Uv[3].y = s_Uv[0].y; float val = m_FillClockwise ? m_FillAmount * 4f - ((corner + m_FillOrigin) % 4) : m_FillAmount * 4f - (3 - ((corner + m_FillOrigin) % 4)); if (RadialCut(s_Xy, s_Uv, Mathf.Clamp01(val), m_FillClockwise, ((corner + 2) % 4))) AddQuad(toFill, s_Xy, color, s_Uv); } } } else { AddQuad(toFill, s_Xy, color, s_Uv); } } } /// /// Adjust the specified quad, making it be radially filled instead. /// static bool RadialCut(Vector3[] xy, Vector3[] uv, float fill, bool invert, int corner) { // Nothing to fill if (fill < 0.001f) return false; // Even corners invert the fill direction if ((corner & 1) == 1) invert = !invert; // Nothing to adjust if (!invert && fill > 0.999f) return true; // Convert 0-1 value into 0 to 90 degrees angle in radians float angle = Mathf.Clamp01(fill); if (invert) angle = 1f - angle; angle *= 90f * Mathf.Deg2Rad; // Calculate the effective X and Y factors float cos = Mathf.Cos(angle); float sin = Mathf.Sin(angle); RadialCut(xy, cos, sin, invert, corner); RadialCut(uv, cos, sin, invert, corner); return true; } /// /// Adjust the specified quad, making it be radially filled instead. /// static void RadialCut(Vector3[] xy, float cos, float sin, bool invert, int corner) { int i0 = corner; int i1 = ((corner + 1) % 4); int i2 = ((corner + 2) % 4); int i3 = ((corner + 3) % 4); if ((corner & 1) == 1) { if (sin > cos) { cos /= sin; sin = 1f; if (invert) { xy[i1].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); xy[i2].x = xy[i1].x; } } else if (cos > sin) { sin /= cos; cos = 1f; if (!invert) { xy[i2].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); xy[i3].y = xy[i2].y; } } else { cos = 1f; sin = 1f; } if (!invert) xy[i3].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); else xy[i1].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); } else { if (cos > sin) { sin /= cos; cos = 1f; if (!invert) { xy[i1].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); xy[i2].y = xy[i1].y; } } else if (sin > cos) { cos /= sin; sin = 1f; if (invert) { xy[i2].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); xy[i3].x = xy[i2].x; } } else { cos = 1f; sin = 1f; } if (invert) xy[i3].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); else xy[i1].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); } } private Vector4 GetPadding() { if (Application.isPlaying) { if (PaddingConfig == null) { Debug.LogError("[padding] 图集信息未初始化"); return Vector4.zero; } if (string.IsNullOrEmpty(SpriteName)) { return Vector4.zero; } if (PaddingConfig.ContainsKey(SpriteName)) { return PaddingConfig[SpriteName]; } if (!string.IsNullOrEmpty(SpriteName)) { Debug.LogErrorFormat("[padding] 数据缺失:{0}", SpriteName); } return Vector4.zero; } #if UNITY_EDITOR if (!activeSprite) return Vector4.zero; if (UseSpritePacker) { return DataUtility.GetPadding(activeSprite); } var editorPadding = NeatlyUI.GetEditorPadding(); if (!editorPadding.ContainsKey(activeSprite.name)) { Debug.LogErrorFormat("[padding] 数据缺失:{0}", activeSprite.name); return Vector4.zero; } return editorPadding[activeSprite.name]; #else return Vector4.zero; #endif } /// sliced特有Diamons, 在Sliced拉伸模式 Padding不拉伸 private Vector4 GetSlicedDiamons() { var padding = GetPadding(); Rect r = GetPixelAdjustedRect(); //原尺寸定死 return new Vector4( r.x + padding.x, r.y + padding.y, r.x + r.width - padding.z, r.y + r.height - padding.w ); } private Vector4 GetDrawingDimensions() { var padding = GetPadding(); var size = activeSprite == null ? Vector2.zero : new Vector2(activeSprite.rect.width, activeSprite.rect.height); Rect r = GetPixelAdjustedRect(); int spriteW = Mathf.RoundToInt(size.x); int spriteH = Mathf.RoundToInt(size.y); float width = spriteW + padding.z + padding.x; float height = spriteH + padding.w + padding.y; var v = new Vector4( padding.x / width, padding.y / height, (width - padding.z) / width, (height - padding.w) / height); v = new Vector4( r.x + r.width * v.x, r.y + r.height * v.y, r.x + r.width * v.z, r.y + r.height * v.w ); return v; } #endregion public override void SetNativeSize() { if (activeSprite != null) { var padding = GetPadding(); float w = activeSprite.rect.width / pixelsPerUnit + padding.x + padding.z; float h = activeSprite.rect.height / pixelsPerUnit + padding.y + padding.w; rectTransform.anchorMax = rectTransform.anchorMin; rectTransform.sizeDelta = new Vector2(w, h); SetAllDirty(); } } //加载网络图片 public void LoadUrlSprite(string url, int width = 0, int height = 0, string time = "0") { NeatlyUI.DownloadUrlSpriteAction(this, url); } public void InitUrlSprite(Texture2D tex2D) { if (gameObject == null) { return; } try { Sprite urlSprite = Sprite.Create(tex2D, new Rect(0, 0, tex2D.width, tex2D.height), new Vector2(0.5f, 0.5f)); m_Sprite = urlSprite; m_Material = null; m_SpriteName = ""; SetAllDirty(); } catch (Exception e) { // ignored } } // public void SetCustomSprite(Sprite sp) // { // m_Sprite = sp; // m_Material = null; // m_SpriteName = null; // SetAllDirty(); // } } }