Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 Unity3D热更新之LuaFramework篇[02]--用Lua建立本身的面板

时隔一个多月我又回来啦!html

坚持真的是很难的一件事,其它事情稍忙,就很容易说服本身把写博客的计划给推迟了。git

好在终于克服了本身的惰性,今天又开始了。github

本篇继续个人Luaframework学习之路。c#

 1、规范开发模式

此前的示例中,动态加载的panel都默认以GuiCamera为父节点,且面板的大小设置得有些随意,为方便后续开发,现作一些调整和规范。框架

一、设定本项目的开发分辨率为1334x750(Game视图分辨率也设置为这个大小);

二、调整相机,将原有的GuiCamera从Canvas下拖离出来(与Canvas并列),并作以下设置:

(1)Canvas的RenderMode为Screen Space-Camera,并指定Render Camera为GuiCamera;ide

(2)设定GUICamera的投射模式(Projection)为正交(Orthogratphic);模块化

(3)设置Size为3.75(3.75 = 750 / 100 /2),这样Canvas的Scale就会为0.01;函数

(4)设置相机的Culling Mask为Everything。post

设置效果见下图:学习

三、调整动态加载panel的父节点为Canvas。

找到Assets/LuaFramework/Scipts/Manager下的PanelManager.cs脚本,找到14行,将本行的

GameObject go = GameObject.FindWithTag("GuiCamera");

修改成:

GameObject go = GameObject.Find("Canvas");

以下图,这样动态加载的panel就会以Canvas为父节点。

 

 2、新建一个登录面板

为了增长学习代入感,后续演示将会以登录场景和大厅场景为示例,文章展现的全部功能,都围绕这两个场景展开。此处先建立一个登录面板。

一、建立一个登录面板

建立一个登录面板,结构层级以下所示,并作成预制体,添加打包。

  这一过程详细作法请参见:Unity3D热更新之LuaFramework篇[02]--用Lua建立本身的面板

二、建立Login相关脚本

建立LoginPanel相应的Lua脚本并设置为首先加载。

在建立LoginCtrl.lua和LoginView.lua脚本的时候,要注意在Controller和View下额外加一层目录login,以作模块化管理。

而后在Require这两个脚本的时候,也要包含login目录:

在CtrlManager.lua头部引用时使用:require "Controller/Login/LoginCtrl";

在define.lua中定义PanelName时使用 "Login/LoginPanel" 

PanelNames = {
    "PromptPanel",    
    "MessagePanel",
    "FirstPanel",
    "Login/LoginPanel"
}

 上述一切步骤完成后,运行游戏就能直接加载出LoginPanel面板了。

 

 3、添加UI监听

根据此前的经验,添加监听有两个步骤:

一、在LoginView中引用相关组件;

--初始化面板--
function LoginPanel.InitPanel()
--帐号输入框
LoginPanel.accountInput = transform:FindChild("AccountInput").gameObject;
--密码输入框
LoginPanel.passwordInput = transform:FindChild("PwdInput").gameObject;
--登录按钮
LoginPanel.loginBtn = transform:FindChild("LoginButton").gameObject;
--记住密码
LoginPanel.savePwdToggle = transform:FindChild("Toggle").gameObject;
end

二、在LoginCtrl中添加事件处理函数;

登录界面有三种须要交互的元素,一个是按钮,一个是输入框,一个是复选框(Toggle)。

按钮(Button)事件的添加,咱们以前有过介绍,是经过LuaBehaviour的AddClick方法实现的,如以前制做的FirstPanel面板的关闭按钮,见下图。

 

输入框组件(InputField),若是只是须要获取输入值的话,不用添加监听,到找组件并引用,取组件的text值就行了;若是须要在输入结束时作一个操做(如判断用户名是否符合规则,注册时会有此需求),则须要给输入框添加相应监听;

复选框组件(Toggle),这是一个时实交互组件,须要动态的取Toggle的值,所以须要添加监听以判断当前的选择状态。

 

既然按钮能够经过LuaBehaviour脚本添加监听,那么对于Toggle和InputField的监听需是否也能够经过此脚本实现呢?

LuaBehaviour.cs脚本位于Assets\LuaFramework\Scripts\Common目录下,打开后能看到,此脚本的包含有添加按钮监听的方法AddClick,本质是在传递过来的GameObject上查找Button组件,并添加一个委托回调。以下图:

 

