热更资源加载部分想使用91焦先生的 BundleMaster UI部分又想使用QFramework的Ui框架 所以对QF的UIkit加载UIPanel资源部分自定义
注:
自定义PanelLoader 意味着 不会具有通过传入的prefabName 前缀匹配对应ResLoader的功能 (这种更适合我 )因为不是使用QF提供的ResLoader加载资源(可以查看ResKitPanelLoaderPool)
没这种功能
采用下面这两种写法
其他方式可以自己拓展
UI预制体的存放位置限制
- 如果使用不填写prefabName的方式 只能存放在"Assets/Bundles/UIPrefab/"目录下 不能嵌套层级(想要嵌套层级的话 可以按照名字和路径进行存储 搜集到一个文件里 然后通过名字匹配查找到指定路径 在加载)
- 如果使用填写prefabName的方式 UI预制体层级随便放
自行导入BundleMaster
自行配置BundleMaster相关
一 直接使用
编写自定义的加载方式进行替换
- 找个地方存放下面这个脚本
- 然后把UIKitWithResKitInit.cs中 Init上的特性给注释了
using System;
using BM;
using UnityEngine;
using Object = UnityEngine.Object;
namespace QFramework
{
public class UIKitWithBMInit
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void Init()
{
UIKit.Config.PanelLoaderPool = new BMPanelLoaderPool();
}
}
public class BMPanelLoaderPool : AbstractPanelLoaderPool
{
public class BMPanelLoader : IPanelLoader
{
private LoadHandler _loadHandler;
private string uiABRootPath="Assets/Bundles/UIPrefab/";
/// <summary>
/// 传递UI预制体的完整路径 GameObjName 不使用全路径的话 UI必须放到"Assets/Bundles/UIWindow/目录下
/// </summary>
/// <param name="panelSearchKeys"></param>
/// <returns></returns>
public GameObject LoadPanelPrefab(PanelSearchKeys panelSearchKeys)
{
if (_loadHandler != null)
{
return (_loadHandler.Asset) as GameObject;
}
if (string.IsNullOrEmpty(panelSearchKeys.GameObjName) && panelSearchKeys.PanelType != null)
{
string nameFullPath = $"{uiABRootPath}{panelSearchKeys.PanelType.Name}.prefab";
return AssetComponent.Load<GameObject>(out _loadHandler, nameFullPath);
}
return AssetComponent.Load<GameObject>(out _loadHandler, panelSearchKeys.GameObjName);
}
public void LoadPanelPrefabAsync(PanelSearchKeys panelSearchKeys, Action<GameObject> onLoad)
{
if (_loadHandler != null)
{
// return (_loadHandler.Asset) as GameObject;
onLoad?.Invoke((_loadHandler.Asset) as GameObject);
return;
}
if (string.IsNullOrEmpty(panelSearchKeys.GameObjName) && panelSearchKeys.PanelType != null)
{
string nameFullPath = $"{uiABRootPath}{panelSearchKeys.PanelType.Name}.prefab";
AssetComponent.LoadAsync<GameObject>(out _loadHandler, nameFullPath);
_loadHandler.Completed += (result) => { onLoad?.Invoke((result.Asset) as GameObject); };
return;
}
AssetComponent.Load<GameObject>(out _loadHandler, panelSearchKeys.GameObjName);
_loadHandler.Completed += (result) => { onLoad?.Invoke((result.Asset) as GameObject); };
}
public void Unload()
{
_loadHandler.UnLoad();
_loadHandler = null;
}
}
protected override IPanelLoader CreatePanelLoader()
{
return new BMPanelLoader();
}
}
}
先使用UIPanel创建一个测试面板
使用
可以正常显示
加载方式通过BM来控制
开发模式加载 然后切换BM资源加载模式为开发模式
AB加载
配置一下分包
先打AB包 然后切换BM资源加载模式为本地模式 copyab资源到StreamingAssets文件夹
然后运行
二 分析
分析
进入UIkit脚本中的OpenPanel<T>方法可以发现
panelSearchKeys.PanelType 记录了测试面板脚本的类型 QFramework.UITestBMResPanel
panelSearchKeys.GameObjName 记录的预制体全路径
通过这两个字段 就可以知道要加载的UI预制体名字和所在的位置
进入UIManager.Instance.OpenUI(panelSearchKeys)这个方法
可以看到在检测到这个面板没被创建的时候会创建一个新的面板
这里跳转到了 var panel = UIKit.Config.LoadPanel(panelSearchKeys); 这个方法
进入UIKitConfig.cs后
可以看到 有一个叫做PanelLoaderPool的字段 这个就是用来存储加载器的加载器池子
找到LoadPanel方法可以看到 池子分配了一个加载起出来
默认的加载器 ResKitPanelLoader
在这个UIKitWithResKitInit中是启动后默认的加载方式
这句话会使方法在场景加载之前执行 意味着UIKitConfig.PanelLoaderPool 会指向这个加载器
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
关于加载器
往下翻可以看到IPanelLoade上凉鞋的注释 很贴心
所以只需要继承IPanelLoader仿照ResKitPanelLoaderPool写一个自己的加载器实现一下同步加载资源和异步加载资源就行了