UGUI教程之-自定义UGUI 扩展集(二)

 

继续上篇文章《UGUI教程之-自定义UGUI 扩展集(一)》,我们继续来学习自定义扩展UGUI控件

4、ToolTip 

【需要外部调用函数显示和隐藏内容】请注意–目前情况下仅适用于Screenspace Camera的画布设置,要包括Screenspace and Worldspace需要更新


namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Tooltip")]
public class ToolTip : MonoBehaviour
{
//text of the tooltip
private Text _text;
private RectTransform _rectTransform;

//if the tooltip is inside a UI element
private bool _inside;

private bool _xShifted, _yShifted = false;

private float width, height, canvasWidth, canvasHeight;

private int screenWidth, screenHeight;

private float YShift,xShift;

private RenderMode _guiMode;

private Camera _guiCamera;

// Use this for initialization
public void Awake()
{
var _canvas = GetComponentInParent<Canvas>();
_guiCamera = _canvas.worldCamera;
_guiMode = _canvas.renderMode;
_rectTransform = GetComponent<RectTransform>();

_text = GetComponentInChildren<Text>();

_inside = false;

//size of the screen
screenWidth = Screen.width;
screenHeight = Screen.height;

xShift = 0f;
YShift = -30f;

_xShifted = _yShifted = false;
this.gameObject.SetActive(false);

}

//Call this function externally to set the text of the template and activate the tooltip
public void SetTooltip(string ttext)
{

if (_guiMode == RenderMode.ScreenSpaceCamera)
{
//set the text and fit the tooltip panel to the text size
_text.text = ttext;

_rectTransform.sizeDelta = new Vector2(_text.preferredWidth + 40f, _text.preferredHeight + 25f);

OnScreenSpaceCamera();

}
}

//call this function on mouse exit to deactivate the template
public void HideTooltip()
{
if (_guiMode == RenderMode.ScreenSpaceCamera)
{
this.gameObject.SetActive(false);
_inside = false;
}
}

// Update is called once per frame
void FixedUpdate()
{
if (_inside)
{
if (_guiMode == RenderMode.ScreenSpaceCamera)
{
OnScreenSpaceCamera();
}
}
}

//main tooltip edge of screen guard and movement
public void OnScreenSpaceCamera()
{
Vector3 newPos = _guiCamera.ScreenToViewportPoint(Input.mousePosition - new Vector3(xShift, YShift, 0f));
Vector3 newPosWVP = _guiCamera.ViewportToWorldPoint(newPos);

width = _rectTransform.sizeDelta[0];
height = _rectTransform.sizeDelta[1];

// check and solve problems for the tooltip that goes out of the screen on the horizontal axis
float val;

Vector3 lowerLeft = _guiCamera.ViewportToWorldPoint(new Vector3(0.0f, 0.0f, 0.0f));
Vector3 upperRight = _guiCamera.ViewportToWorldPoint(new Vector3(1.0f, 1.0f, 0.0f));

//check for right edge of screen
val = (newPosWVP.x + width / 2);
if (val > upperRight.x)
{
Vector3 shifter = new Vector3(val - upperRight.x, 0f, 0f);
Vector3 newWorldPos = new Vector3(newPosWVP.x - shifter.x, newPos.y, 0f);
newPos.x = _guiCamera.WorldToViewportPoint(newWorldPos).x;
}
//check for left edge of screen
val = (newPosWVP.x - width / 2);
if (val < lowerLeft.x)
{
Vector3 shifter = new Vector3(lowerLeft.x - val, 0f, 0f);
Vector3 newWorldPos = new Vector3(newPosWVP.x + shifter.x, newPos.y, 0f);
newPos.x = _guiCamera.WorldToViewportPoint(newWorldPos).x;
}

// check and solve problems for the tooltip that goes out of the screen on the vertical axis

//check for upper edge of the screen
val = (newPosWVP.y + height / 2);
if (val > upperRight.y)
{
Vector3 shifter = new Vector3(0f, 35f + height / 2, 0f);
Vector3 newWorldPos = new Vector3(newPos.x, newPosWVP.y - shifter.y, 0f);
newPos.y = _guiCamera.WorldToViewportPoint(newWorldPos).y;
}

//check for lower edge of the screen (if the shifts of the tooltip are kept as in this code, no need for this as the tooltip always appears above the mouse bu default)
val = (newPosWVP.y - height / 2);
if (val < lowerLeft.y)
{
Vector3 shifter = new Vector3(0f, 35f + height / 2, 0f);
Vector3 newWorldPos = new Vector3(newPos.x, newPosWVP.y + shifter.y, 0f);
newPos.y = _guiCamera.WorldToViewportPoint(newWorldPos).y;
}

this.transform.position = new Vector3(newPosWVP.x, newPosWVP.y, 0f);
this.gameObject.SetActive(true);
_inside = true;
}
}
}