此脚本中,还包含了对Lua脚本的驱动方法(xxxPanel.lua脚本中Awake,Start方法被调用,应该就是被LuaBehaviour调用的),以及RemoveClick、ClearClick方法。

可是,并无能给Toggle和InputField组件添加监听的方法。

 这个框架真的是有点简单啊。

 不过咱们既然知道Button组件是怎么实现监听的,其它组件依照着添加一个就好了。

在LuaBehaviour脚本中添加对Toggle的监听方法,以下:

        /// <summary>
        /// 给Toggle组件添加监听
        /// </summary>
        public void AddToggle(GameObject go, LuaFunction luafunc)
        {
            if (go == null || luafunc == null) return;
            buttons.Add(go.name, luafunc);
            go.GetComponent<Toggle>().onValueChanged.AddListener(
                delegate (bool select) {
                    luafunc.Call(go, select);
                }
            );
        }

在LuaBehaviour给输入组件(InputField)添加结束编辑(OnEndEdit)监听,以下:

    //给输入组件(InputField)添加结束编辑(OnEndEdit)监听
    public static void AddInputFieldEndEditHandler(GameObject go, LuaFunction luafunc)
    {
        if (go == null || luafunc == null) return;

        InputField input = go.GetComponent<InputField>();

        if (input == null) {
            Debug.LogError(go.name + "找不到InputField组件");
            return;
        }

        go.GetComponent<InputField>().onEndEdit.AddListener(
            delegate (string text) {
                luafunc.Call(text);
            }
        );
    }

写法仍是很简单的,本质就是调用C#中对相应组件的处理,封装成方法,经过LuaBehaviour脚本以使其能在Lua脚本中被使用。

如今,在LoginCtrl.lua中给帐号输入框添加一个编辑结束事件处理(实际并不须要,这里只是作演示),给记住密码的复选框添加一个状态变化事件处理。 

behaviour.AddInputFieldEndEditHandler(LoginPanel.accountInput, function (account)
log("帐号输入结束,帐号" .. account);
end);
behaviour:AddToggle(LoginPanel.savePwdToggle, function (go, toggleVal)
log("记住密码:" .. tostring(toggleVal));
end);

而后运行,会报错,提示 AddInputFieldEndEditHandler 方法不存在。

缘由是刚刚改动的c#脚本并未生效,这涉及到c#类型到Lua的映射问题,之后再细述。

目前的解决办法是,点击“Lua/Generate All”菜单。

等待Generate 过程结束后,再点击运行,一切正常。

测试InputField的编辑结束事件以及Toggle的状态变化事件,达到预期效果,见下图:

 自定义添加UI监听事件就是这么简单。

 4、后记

一、除了Toggle和InputField的事件外,其它的组件如Slider、Scroll Bar、Scroll View等,均可照此例添加。

二、上一步在LuaBehaviour中添加了两个方法:AddToggle和AddInputFieldEndEditHandler,可是没有实现相关的移除方法,须要本身完善。

三、考虑到功能单一原责,LuaBehaviour最好只包含Behaviour(脚本生命周期)相关的功能,而添加UI监听的功能最好能抽离到一个单独的类中实现,下一篇将会讲这个。 

四、lua中调用C#函数有点"."调用和冒号":"调用的区别,见上文LoginCtrl中AddToggle和AddInputFieldEndEditHandler的使用方法。以下图:

为何会有不一样的用法,是由于, 在LuaBehaviour中添加相应方法的时候作了区别(为了演示),AddToggle是成员方法,AddInputFieldEndEditHandler是静态方法。

总结就是:成员方法调用用冒号,静态方法调用用点号

 

本文相关脚本代码以下:

using UnityEngine;
using LuaInterface;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine.UI;

namespace LuaFramework {
    public class LuaBehaviour : View {
        private string data = null;
        private Dictionary<string, LuaFunction> buttons = new Dictionary<string, LuaFunction>();

        protected void Awake() {
            Util.CallMethod(name, "Awake", gameObject);
        }

        protected void Start() {
            Util.CallMethod(name, "Start");
        }

        protected void OnClick() {
            Util.CallMethod(name, "OnClick");
        }

        protected void OnClickEvent(GameObject go) {
            Util.CallMethod(name, "OnClick", go);
        }

        /// <summary>
        /// 添加单击事件
        /// </summary>
        public void AddClick(GameObject go, LuaFunction luafunc) {
            if (go == null || luafunc == null) return;
            buttons.Add(go.name, luafunc);
            go.GetComponent<Button>().onClick.AddListener(
                delegate() {
                    luafunc.Call(go);
                }
            );
        }

