/* author:Saber date:2020/4/6 desc:新的文本组件,根据文本宽度和高度自动适应字体大小,且可以获取正确的文本内容宽度 */ using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace LuaFramework{ [AddComponentMenu("UI/AdaptiveText", 16)] [ExecuteInEditMode] public class AdaptiveText : Text { protected AdaptiveText() { useLegacyMeshGeneration = false; } public bool need_adaptive = false; [Range(1, 10)] public int min_size = 10; [Range(11, 70)] public int max_size = 40; // 文本赋值修改 public override string text{ get { return base.m_Text; } set { if (String.IsNullOrEmpty(value)) { if (String.IsNullOrEmpty(base.m_Text)) return; base.m_Text = ""; SetVerticesDirty(); } else if (base.m_Text != value) { base.m_Text = value; SetVerticesDirty(); SetLayoutDirty(); // 重新设置文本大小 FitFontSize(); } } } // 字体大小设定,在自适应大小文本的情况下拒绝外部修改 new public int fontSize { get { return base.fontSize; } set { if (need_adaptive) return; base.fontSize = value; } } protected override void OnEnable() { base.OnEnable(); FontUpdateTracker.TrackText(this); FitFontSize(); } protected override void OnDisable() { base.OnDisable(); FontUpdateTracker.UntrackText(this); } // 文本内容变动回调 private void OnTextureRebuilt(Font font){ if(font == null) return; FitFontSize(); } private void FitFontSize(){ if(!need_adaptive) return; base.fontSize = base.fontSize < min_size ? min_size : base.fontSize; base.fontSize = base.fontSize > max_size ? max_size : base.fontSize; bool pass = CheckTextSizeFitOrNot(); // 先检测缩小,再检测放大 int last_fontSize = base.fontSize; while(!pass && base.fontSize > min_size){ base.fontSize --; pass = CheckTextSizeFitOrNot(); } // 字体没变化说明已经够小,要处理放大到合适大小 // 这么写的原因是要获取到对应字体的真实preferredHeight,这个接口是私有的外面调不到,而且还得构造数据 if (last_fontSize == base.fontSize && base.fontSize < max_size){ base.fontSize ++; pass = CheckTextSizeFitOrNot(); while(pass && base.fontSize <= max_size){ base.fontSize++; pass = CheckTextSizeFitOrNot(); } // 因为字体大小不满足被跳出,则需要减一号字号 base.fontSize--; } } // private Font m_font; // private CharacterInfo characterInfo; // 原先的写法是针对字体的字符类型为dynamic动态型的计算方式,但是如果把字体类型改为Unicode的话,字符的advance会固定为某个数值,这个情况下preferredWidth反而是正确的结果 // 目前项目中主要的字体都不是dynamic字符类型了,但也要保留这部分的代码,后续如果有不同字符类型的字体出现的话就可以使用判断区分计算方式 // 相关的字段名为TrueTypeFontImporter类中的m_ForceTextureCase字段,枚举FontTextureCase // private bool CheckTextSizeFitOrNot(int fontSize){ private bool CheckTextSizeFitOrNot(){ // bool pass = false; // m_font = base.font; // float m_rect_width = this.gameObject.GetComponent().rect.width; // float m_rect_height = this.gameObject.GetComponent().rect.height; // float text_width = 0f; // if(font != null){ // font.RequestCharactersInTexture(base.text, fontSize, base.fontStyle); // for(int i = 0; i ().rect.width; float m_rect_height = this.gameObject.GetComponent().rect.height; return base.preferredWidth <= m_rect_width && base.preferredHeight <= m_rect_height; } // 手动自适应排版 public void FitFontSizeManul(){ FitFontSize(); } // 获取文本的实际宽度 public float GetContentWidth() { float m_rect_width = this.gameObject.GetComponent().rect.width; // 如果文本宽度超过UI大小,则返回UI本身的宽度,否则返回文本宽度 return base.preferredWidth <= m_rect_width ? base.preferredWidth : m_rect_width; } } }