5、ReturnKeyTriggersButton 

首先肯定是要配合 InputField 组件使用,是处理回车键, 【刚刚试了试 InputField 组件 很强大的哦】


using UnityEngine.EventSystems;
namespace UnityEngine.UI
{
[RequireComponent(typeof(InputField))]
[AddComponentMenu("UI/Extensions/Return Key Trigger")]
public class ReturnKeyTriggersButton : MonoBehaviour, ISubmitHandler
{
private EventSystem _system;

public Button button;
private bool highlight = true;
public float highlightDuration = 0.2f;

void Start()
{
_system = EventSystem.current;
}

void RemoveHighlight()
{
button.OnPointerExit(new PointerEventData(_system));
}

public void OnSubmit(BaseEventData eventData)
{
if (highlight) button.OnPointerEnter(new PointerEventData(_system));
button.OnPointerClick(new PointerEventData(_system));

if (highlight) Invoke("RemoveHighlight", highlightDuration);
}
}
}

6、NicerOutline 

和系统的 Outline效果上没有区别,但是实现方式不同可以好好研究一下


using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
//An outline that looks a bit nicer than the default one. It has less "holes" in the outline by drawing more copies of the effect
[AddComponentMenu("UI/Effects/Extensions/Nicer Outline")]
public class NicerOutline : BaseMeshEffect
{
[SerializeField]
private Color m_EffectColor = new Color (0f, 0f, 0f, 0.5f);

[SerializeField]
private Vector2 m_EffectDistance = new Vector2 (1f, -1f);

[SerializeField]
private bool m_UseGraphicAlpha = true;
//
// Properties
//
public Color effectColor
{
get
{
return this.m_EffectColor;
}
set
{
this.m_EffectColor = value;
if (base.graphic != null)
{
base.graphic.SetVerticesDirty ();
}
}
}

public Vector2 effectDistance
{
get
{
return this.m_EffectDistance;
}
set
{
if (value.x > 600f)
{
value.x = 600f;
}
if (value.x < -600f)
{
value.x = -600f;
}
if (value.y > 600f)
{
value.y = 600f;
}
if (value.y < -600f)
{
value.y = -600f;
}
if (this.m_EffectDistance == value)
{
return;
}
this.m_EffectDistance = value;
if (base.graphic != null)
{
base.graphic.SetVerticesDirty ();
}
}
}

public bool useGraphicAlpha
{
get
{
return this.m_UseGraphicAlpha;
}
set
{
this.m_UseGraphicAlpha = value;
if (base.graphic != null)
{
base.graphic.SetVerticesDirty ();
}
}
}
//
// Methods
//
protected void ApplyShadow (List<UIVertex> verts, Color32 color, int start, int end, float x, float y)
{
//Debug.Log("verts count: "+verts.Count);
int num = verts.Count * 2;
if (verts.Capacity < num)
{
verts.Capacity = num;
}
for (int i = start; i < end; i++)
{
UIVertex uIVertex = verts [i];
verts.Add (uIVertex);

Vector3 position = uIVertex.position;
//Debug.Log("vertex pos: "+position);
position.x += x;
position.y += y;
uIVertex.position = position;
Color32 color2 = color;
if (this.m_UseGraphicAlpha)
{
color2.a = (byte)(color2.a * verts [i].color.a / 255);
}
uIVertex.color = color2;
//uIVertex.color = (Color32)Color.blue;
verts [i] = uIVertex;
}
}

public override void ModifyMesh (/*List<UIVertex> verts*/ Mesh mesh)
{
if (!this.IsActive ())
{
return;
}
// 从mesh 得到 顶点集
List<UIVertex> verts = new List<UIVertex> ();
using (VertexHelper vertexHelper = new VertexHelper (mesh))
{
vertexHelper.GetUIVertexStream (verts);
}

Text foundtext = GetComponent<Text>();

float best_fit_adjustment = 1f;

if (foundtext && foundtext.resizeTextForBestFit)
{
best_fit_adjustment = (float)foundtext.cachedTextGenerator.fontSizeUsedForBestFit / (foundtext.resizeTextMaxSize-1); //max size seems to be exclusive

}

float distanceX = this.effectDistance.x * best_fit_adjustment;
float distanceY = this.effectDistance.y * best_fit_adjustment;

int start = 0;
int count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, distanceX, distanceY);
start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, distanceX, -distanceY);
start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, -distanceX, distanceY);
start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, -distanceX, -distanceY);

start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, distanceX, 0);
start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, -distanceX, 0);