        /// <summary>
        /// 给Toggle组件添加监听
        /// </summary>
        public void AddToggle(GameObject go, LuaFunction luafunc)
        {
            if (go == null || luafunc == null) return;
            buttons.Add(go.name, luafunc);
            go.GetComponent<Toggle>().onValueChanged.AddListener(
                delegate (bool select) {
                    luafunc.Call(go, select);
                }
            );
        }

        //给输入组件(InputField)添加结束编辑(OnEndEdit)监听
        public static void AddInputFieldEndEditHandler(GameObject go, LuaFunction luafunc)
        {
            if (go == null || luafunc == null) return;

            InputField input = go.GetComponent<InputField>();

            if (input == null)
            {
                Debug.LogError(go.name + "找不到InputField组件");
                return;
            }

            go.GetComponent<InputField>().onEndEdit.AddListener(
                delegate (string text) {
                    luafunc.Call(text);
                }
            );
        }

        /// <summary>
        /// 删除单击事件
        /// </summary>
        /// <param name="go"></param>
        public void RemoveClick(GameObject go) {
            if (go == null) return;
            LuaFunction luafunc = null;
            if (buttons.TryGetValue(go.name, out luafunc)) {
                luafunc.Dispose();
                luafunc = null;
                buttons.Remove(go.name);
            }
        }

        /// <summary>
        /// 清除单击事件
        /// </summary>
        public void ClearClick() {
            foreach (var de in buttons) {
                if (de.Value != null) {
                    de.Value.Dispose();
                }
            }
            buttons.Clear();
        }

        //-----------------------------------------------------------------
        protected void OnDestroy() {
            ClearClick();
#if ASYNC_MODE
            string abName = name.ToLower().Replace("panel", "");
            ResManager.UnloadAssetBundle(abName + AppConst.ExtName);
#endif
            Util.ClearMemory();
            Debug.Log("~" + name + " was destroy!");
        }
    }
}
LuaBehaviour.cs
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by Tan.
--- DateTime: 2019/6/1 18:25
---

local transform;
local gameObject;

LoginPanel = {};
local this = LoginPanel;

--启动事件--
function LoginPanel.Awake(obj)
    gameObject = obj;
    transform = obj.transform;

    this.InitPanel();
    logWarn("Awake lua--->>"..gameObject.name);
end

--初始化面板--
function LoginPanel.InitPanel()
    --帐号输入框
    LoginPanel.accountInput = transform:FindChild("AccountInput").gameObject;
    --密码输入框
    LoginPanel.passwordInput = transform:FindChild("PwdInput").gameObject;
    --登录按钮
    LoginPanel.loginBtn = transform:FindChild("LoginButton").gameObject;
    --记住密码
    LoginPanel.savePwdToggle = transform:FindChild("Toggle").gameObject;
end

--单击事件--
function LoginPanel.OnDestroy()
    logWarn("OnDestroy---->>>");
end
LoginPanel.lua
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by Tan.
--- DateTime: 2019/6/1 18:25
---

LoginCtrl = {};
local this = LoginCtrl;

local behaviour;
local transform;
local gameObject;

--构建函数--
function LoginCtrl.New()
    logWarn("LoginCtrl.New--->>");
    return this;
end

function LoginCtrl.Awake()
    logWarn("LoginCtrl.Awake--->>");
    panelMgr:CreatePanel('Login', this.OnCreate);
end

--启动事件--
function LoginCtrl.OnCreate(obj)
    gameObject = obj;
    transform = obj.transform;

    behaviour = gameObject:GetComponent('LuaBehaviour');

    behaviour:AddClick(LoginPanel.loginBtn, function ()
        log("你点击了登录");
    end);

    behaviour.AddInputFieldEndEditHandler(LoginPanel.accountInput, function (account)
        log("帐号输入结束,帐号" .. account);
    end);
    behaviour:AddToggle(LoginPanel.savePwdToggle, function (go, toggleVal)
        log("记住密码:" .. tostring(toggleVal));
    end);

end

--单击事件--
function LoginCtrl.OnClick(go)
    destroy(gameObject);
end

--关闭事件--
function LoginCtrl.Close()
    panelMgr:ClosePanel(CtrlNames.Login);
end
LoginCtrl.lua
相关文章
相关标签/搜索