You've already forked taptap2024_GJ_chidouren
651 lines
21 KiB
C#
651 lines
21 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using Object = UnityEngine.Object;
|
||
|
||
namespace IcecreamView
|
||
{
|
||
/// <summary>
|
||
/// icecream页面管理器,驱动页面的核心控制器,用于控制页面生成、展示、隐藏、跳转等操作
|
||
/// </summary>
|
||
public sealed class IC_Controller : IDisposable
|
||
{
|
||
public static IC_Controller InstantiateViewManager (IC_IViewConfig gameViewConfig, Transform parent)
|
||
{
|
||
var IC = new IC_Controller ();
|
||
IC.Init (gameViewConfig, parent);
|
||
return IC;
|
||
}
|
||
|
||
private IC_ViewConfigGroup _config;
|
||
private List<IC_AbstractView> _viewPool;
|
||
public Transform BaseRoot;
|
||
public Dictionary<int, Canvas> Canvases;
|
||
|
||
private int _curFocusID = 0;
|
||
public IC_AbstractView CurFocusView { get; private set; }
|
||
|
||
public IC_UIEventManager EventManager { get; private set; }
|
||
|
||
public Action<IC_AbstractView> OnViewOpened;
|
||
public Action<IC_AbstractView> OnViewClosed;
|
||
public Action<IC_AbstractView> OnViewFocusChanged;
|
||
|
||
public void Init (IC_IViewConfig gameViewConfig, Transform baseRoot)
|
||
{
|
||
this._config = new IC_ViewConfigGroup ();
|
||
this.BaseRoot = baseRoot;
|
||
EventManager = new IC_UIEventManager ();
|
||
this._viewPool = new List<IC_AbstractView> ();
|
||
this.Canvases = new Dictionary<int, Canvas> ();
|
||
this._curFocusID = 0;
|
||
this.AddConfig (gameViewConfig);
|
||
}
|
||
|
||
public void Init (IC_IViewConfig gameViewConfig, IList<CanvasNode> nodes)
|
||
{
|
||
this._config = new IC_ViewConfigGroup ();
|
||
EventManager = new IC_UIEventManager ();
|
||
this._viewPool = new List<IC_AbstractView> ();
|
||
this.Canvases = new Dictionary<int, Canvas> ();
|
||
foreach (var canvasNode in nodes)
|
||
{
|
||
this.BindCanvas (canvasNode);
|
||
if (canvasNode.IsBaseCanvas)
|
||
this.BaseRoot = canvasNode.Canvas.transform;
|
||
}
|
||
|
||
this.AddConfig (gameViewConfig);
|
||
}
|
||
|
||
#region UI Method
|
||
|
||
public void BindCanvas (CanvasNode canvasNode)
|
||
{
|
||
this.Canvases[canvasNode.OrderRange] = canvasNode.Canvas;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建一个View对象
|
||
/// </summary>
|
||
/// <param name="config"></param>
|
||
/// <param name="Table">ViewTable</param>
|
||
/// <returns></returns>
|
||
private IC_AbstractView CreateView (IC_IViewConfig config, string Table, string group = null)
|
||
{
|
||
var viewModle = config.OnAddView (Table);
|
||
IC_AbstractView gameViewAbstract = UnityEngine.Object.Instantiate (viewModle.GetView (), this.BaseRoot);
|
||
gameViewAbstract.VIEWTABLE = Table;
|
||
gameViewAbstract._configID = config.GetHashCode ();
|
||
gameViewAbstract._group = group;
|
||
// gameViewAbstract.transform.localRotation = Quaternion.Euler(Vector3.zero);
|
||
if (viewModle.IsOnce ())
|
||
{
|
||
gameViewAbstract.isOnce = viewModle.IsOnce ();
|
||
}
|
||
else
|
||
{
|
||
gameViewAbstract.isOnce = ContainsKeyView (Table);
|
||
}
|
||
|
||
gameViewAbstract.openCount = 0;
|
||
gameViewAbstract.SetViewManager (this);
|
||
gameViewAbstract.isOpen = false;
|
||
gameViewAbstract.OnInitView ();
|
||
return gameViewAbstract;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定页面
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="table"></param>
|
||
/// <returns></returns>
|
||
public T GetView<T> (string table) where T : IC_AbstractView
|
||
{
|
||
if (ContainsKeyView (table))
|
||
{
|
||
for (int i = 0; i < this._viewPool.Count; i++)
|
||
{
|
||
if (table.Equals (this._viewPool[i].VIEWTABLE))
|
||
{
|
||
return (T) this._viewPool[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
return default(T);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定table页面的指定Module
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <returns></returns>
|
||
public T GetViewModule<T> (string table) where T : IC_AbstractModule
|
||
{
|
||
var View = GetView<IC_ModuleConnector> (table);
|
||
if (View != null)
|
||
{
|
||
return View.GetViewModule<T> ();
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, string group, int sortingLayer, bool isSinge = true,
|
||
params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, group, sortingLayer, isSinge, null, values);
|
||
}
|
||
|
||
|
||
public IC_AbstractView OpenView (string table, string group, int sortingLayer, bool isSinge = true, Action onOpened = null ,
|
||
params IC_ViewData[] values)
|
||
{
|
||
int viewCount = getViewIndex (table, isSinge);
|
||
//如果已经存在相同页面
|
||
if (viewCount != -1)
|
||
{
|
||
var view = this._viewPool[viewCount];
|
||
if (view.isOpen)
|
||
{
|
||
view.OnHardCloseView ();
|
||
}
|
||
|
||
_curFocusID += 1;
|
||
view.openCount += 1;
|
||
view._group = group;
|
||
view.isOpen = true;
|
||
view.gameObject.SetActive (true);
|
||
this.SetSortOrder (view, sortingLayer);
|
||
view._focusID = _curFocusID;
|
||
view.onOpened = onOpened;
|
||
view.OnOpenView (values);
|
||
UpdateFocusView ();
|
||
this.OnViewOpened?.Invoke (view);
|
||
return view;
|
||
}
|
||
|
||
if (this._config.TryContainsKeyConfig (table , out var config))
|
||
{
|
||
IC_AbstractView gameViewAbstract = CreateView (config , table, group);
|
||
gameViewAbstract.isOpen = true;
|
||
gameViewAbstract.gameObject.SetActive (true);
|
||
this.SetSortOrder (gameViewAbstract, sortingLayer);
|
||
this._viewPool.Add (gameViewAbstract);
|
||
this._curFocusID += 1;
|
||
gameViewAbstract.openCount += 1;
|
||
gameViewAbstract._focusID = this._curFocusID;
|
||
gameViewAbstract.onOpened = onOpened;
|
||
gameViewAbstract.OnOpenView (values);
|
||
UpdateFocusView ();
|
||
this.OnViewOpened?.Invoke (gameViewAbstract);
|
||
return gameViewAbstract;
|
||
}
|
||
|
||
Debug.LogFormat ("<color=yellow>{0}</color>", "IC_Controller : 打开view失败,未找到指定table --- " + table);
|
||
return null;
|
||
}
|
||
|
||
public void SetSortOrder (IC_AbstractView view, int sortingLayer)
|
||
{
|
||
if (sortingLayer == -1)
|
||
sortingLayer = view.DefaultStory;
|
||
view.CurSortOrder = sortingLayer;
|
||
Transform viewTransform;
|
||
(viewTransform = view.transform).SetParent (GetCanvasParent (sortingLayer));
|
||
viewTransform.localScale = Vector3.one;
|
||
viewTransform.localPosition = Vector3.zero;
|
||
viewTransform.localRotation = Quaternion.identity;
|
||
Transform transform;
|
||
(transform = view.transform).SetAsLastSibling ();
|
||
var parent = transform.parent;
|
||
for (int i = parent.childCount - 2; i >= 0; i--)
|
||
{
|
||
var tView = parent.GetChild (i).GetComponent<IC_AbstractView> ();
|
||
if (tView is { gameObject: { activeSelf: true } })
|
||
{
|
||
if (view.CurSortOrder >= tView.CurSortOrder)
|
||
break;
|
||
else
|
||
view.transform.SetSiblingIndex (tView.transform.GetSiblingIndex ());
|
||
}
|
||
}
|
||
}
|
||
|
||
private Transform GetCanvasParent (int order)
|
||
{
|
||
foreach (var canvasesKey in this.Canvases.Keys)
|
||
{
|
||
if (order <= canvasesKey)
|
||
{
|
||
return this.Canvases[canvasesKey].transform;
|
||
}
|
||
}
|
||
|
||
return this.BaseRoot;
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, int sortingLayer, bool isSinge = true,
|
||
params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, null, sortingLayer, isSinge, values);
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, bool isSinge = true, params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, null, -1, isSinge, values);
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, bool isSinge = true, Action onOpened = null, params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, null, -1, isSinge, values);
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, null, -1, true, values);
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, Action onOpened, params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, null, -1, true, onOpened, values);
|
||
}
|
||
|
||
public IC_AbstractView OpenView (string table, string group, params IC_ViewData[] values)
|
||
{
|
||
return OpenView (table, group, -1, true, values);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭所有页面 并打开指定页面
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
/// <returns></returns>
|
||
public IC_AbstractView OpenViewAndCloseOther (string table, bool isSinge, params IC_ViewData[] values)
|
||
{
|
||
if (table == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
this.CloseAllView ();
|
||
IC_AbstractView view = OpenView (table, isSinge, values);
|
||
return view;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提前缓存指定Table数组
|
||
/// </summary>
|
||
/// <param name="Tables"></param>
|
||
internal void CacheView (List<string> Tables)
|
||
{
|
||
foreach (var Table in Tables)
|
||
{
|
||
if (this._config.TryContainsKeyConfig (Table, out var config))
|
||
{
|
||
var view = CreateView (config, Table);
|
||
view.gameObject.SetActive (false);
|
||
this._viewPool.Add (view);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 缓存指定页面
|
||
/// </summary>
|
||
/// <param name="Table"></param>
|
||
/// <returns></returns>
|
||
internal void CacheView (string Table)
|
||
{
|
||
if (this._config.TryContainsKeyConfig (Table, out var config))
|
||
{
|
||
var view = CreateView (config, Table);
|
||
view.gameObject.SetActive (false);
|
||
this._viewPool.Add (view);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断指定table是否存在
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
/// <returns></returns>
|
||
public bool ContainsKeyView (string table)
|
||
{
|
||
for (int i = 0; i < this._viewPool.Count; i++)
|
||
{
|
||
if (table.Equals (this._viewPool[i].VIEWTABLE))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断指定table页面是否已存在
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
/// <returns></returns>
|
||
public bool IsOpenedView (string table)
|
||
{
|
||
for (int i = 0; i < this._viewPool.Count; i++)
|
||
{
|
||
var abstractView = this._viewPool[i];
|
||
if (table.Equals (abstractView.VIEWTABLE) && abstractView.isOpen)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回一个指定table的View对应下标
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
/// <returns></returns>
|
||
private int getViewIndex (string table, bool isSinge = false, bool objectType = false)
|
||
{
|
||
for (int i = 0; i < this._viewPool.Count; i++)
|
||
{
|
||
if (table.Equals (this._viewPool[i].VIEWTABLE, StringComparison.Ordinal))
|
||
{
|
||
if (isSinge)
|
||
{
|
||
return i;
|
||
}
|
||
else if (this._viewPool[i].gameObject.activeSelf == objectType)
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新当前焦点页面
|
||
/// </summary>
|
||
internal void UpdateFocusView ()
|
||
{
|
||
//先计算出当前焦点页面
|
||
var focusView = _getFocusView ();
|
||
//在比较是否与当前的焦点页面相同
|
||
//如果相同则不做处理
|
||
//如果不同则更新当前焦点页面
|
||
if (ReferenceEquals (focusView, null) || focusView == CurFocusView)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var lastFocusView = CurFocusView;
|
||
if (lastFocusView is { CurFocusState: true, isOpen: true })
|
||
{
|
||
lastFocusView.CurFocusState = false;
|
||
}
|
||
|
||
//此处改为先通知新页面获得焦点,再通知旧页面失去焦点
|
||
CurFocusView = focusView;
|
||
CurFocusView.CurFocusState = true;
|
||
CurFocusView.OnFocus (true);
|
||
if (lastFocusView is { CurFocusState: false })
|
||
{
|
||
lastFocusView.OnFocus (false);
|
||
}
|
||
this.OnViewFocusChanged?.Invoke (CurFocusView);
|
||
}
|
||
|
||
IC_AbstractView _getFocusView ()
|
||
{
|
||
//对所有符合规则的页面焦点ID与当前焦点ID进行比较,获得差值最小的页面
|
||
//如果差值相同则取最后打开的页面
|
||
IC_AbstractView view = null;
|
||
int min = int.MaxValue;
|
||
for (int i = 0; i < _viewPool.Count; i++)
|
||
{
|
||
var tempView = _viewPool[i];
|
||
if (tempView.isOpen && tempView.hasFocusView)
|
||
{
|
||
var temp = Mathf.Abs (tempView._focusID - _curFocusID);
|
||
if (temp <= min)
|
||
{
|
||
min = temp;
|
||
view = tempView;
|
||
}
|
||
}
|
||
}
|
||
|
||
return view;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭指定Table的页面
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
/// <param name="onClosed"></param>
|
||
public void CloseView (string table , Action onClosed = null)
|
||
{
|
||
var count = getViewIndex (table, false, true);
|
||
if (count == -1) return;
|
||
_closeView (this._viewPool[count] , onClosed);
|
||
UpdateFocusView ();
|
||
}
|
||
|
||
internal void CloseViewFromView (IC_AbstractView view)
|
||
{
|
||
_closeView (view);
|
||
UpdateFocusView ();
|
||
}
|
||
|
||
private void _closeView (IC_AbstractView view , Action onClosed = null)
|
||
{
|
||
if (ReferenceEquals (view, default)) return;
|
||
|
||
if (!view.isOpen)
|
||
{
|
||
#if UNITY_EDITOR || DEBUG
|
||
Debug.Log (view.VIEWTABLE + " view is Closed");
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
_closeViewBefore (view);
|
||
view.openCount = 0;
|
||
view.isOpen = false;
|
||
view.onClosed = onClosed;
|
||
view.OnCloseView ();
|
||
if (view._closeHook ())
|
||
{
|
||
view._directClose ();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭指定类型的所有页面
|
||
/// </summary>
|
||
/// <param name="table"></param>
|
||
public void CloseTableViews (string table)
|
||
{
|
||
if (table == null) return;
|
||
for (int i = 0; i < this._viewPool.Count; i++)
|
||
{
|
||
if (table.Equals (this._viewPool[i].VIEWTABLE, StringComparison.Ordinal))
|
||
{
|
||
_closeView (_viewPool[i]);
|
||
}
|
||
}
|
||
|
||
UpdateFocusView ();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭指定Group的所有页面
|
||
/// </summary>
|
||
public void CloseViewWithGroup (string group)
|
||
{
|
||
if (group == null) return;
|
||
for (int i = this._viewPool.Count - 1; i >= 0; i--)
|
||
{
|
||
var view = this._viewPool[i];
|
||
if (group.Equals (view.Group, StringComparison.Ordinal))
|
||
{
|
||
_closeView (view);
|
||
}
|
||
}
|
||
|
||
UpdateFocusView ();
|
||
}
|
||
|
||
internal void CloseViewWithConfigId (IC_IViewConfig config)
|
||
{
|
||
var hashCode = config.GetHashCode ();
|
||
for (int i = this._viewPool.Count - 1; i >= 0; i--)
|
||
{
|
||
var view = this._viewPool[i];
|
||
if (view._configID == hashCode)
|
||
{
|
||
_closeView (view);
|
||
}
|
||
}
|
||
|
||
UpdateFocusView ();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭所有页面
|
||
/// </summary>
|
||
public void CloseAllView ()
|
||
{
|
||
for (int i = this._viewPool.Count - 1; i >= 0; i--)
|
||
{
|
||
var view = this._viewPool[i];
|
||
if (view.isOpen)
|
||
{
|
||
_closeView (view);
|
||
}
|
||
}
|
||
|
||
UpdateFocusView ();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 直接销毁所有View,不会触发任何生命周期
|
||
/// </summary>
|
||
internal void ClearAll ()
|
||
{
|
||
_curFocusID = 0;
|
||
CurFocusView = null;
|
||
this._viewPool.ForEach (view => UnityEngine.Object.Destroy (view.gameObject));
|
||
this._viewPool.Clear ();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 销毁指定的view
|
||
/// </summary>
|
||
/// <param name="hash"></param>
|
||
internal void DestroyViewAtHash (int hash)
|
||
{
|
||
for (int i = 0; i < this._viewPool.Count; i++)
|
||
{
|
||
if (this._viewPool[i].gameObject.GetHashCode () == hash)
|
||
{
|
||
// GameObject.Destroy(ViewPool[i].gameObject);
|
||
this._config.OnRemoveView (this._viewPool[i]);
|
||
this._viewPool.Remove (this._viewPool[i]);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
// /// <summary>
|
||
// /// 重置view配置表
|
||
// /// </summary>
|
||
// /// <param name="viewConfig"></param>
|
||
// /// <param name="config"></param>
|
||
// public void ResetConfig (IC_IViewConfig viewConfig)
|
||
// {
|
||
// if (viewConfig == null)
|
||
// {
|
||
// return;
|
||
// }
|
||
//
|
||
// this.ClearAll ();
|
||
// this._config?.OnDispose ();
|
||
// this._config = viewConfig;
|
||
// this._config.OnInit ();
|
||
// //缓存页面
|
||
// this.CacheView (this._config.GetCacheTables ());
|
||
// if (!string.IsNullOrEmpty (this._config.GetDefaultViewTable ()))
|
||
// {
|
||
// OpenView (this._config.GetDefaultViewTable ());
|
||
// }
|
||
// }
|
||
|
||
public void AddConfig (IC_IViewConfig config)
|
||
{
|
||
if (config == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (this._config.AddConfig (config))
|
||
{
|
||
config.OnInit ();
|
||
//缓存页面
|
||
this.CacheView (this._config.GetCacheTables ());
|
||
}
|
||
}
|
||
|
||
public void RemoveConfig (IC_IViewConfig config)
|
||
{
|
||
if (config == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
this.CloseViewWithConfigId (config);
|
||
this._config.RemoveConfig (config);
|
||
}
|
||
|
||
public void Dispose ()
|
||
{
|
||
foreach (var value in Canvases.Values)
|
||
{
|
||
Object.Destroy (value.gameObject);
|
||
}
|
||
|
||
this.Canvases.Clear ();
|
||
this.ClearAll ();
|
||
this._config?.OnDispose ();
|
||
System.GC.Collect ();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 真正被销毁之前
|
||
/// </summary>
|
||
/// <param name="view"></param>
|
||
internal void _closeViewBefore (IC_AbstractView view)
|
||
{
|
||
if (view.CurFocusState)
|
||
{
|
||
view.CurFocusState = false;
|
||
// view.OnFocus (false);
|
||
}
|
||
|
||
_curFocusID -= view.openCount;
|
||
if (_curFocusID < 0)
|
||
{
|
||
_curFocusID = 0;
|
||
}
|
||
}
|
||
}
|
||
} |