以下内容是根據Unity 2020.1.01f版本進行編寫的
UGUI源代碼之RawImage—Set UVRect Value按鈕
- 1、目的
- 2、參考
- 3、代碼閱讀
- 4、準備修改UGUI源代碼
- 5、增加Set UVRect Value按鈕
- 6、最終效果
- 7、項目工程源代碼
1、目的
在使用RawImage元件時,發現隻能通過設定的UVRect大小來設定節點的寬高,而不能通過節點寬高設定UVRect的值,是以想試試增加一個設定UVRect Value的按鈕。最終實作出來的效果還需要進一步測試才能用于實際項目中。
2、參考
本文參考Unity官方的UGUI源代碼
Github位址:https://github.com/Unity-Technologies/uGUI
3、代碼閱讀
我們可以先參考下已有的Set Native Size按鈕
首先看看RawImageEditor的代碼(已删除注釋):
SerializedProperty m_Texture;
SerializedProperty m_UVRect;
GUIContent m_UVRectContent;
protected override void OnEnable()
{
base.OnEnable();
m_UVRectContent = EditorGUIUtility.TrTextContent("UV Rect");
m_Texture = serializedObject.FindProperty("m_Texture");
m_UVRect = serializedObject.FindProperty("m_UVRect");
SetShowNativeSize(true);
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_Texture);
AppearanceControlsGUI();
RaycastControlsGUI();
EditorGUILayout.PropertyField(m_UVRect, m_UVRectContent);
SetShowNativeSize(false);
NativeSizeButtonGUI();
serializedObject.ApplyModifiedProperties();
}
void SetShowNativeSize(bool instant)
{
base.SetShowNativeSize(m_Texture.objectReferenceValue != null, instant);
}
從代碼可以看出,在OnSpectorGUI函數中,NativeSizeButtonGUI就是控制顯示Set Native Size按鈕的代碼了(如果看不出來是哪段代碼控制顯示Set Native Size按鈕的話,可以嘗試逐行代碼注釋看效果,但是一般可以直接通過看函數名字知道函數大概是做什麼的)
跳轉到NativeSizeButtonGUI函數中(已删除注釋):
protected void NativeSizeButtonGUI()
{
if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded))
{
EditorGUILayout.BeginHorizontal();
{
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button(m_CorrectButtonContent, EditorStyles.miniButton))
{
foreach (Graphic graphic in targets.Select(obj => obj as Graphic))
{
Undo.RecordObject(graphic.rectTransform, "Set Native Size");
graphic.SetNativeSize();
EditorUtility.SetDirty(graphic);
}
}
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndFadeGroup();
}
從代碼可以大概了解,如果Set Native Size按鈕的不透明度為1,則使用EditorGUILayout布局将其顯示出來
我們還需要知道Set Native Size按鈕是怎麼定義的,跳轉到GraphicEditor(因為RawImageEditor類繼承自GraphicEditor類,RawImageEditor類中OnEnable函數調用了父類的OnEnable函數,是以要跳轉到GraphicEditor類看OnEnable函數):
protected SerializedProperty m_Script;
protected SerializedProperty m_Color;
protected SerializedProperty m_Material;
protected SerializedProperty m_RaycastTarget;
private GUIContent m_CorrectButtonContent;
protected AnimBool m_ShowNativeSize;
protected virtual void OnDisable()
{
Tools.hidden = false;
m_ShowNativeSize.valueChanged.RemoveListener(Repaint);
}
protected virtual void OnEnable()
{
m_CorrectButtonContent = EditorGUIUtility.TrTextContent("Set Native Size", "Sets the size to match the content.");
m_Script = serializedObject.FindProperty("m_Script");
m_Color = serializedObject.FindProperty("m_Color");
m_Material = serializedObject.FindProperty("m_Material");
m_RaycastTarget = serializedObject.FindProperty("m_RaycastTarget");
m_ShowNativeSize = new AnimBool(false);
m_ShowNativeSize.valueChanged.AddListener(Repaint);
}
從代碼中可以看出,m_CorrectButtonContent就是Set Native Size按鈕了,其在OnEnable函數通過EditorGUIUtility.TrTextContent函數設定按鈕内的文本,以及滑鼠停留在按鈕上面時顯示的提示文本;
M_ShowNativeSize則是bool類型資料在Inspector面闆的動畫效果,類名是AnimBool,主要就是漸隐漸顯,這個函數後面使用的時候,直接複制改個名字就行
回看RawImageEditor的代碼,其中OnInspectorGui函數中,還有SetShowNativeSize函數,此函數就是設定此按鈕是否可見,如果可見才會使用NativeSizeButtonGUI函數在Inspector面闆繪制出來,跳轉到SetShowNativeSize函數:
void SetShowNativeSize(bool instant)
{
base.SetShowNativeSize(m_Texture.objectReferenceValue != null, instant);
}
這裡引用的是父類的函數,跳轉到父類的SetShowNativeSize函數:
protected void SetShowNativeSize(bool show, bool instant)
{
if (instant)
m_ShowNativeSize.value = show;
else
m_ShowNativeSize.target = show;
}
結合上面兩個函數來看,其實就是如果RawImage元件的Texture不為空,則設定其動畫的value為true,然後動畫的faded屬性就會變成1,當faded屬性為1時,NativeSizeButtonGUI函數就會把按鈕在Inspector面闆中繪制出來。這裡我們隻需要模仿來寫就可以了
然後我們還需要知道點選按鈕後的函數,從GraphicEditor中的SetShowNativeSize函數可以看出,graphic.SetNativeSize函數就是點選後設定節點寬高的函數了,跳轉到RawImage類找到此函數(跳轉到Graphic類中的SetNativeSize函數隻會看到虛方法,沒有函數實體):
public override void SetNativeSize()
{
Texture tex = mainTexture;
if (tex != null)
{
int w = Mathf.RoundToInt(tex.width * uvRect.width);
int h = Mathf.RoundToInt(tex.height * uvRect.height);
rectTransform.anchorMax = rectTransform.anchorMin;
rectTransform.sizeDelta = new Vector2(w, h);
}
}
這段代碼比較簡單,隻是擷取Sprite圖檔Texture的寬高,向上取整得到int類型的數,再将其設定為節點RectTransform元件的寬高
4、準備修改UGUI源代碼
請看這篇:UGUI源代碼之修改源代碼的前期準備
已經準備過的同學可以跳過
5、增加Set UVRect Value按鈕
按照上一個步驟得出的結果,我們隻需要模仿上述的Set Native Size按鈕,給RawImage元件增加一個Set UVRect Value按鈕即可
考慮到Graphic類以及GraphicEditor類會有不少子類,是以将所有增加的代碼都寫在RawImage類以及RawImageEditor類中
首先修改RawImageEditor類:
SerializedProperty m_Texture;
SerializedProperty m_UVRect;
GUIContent m_UVRectContent;
//增加Set UVRect Value按鈕及其Insprctor動畫
GUIContent m_SetUVRectButtonContent;
AnimBool m_ShowSetUVRect;
protected override void OnDisable()
{
base.OnDisable();
m_ShowSetUVRect.valueChanged.RemoveListener(Repaint);
}
protected override void OnEnable()
{
base.OnEnable();
m_UVRectContent = EditorGUIUtility.TrTextContent("UV Rect");
m_Texture = serializedObject.FindProperty("m_Texture");
m_UVRect = serializedObject.FindProperty("m_UVRect");
SetShowNativeSize(true);
//增加根據目前節點寬高設定UVRect屬性
m_SetUVRectButtonContent = EditorGUIUtility.TrTextContent("Set UVRect Value", "Sets the values to UVRect.");
m_ShowSetUVRect = new AnimBool(false);
m_ShowSetUVRect.valueChanged.AddListener(Repaint);
SetShowUVRect(true);
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_Texture);
AppearanceControlsGUI();
RaycastControlsGUI();
EditorGUILayout.PropertyField(m_UVRect, m_UVRectContent);
SetShowNativeSize(false);
NativeSizeButtonGUI();
//增加設定UVRect values的按鈕
SetShowUVRect(false);
if (EditorGUILayout.BeginFadeGroup(m_ShowSetUVRect.faded))
{
EditorGUILayout.BeginHorizontal();
{
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button(m_SetUVRectButtonContent, EditorStyles.miniButton))
{
foreach (RawImage rawImage in targets.Select(obj => obj as RawImage))
{
Undo.RecordObject(rawImage.rectTransform, "Set UVRect value");
rawImage.SetUVRectValues();
EditorUtility.SetDirty(rawImage);
}
}
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndFadeGroup();
serializedObject.ApplyModifiedProperties();
}
void SetShowUVRect(bool instant)
{
if (instant)
m_ShowSetUVRect.value = m_Texture.objectReferenceValue != null;
else
m_ShowSetUVRect.target = m_Texture.objectReferenceValue != null;
}
首先增加按鈕及其動畫屬性,在OnEnable函數中模仿Set Native Size按鈕進行初始化,同樣的在OnDisable函數中移除事件監聽,模仿SetShowNativeSize函數,增加了一個SetShowUVRect的函數
另外,繪制按鈕時,按鈕的響應函數也要改變:
if (EditorGUILayout.BeginFadeGroup(m_ShowSetUVRect.faded))
{
EditorGUILayout.BeginHorizontal();
{
GUILayout.Space(EditorGUIUtility.labelWidth);
if (GUILayout.Button(m_SetUVRectButtonContent, EditorStyles.miniButton))
{
foreach (RawImage rawImage in targets.Select(obj => obj as RawImage))
{
Undo.RecordObject(rawImage.rectTransform, "Set UVRect value");
rawImage.SetUVRectValues();
EditorUtility.SetDirty(rawImage);
}
}
}
EditorGUILayout.EndHorizontal();
}
其中,在GUILayout.Button中的foreach循環用的是Graphic類,但我把代碼都寫在了RawImageEditor類以及RawImage類中,是以引用的類型需要改為RawImage。另外,rawImage.SetUVRectValues就是我在RawImage類中增加的設定UVRect值的函數了
如果此時注釋掉rawImage.SetUVRectValues()這行代碼,就可以在Unity中看到新增的按鈕了,此時點選沒有反應:

接着在RawImage類中增加SetUVRectValues函數:
public void SetUVRectValues()
{
m_UVRect.width = rectTransform.sizeDelta.x / mainTexture.width;
m_UVRect.height = rectTransform.sizeDelta.y / mainTexture.height;
SetVerticesDirty();
}
代碼比較簡單,就隻是用節點的寬高分别除以Texture的寬高,得到的就是目前節點寬高對應的UVRect值了。SetVerticesDirty函數是Graphic類的函數,用于修改頂點,任何修改到元件效果的函數一般都要重新修改頂點
最好記得把剛剛在RawImageEditor注釋掉的代碼取消注釋,就大功告成了!
6、最終效果
7、項目工程源代碼
待補~~
大佬們找到問題歡迎拍磚~