公共弹窗一般即用即生成,不在UIMgr中缓存,生成公共弹窗时正好生成在Canvas的最前面,销毁时也是在Canvas内直接Destroy。

Prefab设计

Hierarchy

Content下面挂载Text组件和ContentSizeFitter组件以及Layout Element组件,Horizontal Fit和Vertical Fit都设置成preferred size,Preferred Width设为550。

Content里面显示的文字有多有少,我们需要把它设置成自适应的,挂载ContentSizeFitter组件能够保证文字的Rect数据随着文字的内容动态变化,从而方便计算。注意,我们不能打开Text组件的Best Fit来自适应,那样会消耗很多性能。挂载Layout Element组件能让文本自动换行。文本宽度超过550时自动换行。

Buttons和One、Two都是横向Stretch模式,PosY和Height都可以设置

样式参考

在自适应计算的过程中,我们以Content的CenterTop锚点为基准点。

自适应计算

挂载Layout Element组件时会强制修改Rect的宽度,我们需要在代码中设置Layout Element的Preferred Width。如果文本长度超过550再打开它。

DialogView

在View文件夹内新建DialogView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;

[BindPrefab(Pathes.DIALOG_VIEW,Consts.BIND_PREFAB_PRIORITY_VIEW)]
public class DialogView : MonoBehaviour, IView
{
private UIUtil _uiUtil;

private readonly string _onePath = "Frame/Buttons/One";
private readonly string _twoPath = "Frame/Buttons/Two";
private readonly string _yesBtn = "Yes";
private readonly string _noBtn = "No";
private readonly float _upAndDown = 40;//content文字距离父级界面上下边界的最小值
private readonly float _leftAndRight = 60;//content文字距离父级界面左右边界的最小值
private readonly float _offset = 40;//content文字距离下边按钮的最小值
private readonly float _maxWidth = 550;//Layout Element指定的content文字宽度最大值
private readonly float _minWidth = 330;//文字框的最小宽度
public void InitDialog(string content, Action trueAction = null, Action falseAction = null)
{
if(_uiUtil == null)
{
_uiUtil = gameObject.AddComponent<UIUtil>();
_uiUtil.Init();
}
UpdateContent(content);
AddAction(trueAction, falseAction);
CoroutineMgr.Instance.ExecuteOnce(ChangeSize());
}
private void UpdateContent(string content)
{
transform.Find("Frame/Content").GetComponent<Text>().text = content;
}
#region 动态改变弹窗大小
//使用ContentSizeFitter后,需要等一帧才能读取到修改后的Rect大小
private IEnumerator ChangeSize()
{
yield return null;
var contentRectTrans = _uiUtil.Get("Frame/Content").RectTransform;
var buttonsRectTrans = _uiUtil.Get("Frame/Buttons").RectTransform;
var frameRectTrans = _uiUtil.Get("Frame").RectTransform;
SetWidth(contentRectTrans,frameRectTrans);
yield return null;
SetHeight(contentRectTrans, buttonsRectTrans, frameRectTrans);
}
private void SetWidth(RectTransform contentRectTrans, RectTransform frameRectTrans)
{
float width = _leftAndRight * 2 + contentRectTrans.rect.width;

float result = 0;
if (width <= _minWidth)
{
result = _minWidth;
}
else if(width > _maxWidth)
{
result = _maxWidth + _leftAndRight * 2;
contentRectTrans.gameObject.GetComponent<LayoutElement>().preferredWidth = _maxWidth;
}
else
{
result = width;
}
frameRectTrans.sizeDelta = new Vector2(result, frameRectTrans.sizeDelta.y);
}
private void SetHeight(RectTransform contentRectTrans, RectTransform buttonsRectTrans, RectTransform frameRectTrans)
{
SetContentY(contentRectTrans);
SetButtonsY(contentRectTrans, buttonsRectTrans);
SetFrameHeight(contentRectTrans, buttonsRectTrans,frameRectTrans);
}
private void SetContentY(RectTransform contentRectTrans)
{
float y = contentRectTrans.rect.height * 0.5f + _upAndDown;

SetAnchorPosY(contentRectTrans, y);
}
private void SetButtonsY(RectTransform contentRectTrans, RectTransform buttonsRectTrans)
{
float offset = _upAndDown + contentRectTrans.rect.height + _offset;
float y = buttonsRectTrans.rect.height * 0.5f + offset;

SetAnchorPosY(buttonsRectTrans, y);
}
private void SetAnchorPosY(RectTransform rectTrans, float y)
{
var pos = rectTrans.anchoredPosition;
pos.y = -y;
rectTrans.anchoredPosition = pos;
}
private void SetFrameHeight(RectTransform contentRectTrans, RectTransform buttonsRectTrans, RectTransform frameRectTrans)
{
float height = contentRectTrans.rect.height + buttonsRectTrans.rect.height + _upAndDown * 2 + _offset;
var size = frameRectTrans.sizeDelta;
size.y = height;
frameRectTrans.sizeDelta = size;
}
#endregion
private void AddAction(Action trueAction, Action falseAction)
{
if (trueAction == null && falseAction == null)
{
SetButtonState(true);
AddOneListener(trueAction);
}
else if (trueAction == null && falseAction != null)
{
Debug.LogError("弹框中的取消按钮不为空时确认按扭不能为空");
AddOneListener(null);
}
else if (trueAction != null && falseAction == null)
{
SetButtonState(true);
AddOneListener(trueAction);
}
else
{
SetButtonState(false);
AddTwoListener(trueAction, falseAction);
}
}
private void SetButtonState(bool isOne)
{

transform.Find(_onePath).gameObject.SetActive(isOne);
transform.Find(_twoPath).gameObject.SetActive(!isOne);
}
private void AddOneListener(Action trueAction)
{
if (trueAction == null)
{
transform.ButtonAction(_onePath + "/" + _yesBtn, UIMgr.Instance.Back);
}
else
{
transform.ButtonAction(_onePath + "/" + _yesBtn, trueAction);
}
}
private void AddTwoListener(Action trueAction, Action falseAction)
{
transform.ButtonAction(_twoPath + "/" + _yesBtn, trueAction);
transform.ButtonAction(_twoPath + "/" + _noBtn, falseAction);
}

public Transform GetTrans()
{
return transform;
}

public void UpdateFun()
{
}

public void Init()
{
}

public void Show()
{
}

public void Hide()
{
Destroy(gameObject);
}
}