start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, 0, distanceY);
start = count;
count = verts.Count;
this.ApplyShadow (verts, this.effectColor, start, verts.Count, 0, -distanceY);

// 在合成mesh
using (VertexHelper vertexHelper2 = new VertexHelper ())
{
vertexHelper2.AddUIVertexTriangleStream (verts);
vertexHelper2.FillMesh (mesh);
}
}

protected override void OnValidate ()
{
this.effectDistance = this.m_EffectDistance;
base.OnValidate ();
}
}
}

7、LetterSpacing

单独使用 每个字符间可以设置间距了!【uGUI Text 组件支持行间距,但不是字符间距。 问题是-text layout 引擎不是开源的的一部分,你无法拿到合适的 API,一种解决办法是,只需修改现有的字体,每个字符添加额外的空间。这是那样难以管理,它的声音,和我到其中有很多的不同间隔标题工作不切实际的最近的设计。我需要为每个不同的间距不同的字体。    我最好的解决办法是,只需修改现有的字体fonts ,每个字符添加额外的空间。这样难以管理,我到其中有很多的不同间隔标题工作不切实际的设计。我需要为每个不同的间距不同的字体。     然后偶然看了看Shadow 效果,使用 BaseVertexEffect 来修改绘制的源对象的几何形状的顶点列表。和这个技术相同,文本 间距(虽然它不会产生任何额外的verts)。将组件添加到 UI 文本字段,调整间距值,完成工作。但它不能很好与rich text或自动换行的文本工作】


using System.Collections.Generic;

namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Effects/Extensions/Letter Spacing")]
public class LetterSpacing : BaseMeshEffect
{
[SerializeField]
private float m_spacing = 0f;

protected LetterSpacing() { }

#if UNITY_EDITOR
protected override void OnValidate()
{
spacing = m_spacing;
base.OnValidate();
}
#endif

public float spacing
{
get { return m_spacing; }
set
{
if (m_spacing == value) return;
m_spacing = value;
if (graphic != null) graphic.SetVerticesDirty();
}
}

public override void ModifyMesh(/*List<UIVertex> verts*/Mesh mesh)
{
if (! IsActive()) return;

// 从mesh 得到 顶点集
List<UIVertex> verts = new List<UIVertex> ();
using (VertexHelper vertexHelper = new VertexHelper (mesh))
{
vertexHelper.GetUIVertexStream (verts);
}

Text text = GetComponent<Text>();
if (text == null)
{
Debug.LogWarning("LetterSpacing: Missing Text component");
return;
}

string[] lines = text.text.Split('\n');
Vector3  pos;
float    letterOffset    = spacing * (float)text.fontSize / 100f;
float    alignmentFactor = 0;
int      glyphIdx        = 0;

switch (text.alignment)
{
case TextAnchor.LowerLeft:
case TextAnchor.MiddleLeft:
case TextAnchor.UpperLeft:
alignmentFactor = 0f;
break;

case TextAnchor.LowerCenter:
case TextAnchor.MiddleCenter:
case TextAnchor.UpperCenter:
alignmentFactor = 0.5f;
break;

case TextAnchor.LowerRight:
case TextAnchor.MiddleRight:
case TextAnchor.UpperRight:
alignmentFactor = 1f;
break;
}

for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
{
string line = lines[lineIdx];
float lineOffset = (line.Length -1) * letterOffset * alignmentFactor;

for (int charIdx = 0; charIdx < line.Length; charIdx++)
{
int idx1 = glyphIdx * 4 + 0;
int idx2 = glyphIdx * 4 + 1;
int idx3 = glyphIdx * 4 + 2;
int idx4 = glyphIdx * 4 + 3;

// Check for truncated text (doesn't generate verts for all characters)
if (idx4 > verts.Count - 1) return;

UIVertex vert1 = verts[idx1];
UIVertex vert2 = verts[idx2];
UIVertex vert3 = verts[idx3];
UIVertex vert4 = verts[idx4];

pos = Vector3.right * (letterOffset * charIdx - lineOffset);

vert1.position += pos;
vert2.position += pos;
vert3.position += pos;
vert4.position += pos;

verts[idx1] = vert1;
verts[idx2] = vert2;
verts[idx3] = vert3;
verts[idx4] = vert4;

glyphIdx++;
}

// Offset for carriage return character that still generates verts
glyphIdx++;
}

// 在合成mesh
using (VertexHelper vertexHelper2 = new VertexHelper ())
{
vertexHelper2.AddUIVertexTriangleStream (verts);
vertexHelper2.FillMesh (mesh);
}
}
}
}

本篇UGUI教程关于UGUI的拓展介绍到此结束,下篇我们来学习 Gradient  、UIWindowBase 、lowLayoutGroup 等