目的:
今天要做一个基于UGUI标签流的功能的文档。标签流的作用在于:在日常的App中,时常会涉及到对热门、推荐等标签自动换行的流式布局。常用于关键词搜索或者热门标签等场景
类似于下面:
流式布局的原理:当某一行的空间不足容纳新的内容时,自动向下一行移动
如下:
所涉及到的重点:
(1)通过字体及字符串Length,获取字符串所占Text长度(显示的像素)
(2)计算当前行剩余空间是否能容纳下一个标签
代码如下所示:
1:通过字体及字符串长度获取字符串显示长度:
/// <summary>
/// 通过字体及字符串长度获取某字符串显示长度(像素)
/// </summary>
/// <param name="fontsize">字号</param>
/// <param name="text">内容</param>
/// <param name="fontStyle">字体类型(普通、加粗、倾斜)</param>
/// <param name="path">字体路径</param>
/// <returns></returns>
float GetTextWidth(int fontsize,string text,FontStyle fontStyle,string path)
{
Font font = Resources.Load<Font>(path);
font.RequestCharactersInTexture(text, fontsize, fontStyle);
CharacterInfo characterInfo;
float width = 0f;
for (int i = 0; i < text.Length; i++)
{
font.GetCharacterInfo(text[i], out characterInfo, fontsize);
width += characterInfo.advance;
}
return width;
}
2:通过克隆并显示一个Button
/// <summary>
/// 通过克隆并显示一个Button
/// </summary>
/// <param name="ContentText">Button文字</param>
/// <param name="objParent">初始化后Button的父物体(容纳的Box)</param>
/// <param name="info">字符串相关信息(字号、字体、类型、路径等)</param>
/// <returns></returns>
GameObject GetInitButton(string ContentText,Transform objParent,OriginInfo info)
{
var textWidth = GetTextWidth(info._fontsize, ContentText, info._fontStyle, info._fontPath);
var btn = (GameObject)Object.Instantiate(Resources.Load(info._btnResPath));
btn.transform.SetParent(objParent);
btn.GetComponent<RectTransform>().sizeDelta = new Vector2(textWidth + info._addRect.x, info._addRect.y);
btn.GetComponentInChildren<UnityEngine.UI.Text>().text = ContentText;
btn.transform.localScale = Vector3.one;
return btn;
}
3:标签流显示
/// <summary>
/// 标签流展示
/// </summary>
/// <param name="labelFlowOrignInfo"></param>
/// <param name="contentList">字符串列表(所要展示的Button流)</param>
/// <param name="objParent"></param>
/// <param name="info"></param>
public void LabelFlowShow(LabelFlowOrigin labelFlowOrignInfo, List<string> contentList,Transform objParent,OriginInfo info)
{
labelFlowOrignInfo._totalLength = labelFlowOrignInfo._paddingLeft;
var parentWidth = objParent.GetComponent<RectTransform>().sizeDelta.x;//当父物体没有做拉伸时
for (int i = 0; i < contentList.Count; i++)
{
//Initialization button
var objButton = GetInitButton(contentList[i], objParent,info);
var objButtonRect = objButton.GetComponent<RectTransform>();
//Control button postion
if (labelFlowOrignInfo._totalLength + objButtonRect.sizeDelta.x + labelFlowOrignInfo._paddingRight > parentWidth)
{
labelFlowOrignInfo._totalLength = labelFlowOrignInfo._paddingLeft;
labelFlowOrignInfo._rows++;
}
objButton.GetComponent<RectTransform>().localPosition = new Vector3(labelFlowOrignInfo._totalLength, -labelFlowOrignInfo._spacingVertical * labelFlowOrignInfo._rows - objButtonRect.sizeDelta.y * (labelFlowOrignInfo._rows - 1), 0);
labelFlowOrignInfo._totalLength += objButtonRect.sizeDelta.x + labelFlowOrignInfo._spacingHorizontal;
}
}
4:两个类用于代码管理
/// <summary>
/// 两个类用于代码管理
/// </summary>
public class LabelFlowOrigin
{
public float _paddingLeft;//左边距
public float _paddingRight;//右边距
public float _paddingUp;//上边距
public float _spacingHorizontal;//行间距
public float _spacingVertical;//列间距
public float _totalLength;//某行的当前长度
public int _rows;//第几行
public LabelFlowOrigin(float paddingLeft, float paddingRight, float paddingUp, float spacingHorizonta, float spacingVertical, float totalLength, int rows)
{
this._paddingLeft = paddingLeft;
this._paddingRight = paddingRight;
this._paddingUp = paddingUp;
this._spacingHorizontal = spacingHorizonta;
this._spacingVertical = spacingVertical;
this._totalLength = totalLength;
this._rows = rows;
}
}
public class OriginInfo
{
public int _fontsize;//字号
public FontStyle _fontStyle;//类型
//Button的显示(x——Button背景比字符串本身左右宽多少长度,y——Button高度)
public Vector2 _addRect;
public string _fontPath;//字体路径
public string _btnResPath;//Button预制体路径
public OriginInfo(int fontsize, FontStyle fontStyle, Vector2 addRect, string fontPath, string btnResPath)
{
this._fontPath = fontPath;
this._fontStyle = fontStyle;
this._fontsize = fontsize;
this._addRect = addRect;
this._btnResPath = btnResPath;
}
}
全部代码如下所示:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 标签流——Made By XXQQ
/// </summary>
public class InitLabelFlow
{
#region singleton
static InitLabelFlow instance = null;
public static InitLabelFlow Instance
{
get
{
if (instance == null)
instance = new InitLabelFlow();
return instance;
}
}
#endregion;
/// <summary>
/// 通过字体及字符串长度获取某字符串显示长度(像素)
/// </summary>
/// <param name="fontsize">字号</param>
/// <param name="text">内容</param>
/// <param name="fontStyle">字体类型(普通、加粗、倾斜)</param>
/// <param name="path">字体路径</param>
/// <returns></returns>
float GetTextWidth(int fontsize,string text,FontStyle fontStyle,string path)
{
Font font = Resources.Load<Font>(path);
font.RequestCharactersInTexture(text, fontsize, fontStyle);
CharacterInfo characterInfo;
float width = 0f;
for (int i = 0; i < text.Length; i++)
{
font.GetCharacterInfo(text[i], out characterInfo, fontsize);
width += characterInfo.advance;
}
return width;
}
/// <summary>
/// 通过克隆并显示一个Button
/// </summary>
/// <param name="ContentText">Button文字</param>
/// <param name="objParent">初始化后Button的父物体(容纳的Box)</param>
/// <param name="info">字符串相关信息(字号、字体、类型、路径等)</param>
/// <returns></returns>
GameObject GetInitButton(string ContentText,Transform objParent,OriginInfo info)
{
var textWidth = GetTextWidth(info._fontsize, ContentText, info._fontStyle, info._fontPath);
var btn = (GameObject)Object.Instantiate(Resources.Load(info._btnResPath));
btn.transform.SetParent(objParent);
btn.GetComponent<RectTransform>().sizeDelta = new Vector2(textWidth + info._addRect.x, info._addRect.y);
btn.GetComponentInChildren<UnityEngine.UI.Text>().text = ContentText;
btn.transform.localScale = Vector3.one;
return btn;
}
/// <summary>
/// 标签流显示
/// </summary>
/// <param name="labelFlowOrignInfo"></param>
/// <param name="contentList">字符串列表(所要展示的Button流)</param>
/// <param name="objParent"></param>
/// <param name="info"></param>
public void LabelFlowShow(LabelFlowOrigin labelFlowOrignInfo, List<string> contentList,Transform objParent,OriginInfo info)
{
labelFlowOrignInfo._totalLength = labelFlowOrignInfo._paddingLeft;
var parentWidth = objParent.GetComponent<RectTransform>().sizeDelta.x;//当父物体没有做拉伸时
for (int i = 0; i < contentList.Count; i++)
{
//Initialization button
var objButton = GetInitButton(contentList[i], objParent,info);
var objButtonRect = objButton.GetComponent<RectTransform>();
//Control button postion
if (labelFlowOrignInfo._totalLength + objButtonRect.sizeDelta.x + labelFlowOrignInfo._paddingRight > parentWidth)
{
labelFlowOrignInfo._totalLength = labelFlowOrignInfo._paddingLeft;
labelFlowOrignInfo._rows++;
}
objButton.GetComponent<RectTransform>().localPosition = new Vector3(labelFlowOrignInfo._totalLength, -labelFlowOrignInfo._spacingVertical * labelFlowOrignInfo._rows - objButtonRect.sizeDelta.y * (labelFlowOrignInfo._rows - 1), 0);
labelFlowOrignInfo._totalLength += objButtonRect.sizeDelta.x + labelFlowOrignInfo._spacingHorizontal;
}
}
}
/// <summary>
/// 两个类用于代码管理
/// </summary>
public class LabelFlowOrigin
{
public float _paddingLeft;//左边距
public float _paddingRight;//右边距
public float _paddingUp;//上边距
public float _spacingHorizontal;//行间距
public float _spacingVertical;//列间距
public float _totalLength;//某行的当前长度
public int _rows;//第几行
public LabelFlowOrigin(float paddingLeft, float paddingRight, float paddingUp, float spacingHorizonta, float spacingVertical, float totalLength, int rows)
{
this._paddingLeft = paddingLeft;
this._paddingRight = paddingRight;
this._paddingUp = paddingUp;
this._spacingHorizontal = spacingHorizonta;
this._spacingVertical = spacingVertical;
this._totalLength = totalLength;
this._rows = rows;
}
}
public class OriginInfo
{
public int _fontsize;//字号
public FontStyle _fontStyle;//类型
//Button的显示(x——Button背景比字符串本身左右宽多少长度,y——Button高度)
public Vector2 _addRect;
public string _fontPath;//字体路径
public string _btnResPath;//Button预制体路径
public OriginInfo(int fontsize, FontStyle fontStyle, Vector2 addRect, string fontPath, string btnResPath)
{
this._fontPath = fontPath;
this._fontStyle = fontStyle;
this._fontsize = fontsize;
this._addRect = addRect;
this._btnResPath = btnResPath;
}
}
标签流测试用例
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 标签流测试用例
/// </summary>
public class Test : MonoBehaviour
{
void Start()
{
var labelFlowOrigin = new LabelFlowOrigin(10, 10, 0, 30, 30, 0, 1);
List<string> contentList = new List<string>() { "跪下,叫爸爸!", "我是Bruce", "XXQQ", "今天的天气哈哈哈", "落霞与孤鹜齐飞", "Smiles Of Roses","我在马路边捡到一分钱","震惊——" };
var parent = GameObject.Find("Image").transform;
var originInfo = new OriginInfo(24, FontStyle.Normal, new Vector2(60, 50), "font/DroidSansFallback", "XQResources/CollectionButton");
InitLabelFlow.Instance.LabelFlowShow(labelFlowOrigin, contentList, parent, originInfo);
}
}