UIMgr

UIMgr中写明公共弹窗的调用逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private IView _dialog;
//...
public DialogView ShowDialog(string content, Action trueAction = null, Action falseAction = null)
{
var dialogGo = LoadMgr.Instance.LoadPrefab(Pathes.DIALOG_VIEW, Canvas.transform);
AddTypeComponent(dialogGo, Pathes.DIALOG_VIEW);

DialogView dialogView = dialogGo.GetComponent<DialogView>();
if (dialogView != null)
{
dialogView.InitDialog(content, trueAction, falseAction);
}
_dialog = dialogView;
return dialogView;
}
//...
/// <summary>
/// 返回上一个界面
/// </summary>
public void Back()
{
if(uiStack.Count <=1)//主界面不可以回退
{
return;
}
if (_dialog == null)
{
string name = uiStack.Pop();
HideAll(viewsDic[name]);

name = uiStack.Peek();
ShowAll(viewsDic[name]);
}
else
{
_dialog.Hide();
_dialog = null;
var name = uiStack.Peek();
ShowAll(viewsDic[name]);
}
}

补全强化界面逻辑

StrengthenController

补全强化时钻石不够的弹窗。

1
2
3
4
5
6
7
8
9
10
11
12
13
private void Upgrades()
{
//...

if (money >= cost && GameStateModel.Instance.Level < levelMax)
{
//...
}
else
{
UIMgr.Instance.ShowDialog("钻石不足!");//+++
}
}

PropertyItemController

补全星星不够的弹窗

1
2
3
4
5
6
7
8
9
10
11
12
13
private void AddAction()
{
//...

if (cost <= money)
{
ChangeData();
}
else
{
UIMgr.Instance.ShowDialog("星星不足!");//+++
}
}