源码17:Image
Image可以说是用的最多得UI组件了,相比于RawImage来说也复杂得多
public class Image : MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastFilter
{
...
[SerializeField]
private Sprite m_Sprite;
/// How the Image is drawn.
[SerializeField] private Type m_Type = Type.Simple;
...
}
Image使用得图片资源是Sprite格式,这个需要在图片导入得时候在Inspector里吧TextureType 设置为Sprite
Image重写了Graphic里得OnPopulateMesh
protected override void OnPopulateMesh(VertexHelper toFill)
{
if (activeSprite == null)
{
base.OnPopulateMesh(toFill);
return;
}
switch (type)
{
case Type.Simple:
if (!useSpriteMesh)
GenerateSimpleSprite(toFill, m_PreserveAspect);
else
GenerateSprite(toFill, m_PreserveAspect);
break;
case Type.Sliced:
GenerateSlicedSprite(toFill);
break;
case Type.Tiled:
GenerateTiledSprite(toFill);
break;
case Type.Filled:
GenerateFilledSprite(toFill, m_PreserveAspect);
break;
}
}
再渲染Image得时候,分了四种渲染方法。最终VertexHelper中传入顶点数据 会根据这四种渲染方式来做不同计算
public enum Type
{
//渲染普通图片资源
Simple,
//渲染九宫格式图片
Sliced,
//平铺模式
Tiled,
//填充模式
Filled
}
下面就分析下不同得实现:
useSpriteMesh 基本都是False 没看到有设置为True得 所以只考虑GenerateSimpleSprite
void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
{
Vector4 v = GetDrawingDimensions(lPreserveAspect);
var uv = (activeSprite != null) ? Sprites.DataUtility.GetOuterUV(activeSprite) : Vector4.zero;
var color32 = color;
vh.Clear();
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);
}
GetDrawingDimensions 获取图片得左下角 右上角顶点得位置,得到数据后AddVert、AddTriangle。处理方式基本和RawImage的方式一样。
private void GenerateSlicedSprite(VertexHelper toFill)
{
if (!hasBorder)
{
GenerateSimpleSprite(toFill, false);
return;
}
Vector4 outer, inner, padding, border;
if (activeSprite != null)
{
outer = Sprites.DataUtility.GetOuterUV(activeSprite);
inner = Sprites.DataUtility.GetInnerUV(activeSprite);
padding = Sprites.DataUtility.GetPadding(activeSprite);
border = activeSprite.border;
}
else
{
outer = Vector4.zero;
inner = Vector4.zero;
padding = Vector4.zero;
border = Vector4.zero;
}
Rect rect = GetPixelAdjustedRect();
Vector4 adjustedBorders = GetAdjustedBorders(border / multipliedPixelsPerUnit, rect);
padding = padding / multipliedPixelsPerUnit;
s_VertScratch[0] = new Vector2(padding.x, padding.y);
s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w);
s_VertScratch[1].x = adjustedBorders.x;
s_VertScratch[1].y = adjustedBorders.y;
s_VertScratch[2].x = rect.width - adjustedBorders.z;
s_VertScratch[2].y = rect.height - adjustedBorders.w;
for (int i = 0; i < 4; ++i)
{
s_VertScratch[i].x += rect.x;
s_VertScratch[i].y += rect.y;
}
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 (!m_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));
}
}
}
hasBorder : 当没有边框 也就是没有设置成九宫格得时候 就直接和Simple模式下一样
padding 我们通常会设置为0 这里就不考虑他,先计算得outer inner border 基本如下
最终两个For其实是生成三角形
- 生成36个uv点,九宫格里每一个格子对应4个uv点。
- 生成36个顶点,九宫格里每一个格子对应4个顶点。
- 中心区域被拉大,四角部分不变。当取消Image上的Fill Center的时候,中间区域变透明,这是因为中间区域顶点、UV等信息都没有。
-
Filled 区分了不同的填充方法(Horizontal,Vertical,Radial 90,Radial 180,Radial 360) Horizontal和Vertical填充方法 根据m_FillOrigin(填充的起点)和m_FillAmount(填充的值),设置顶点和UV。 Radial系列方法 调用RadialCut方法,调整指定的四边形,使其径向填充。然后调用AddQuad方法,设置顶点,颜色和UV。
|