Тема: ButtonWrapper
Показать сообщение отдельно
Старый 05.04.2016, 13:11   #1
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
ButtonWrapper

Класс-обёртка для удобства использования 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 0count; ++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 captionTParam valueGameObject buttonPrefabTransform 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(hexout 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 0count; ++k) {
        
ButtonWrapper<intwrap = new ButtonWrapper<int>((1).ToString(), kprefabButtonLevelNumroot);
        
wrap.OnClick += (sendere) => {
            
SelectLevel_Start(e.Value);
        };
        
int v 12;
        
string color;
        if (
== 0)
            
color "41C64E";
        else if (
== 1)
            
color "F9FF67";
        else if (
== 2)
            
color "3381FF";
        else
            
color "FF4B3E";
        
wrap.SetColor(color);
    }

(Offline)
 
Ответить с цитированием