文章目录
前言
本篇主要结合上一篇文章进一步学习UIManager中的各种方法与调用.
UIManager中的方法
1.打开界面
根据文章源码学习一我们可以知道,在UIManager中打开一个界面是主要通过这个方法
public int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm, object userData)
{
if (m_ResourceManager == null)
{
throw new GameFrameworkException("You must set resource manager first.");
}
if (m_UIFormHelper == null)
{
throw new GameFrameworkException("You must set UI form helper first.");
}
if (string.IsNullOrEmpty(uiFormAssetName))
{
throw new GameFrameworkException("UI form asset name is invalid.");
}
if (string.IsNullOrEmpty(uiGroupName))
{
throw new GameFrameworkException("UI group name is invalid.");
}
UIGroup uiGroup = (UIGroup)GetUIGroup(uiGroupName);
if (uiGroup == null)
{
throw new GameFrameworkException(Utility.Text.Format("UI group '{0}' is not exist.", uiGroupName));
}
int serialId = ++m_Serial;
UIFormInstanceObject uiFormInstanceObject = m_InstancePool.Spawn(uiFormAssetName);
if (uiFormInstanceObject == null)
{
m_UIFormsBeingLoaded.Add(serialId, uiFormAssetName);
m_ResourceManager.LoadAsset(uiFormAssetName, priority, m_LoadAssetCallbacks, OpenUIFormInfo.Create(serialId, uiGroup, pauseCoveredUIForm, userData));
}
else
{
InternalOpenUIForm(serialId, uiFormAssetName, uiGroup, uiFormInstanceObject.Target, pauseCoveredUIForm, false, 0f, userData);
}
return serialId;
}
?对于其他的OpenUIForm方法均是对该方法的进一步参数的封装.
对于该方法中的前一部分则是对UIManager中内部字段与传递来的参数的判断,以防止未初始化前调用该方法.
在这之后我们能看到第一个方法调用 UIGroup uiGroup = (UIGroup)GetUIGroup(uiGroupName);
public IUIGroup GetUIGroup(string uiGroupName)
{
if (string.IsNullOrEmpty(uiGroupName))
{
throw new GameFrameworkException("UI group name is invalid.");
}
UIGroup uiGroup = null;
if (m_UIGroups.TryGetValue(uiGroupName, out uiGroup))
{
return uiGroup;
}
return null;
}
?在这个提一下,GF中对UI是以"组"来管理的,每一个界面都由某一组来管理,初次打开UI时需在Unity端设置新的UIGroup.
?在UIGroups中点击加号以自主创建组.
回到GetUIGroup()方法中,该方法就是得到以Dictionary管理组中的特定需要的组,如果没有则返回Null.
UIGroup uiGroup = (UIGroup)GetUIGroup(uiGroupName);
if (uiGroup == null)
{
throw new GameFrameworkException(Utility.Text.Format("UI group '{0}' is not exist.", uiGroupName));
}
int serialId = ++m_Serial;
UIFormInstanceObject uiFormInstanceObject = m_InstancePool.Spawn(uiFormAssetName);
if (uiFormInstanceObject == null)
{
m_UIFormsBeingLoaded.Add(serialId, uiFormAssetName);
m_ResourceManager.LoadAsset(uiFormAssetName, priority, m_LoadAssetCallbacks, OpenUIFormInfo.Create(serialId, uiGroup, pauseCoveredUIForm, userData));
}
else
{
InternalOpenUIForm(serialId, uiFormAssetName, uiGroup, uiFormInstanceObject.Target, pauseCoveredUIForm, false, 0f, userData);
}
return serialId;
得到UIGroup后,如果为null,接下来则会throw Exception,不为空首先会在实体池中去取得对应的实体(实体池中保存所有在资源加载后的实体对象,如果池中不存在对应的实体则会通过资源加载模块来异步加载资源).
若该实体不存在会先在m_UIFormsBeingLoaded字典中加入该对象,该字典中保存了所有正在加载的UI界面资源,之后会通过资源加载模块去Load该资源;如果该实体存在则会通过InternalOpenUIForm方法来内部打开该UI,并最终返回该UI界面的序列编号.
private void InternalOpenUIForm(int serialId, string uiFormAssetName, UIGroup uiGroup, object uiFormInstance, bool pauseCoveredUIForm, bool isNewInstance, float duration, object userData)
{
try
{
IUIForm uiForm = m_UIFormHelper.CreateUIForm(uiFormInstance, uiGroup, userData);
if (uiForm == null)
{
throw new GameFrameworkException("Can not create UI form in UI form helper.");
}
uiForm.OnInit(serialId, uiFormAssetName, uiGroup, pauseCoveredUIForm, isNewInstance, userData);
uiGroup.AddUIForm(uiForm);
uiForm.OnOpen(userData);
uiGroup.Refresh();
if (m_OpenUIFormSuccessEventHandler != null)
{
OpenUIFormSuccessEventArgs openUIFormSuccessEventArgs = OpenUIFormSuccessEventArgs.Create(uiForm, duration, userData);
m_OpenUIFormSuccessEventHandler(this, openUIFormSuccessEventArgs);
ReferencePool.Release(openUIFormSuccessEventArgs);
}
}
catch (Exception exception)
{
if (m_OpenUIFormFailureEventHandler != null)
{
OpenUIFormFailureEventArgs openUIFormFailureEventArgs = OpenUIFormFailureEventArgs.Create(serialId, uiFormAssetName, uiGroup.Name, pauseCoveredUIForm, exception.ToString(), userData);
m_OpenUIFormFailureEventHandler(this, openUIFormFailureEventArgs);
ReferencePool.Release(openUIFormFailureEventArgs);
return;
}
throw;
}
}
?InternalOpenUIForm()方法中会通过m_UIFormHelper这一接口来进一步加载UI,该接口的具体实现在Unity端,第二部分会详细说明,这里只需要知道通过该接口的CreateUIForm()方法会生成UI游戏对象即可.
在生成完毕之后返回得到的UIForm,之后则是对该UIForm的进一步处理,类似于大部分其他的简易UI模块对生成UI的处理方法,在处理完毕之后会调用成功事件,这里用了ReferencePool是为了把该成功进行缓存,在catch错误时会进行与成功时相似的失败调用事件操作.
2.在Unity内部打开界面
在Unity端对UI模块的处理则是通过将接口具体实现并把UIManager中的方法在UIComponent中再次封装,使其能被调用
protected override void Awake()
{
base.Awake();
m_UIManager = GameFrameworkEntry.GetModule<IUIManager>();
if (m_UIManager == null)
{
Log.Fatal("UI manager is invalid.");
return;
}
if (m_EnableOpenUIFormSuccessEvent)
{
m_UIManager.OpenUIFormSuccess += OnOpenUIFormSuccess;
}
m_UIManager.OpenUIFormFailure += OnOpenUIFormFailure;
if (m_EnableOpenUIFormUpdateEvent)
{
m_UIManager.OpenUIFormUpdate += OnOpenUIFormUpdate;
}
if (m_EnableOpenUIFormDependencyAssetEvent)
{
m_UIManager.OpenUIFormDependencyAsset += OnOpenUIFormDependencyAsset;
}
if (m_EnableCloseUIFormCompleteEvent)
{
m_UIManager.CloseUIFormComplete += OnCloseUIFormComplete;
}
}
private void Start()
{
BaseComponent baseComponent = GameEntry.GetComponent<BaseComponent>();
if (baseComponent == null)
{
Log.Fatal("Base component is invalid.");
return;
}
m_EventComponent = GameEntry.GetComponent<EventComponent>();
if (m_EventComponent == null)
{
Log.Fatal("Event component is invalid.");
return;
}
if (baseComponent.EditorResourceMode)
{
m_UIManager.SetResourceManager(baseComponent.EditorResourceHelper);
}
else
{
m_UIManager.SetResourceManager(GameFrameworkEntry.GetModule<IResourceManager>());
}
m_UIManager.SetObjectPoolManager(GameFrameworkEntry.GetModule<IObjectPoolManager>());
m_UIManager.InstanceAutoReleaseInterval = m_InstanceAutoReleaseInterval;
m_UIManager.InstanceCapacity = m_InstanceCapacity;
m_UIManager.InstanceExpireTime = m_InstanceExpireTime;
m_UIManager.InstancePriority = m_InstancePriority;
UIFormHelperBase uiFormHelper = Helper.CreateHelper(m_UIFormHelperTypeName, m_CustomUIFormHelper);
if (uiFormHelper == null)
{
Log.Error("Can not create UI form helper.");
return;
}
uiFormHelper.name = "UI Form Helper";
Transform transform = uiFormHelper.transform;
transform.SetParent(this.transform);
transform.localScale = Vector3.one;
m_UIManager.SetUIFormHelper(uiFormHelper);
if (m_InstanceRoot == null)
{
m_InstanceRoot = new GameObject("UI Form Instances").transform;
m_InstanceRoot.SetParent(gameObject.transform);
m_InstanceRoot.localScale = Vector3.one;
}
m_InstanceRoot.gameObject.layer = LayerMask.NameToLayer("UI");
for (int i = 0; i < m_UIGroups.Length; i++)
{
if (!AddUIGroup(m_UIGroups[i].Name, m_UIGroups[i].Depth))
{
Log.Warning("Add UI group '{0}' failure.", m_UIGroups[i].Name);
continue;
}
}
}
public int OpenUIForm(string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm, object userData)
{
return m_UIManager.OpenUIForm(uiFormAssetName, uiGroupName, priority, pauseCoveredUIForm, userData);
}
在Awake与Start方法中,对UIManager中的各种事件进行添加回调,并进行对UIManager中的字段属性进行赋值,以以此达到与Unity进行通信的目的
public class DefaultUIFormHelper : UIFormHelperBase
{
private ResourceComponent m_ResourceComponent = null;
public override object InstantiateUIForm(object uiFormAsset)
{
return Instantiate((Object)uiFormAsset);
}
public override IUIForm CreateUIForm(object uiFormInstance, IUIGroup uiGroup, object userData)
{
GameObject gameObject = uiFormInstance as GameObject;
if (gameObject == null)
{
Log.Error("UI form instance is invalid.");
return null;
}
Transform transform = gameObject.transform;
transform.SetParent(((MonoBehaviour)uiGroup.Helper).transform);
transform.localScale = Vector3.one;
return gameObject.GetOrAddComponent<UIForm>();
}
public override void ReleaseUIForm(object uiFormAsset, object uiFormInstance)
{
m_ResourceComponent.UnloadAsset(uiFormAsset);
Destroy((Object)uiFormInstance);
}
private void Start()
{
m_ResourceComponent = GameEntry.GetComponent<ResourceComponent>();
if (m_ResourceComponent == null)
{
Log.Fatal("Resource component is invalid.");
return;
}
}
}
?在上文中我们提到IUIFormHelper接口,这里则是对该接口的具体实现,可见生成UI对象时与正常Instantiate物体时一样的操作,在创建UIForm对象时先将其UI资源转为GameObject之后设置该对象的位置与父类最后添加或取得UIForm组件,并返回该组件.
在GF中对UI物体中的生命周期方法是放在UILogic组件中,UIForm只是有对其的引用.
public sealed class UIForm : MonoBehaviour, IUIForm
{
private int m_SerialId;
private string m_UIFormAssetName;
private IUIGroup m_UIGroup;
private int m_DepthInUIGroup;
private bool m_PauseCoveredUIForm;
private UIFormLogic m_UIFormLogic;
................
}
在OnInit()方法中会先以GetComponent方法来得到UILogic组件,之后的生命周期方法则是对UILogic方法的调用,以打开为例
public void OnOpen(object userData)
{
try
{
m_UIFormLogic.OnOpen(userData);
}
catch (Exception exception)
{
Log.Error("UI form '[{0}]{1}' OnOpen with exception '{2}'.", m_SerialId.ToString(), m_UIFormAssetName, exception.ToString());
}
}
因此对UI的打开关闭等方法是要求开发者进一步编写UILogic组件中的方法来实现.
最后对GF中UI调用的逻辑进行总结
在第一次使用UI模块时首先是在Unity端Inspector面板的UIComponent组件中的组进行添加新组,之后通过该组件的OpenUIForm()方法进行对UIManager对于方法的调用,UIManager之后会先得到对应的组,在组中进行添加新UIForm,,在生成新UIForm时会调用资源加载模块进行对其加载,并对其进行缓存,之后在UIManager内部Open方法中对UIForm生命周期方法进行调用,即对UIForm中UILogic组件中的方法进行进一步调用.
|