Класс-обёртка для удобства использования UI.Button.
Мне для игры понадобилось программно сделать кнопки с номерами уровней.
Сделал GridLayout, в который добавлял кнопки, создавая их из префаба.
Возникла проблема с событием onClick.
Код:
void InitLevelTasks()
{
levelChooser = new LevelChooser(imageForLevelTask);
Transform root = PanelLevelsList;
foreach (Transform child in root) {
Destroy(child.gameObject);
}
int count = 48;
for (int k = 0; k < count; ++k) {
var clone = GameObject.Instantiate(buttonPrefab);
clone.transform.SetParent(root);
clone.transform.localScale = Vector3.one;
var button = clone.GetComponent<Button>();
text = button.transform.Find("Text").GetComponent<Text>();
text.text = ""+k;
UnityAction act = new UnityAction (() => SelectLevel_Start (k));
button.onClick.AddListener(act);
}
}
Любая кнопка при нажатии стартует уровень 48 - т.е. это значение К при выходе из цикла.
Я с ходу не понял, как можно впихнуть корректный параметр, и сделал обёртку для кнопки.
/* ButtonEventArgs */
public class ButtonEventArgs<TValue> : EventArgs {
public TValue Value { get; private set; }
public ButtonEventArgs(TValue value) {
Value = value;
}
}
/* ButtonWrapper */
public class ButtonWrapper<TParam> {
public event EventHandler<ButtonEventArgs<TParam>> OnClick;
public GameObject gameObject;
Text text;
Button button;
TParam value;
public ButtonWrapper(string caption, TParam value, GameObject buttonPrefab, Transform parent) {
this.value = value;
gameObject = GameObject.Instantiate(buttonPrefab);
gameObject.transform.SetParent(parent);
gameObject.transform.localScale = Vector3.one;
button = gameObject.GetComponent<Button>();
UnityAction act = new UnityAction(Clicked);
button.onClick.AddListener(act);
text = button.transform.Find("Text").GetComponent<Text>();
text.text = caption;
}
public void SetColor(string hex) {
if (!hex.StartsWith("#"))
hex = "#" + hex;
Color c;
ColorUtility.TryParseHtmlString(hex, out c);
button.GetComponent<Image>().color = c;
}
private void Clicked () {
if (OnClick != null)
OnClick(this, new ButtonEventArgs<TParam>(value));
}
}
Что имеем?
1. Событие onClick в виде привычного с# event'a, на которое можно подписаться через +=
2. При клике - событие может содержать любой тип данных, какой мы укажем при создании враппера - достаём данные из параметра ButtonEventArgs.
Итоговый код создания кнопок (добавлена раскраска - 4 разных цвета по 12 кнопок в каждом блоке)
void InitLevelTasks()
{
levelChooser = new LevelChooser(imageForLevelTask);
Transform root = PanelLevelsList;
foreach (Transform child in root) {
Destroy(child.gameObject);
}
int count = 48;
for (int k = 0; k < count; ++k) {
ButtonWrapper<int> wrap = new ButtonWrapper<int>((k + 1).ToString(), k, prefabButtonLevelNum, root);
wrap.OnClick += (sender, e) => {
SelectLevel_Start(e.Value);
};
int v = k / 12;
string color;
if (v == 0)
color = "41C64E";
else if (v == 1)
color = "F9FF67";
else if (v == 2)
color = "3381FF";
else
color = "FF4B3E";
wrap.SetColor(color);
}
}