Laya Button 拓展方法

目录


三种使用方式对比

方式 适用场景 优点 缺点
ButtonHelper 代码动态创建按钮 灵活,运行时配置 需要编写代码
ButtonAnimComponent Unity 风格,IDE 配置 可视化配置,设计友好 需要添加组件
IDE 面板注册 快速原型,简单交互 最简单,非零代码 仅支持简单逻辑

方式一:ButtonHelper 拓展方式

ButtonHelper 是按钮辅助类,为按钮提供统一的点击音效和动画效果。

特点

  • ✅ 运行时动态配置
  • ✅ 支持多种预设动画
  • ✅ 可自定义动画逻辑
  • ✅ 统一的音效管理

动画类型

类型 效果描述
ButtonAnimType.None 无动画
ButtonAnimType.Scale 缩放动画:按下缩小后弹回
ButtonAnimType.Shake 摇晃动画:左右摇晃后回正
ButtonAnimType.Bounce 弹跳动画:压扁后回弹
ButtonAnimType.Rotate 旋转动画:旋转一定角度
ButtonAnimType.Pulse 脉冲动画:放大后弹回
ButtonAnimType.Custom 自定义动画

基础用法

import { ButtonHelper, ButtonAnimType } from "./button/utils/ButtonHelper";

// 1. 简单使用 - 指定动画类型
ButtonHelper.setupButton(btnConfirm, ButtonAnimType.Scale);
ButtonHelper.setupButton(btnCancel, ButtonAnimType.Shake);

// 2. 使用预设配置
import { ButtonAnimPresets } from "./button/utils/ButtonHelper";
ButtonHelper.setupButton(btnOK, ButtonAnimPresets.Primary);
ButtonHelper.setupButton(btnDelete, ButtonAnimPresets.Danger);

完整配置示例

ButtonHelper.setupButton(btnAttack, {
    type: ButtonAnimType.Rotate,
    sound: "resources/audio/click.mp3",   // 音效路径
    soundVolume: 0.8,                      // 音量 0-1
    rotation: 180,                         // 旋转角度
    duration: 200,                         // 动画时长(ms)
    ease: Laya.Ease.backOut,               // 缓动函数
    onComplete: () => {                    // 动画完成回调
        console.log("动画完成");
    }
});

自定义动画示例

ButtonHelper.setupButton(btnSpecial, {
    type: ButtonAnimType.Custom,
    sound: "resources/audio/special.mp3",
    customAnim: (btn: Laya.Button) => {
        Laya.TimeLine.to(btn, { rotation: 720, scaleX: 0, scaleY: 0 }, 300)
            .to(btn, { rotation: 0, scaleX: 1, scaleY: 1 }, 400, Laya.Ease.elasticOut)
            .play();
    }
});

预设配置

import { ButtonAnimPresets } from "./button/utils/ButtonHelper";

ButtonAnimPresets.Primary   // 主要按钮:缩放 + 默认点击音
ButtonAnimPresets.Danger    // 危险按钮:摇晃 + 取消音
ButtonAnimPresets.Success   // 成功按钮:脉冲 + 确认音
ButtonAnimPresets.Attack    // 攻击按钮:旋转 + 攻击音

完整示例:StartScript.ts

import { ButtonHelper, ButtonAnimType } from "../index";

const {regClass, property} = Laya;

@regClass()
export class StartScript extends Laya.Script {
    /** 按钮引用(在 IDE 中拖拽赋值) */
    @property(Laya.Button)
    public button: Laya.Button;

    onEnable(): void {
        // 设置全局音量
        Laya.SoundManager.soundVolume = 0.2;

        // 配置按钮动画和音效
        ButtonHelper.setupButton(this.button, {
            type: ButtonAnimType.Bounce,
            sound: "resources/audio/click.mp3",
            duration: 100,
            onComplete: () => {
                // 动画完成后打开游戏场景
                Laya.Scene.open("Game.ls");
            }
        });
    }

    onDisable(): void {
        // 清理资源
        Laya.SoundManager.stopAllSound();
        ButtonHelper.cleanup(this.button);
    }
}

创建测试按钮示例

import { ButtonHelper, ButtonAnimType, ButtonAnimPresets } from "./button/utils/ButtonHelper";

function createTestButton(label: string, x: number, y: number): Laya.Button {
    const btn = new Laya.Button();
    btn.skin = "atlas/comp/button.png";
    btn.label = label;
    btn.labelSize = 24;
    btn.labelColors = "#ffffff,#d4d4d4,#8a8a8a";
    btn.size(160, 50);
    btn.pos(x, y);
    Laya.stage.addChild(btn);
    return btn;
}

// 创建测试按钮
const btnConfirm = createTestButton("缩放动画", 100, 100);
const btnCancel = createTestButton("摇晃动画", 300, 100);
const btnOK = createTestButton("Primary预设", 100, 180);
const btnAttack = createTestButton("旋转攻击", 100, 260);

// 1. 简单使用 - 预设动画类型
ButtonHelper.setupButton(btnConfirm, ButtonAnimType.Scale);
ButtonHelper.setupButton(btnCancel, ButtonAnimType.Shake);

// 2. 使用预设配置
ButtonHelper.setupButton(btnOK, ButtonAnimPresets.Primary);

// 3. 自定义配置(带音效)
ButtonHelper.setupButton(btnAttack, {
    type: ButtonAnimType.Rotate,
    sound: "resources/audio/click.mp3",
    soundVolume: 0.8,
    rotation: 180,
    duration: 200
});

// 添加点击事件
btnConfirm.clickHandler = Laya.Handler.create(null, () => console.log("点击了确认"));

方式二:ButtonAnimComponent 组件方式

类似 Unity 的组件化设计,通过添加组件到按钮上,在 IDE 面板中配置动画和事件。

特点

  • ✅ Unity 风格的组件设计
  • ✅ IDE 可视化配置
  • ✅ 支持方法名绑定(字符串类型。若喜欢无代码编程可使用GUI)

组件属性

属性 类型 默认值 说明
animType ButtonAnimType Scale 动画类型
sound String “” 点击音效路径
soundVolume Number 1 音效音量 (0-1)
duration Number 100 动画持续时间(ms)
scale Number 0.9 缩放比例
rotation Number 15 旋转角度
onClickMethodName String “” 点击事件方法名

使用步骤

1. 在 IDE 中添加组件
  1. 选中场景中的 Button 节点
  2. 在属性检查器中点击"添加组件"
  3. 选择 ButtonAnimComponent
  4. 在面板中配置动画参数
2. 配置点击事件

工作原理

onClickMethodName 使用字符串反射机制,在运行时动态查找和调用方法。查找顺序如下:

1. 在 owner 节点的所有 Script 组件中查找
   ↓ 找到则调用并停止
2. 在 owner 节点自身查找
   ↓ 找到则调用并停止
3. 未找到则输出警告

查找机制详解

// ButtonAnimComponent 内部实现
private invokeMethodByName(methodName: string): void {
    if (!this.owner) return;

    // 1️⃣ 在 owner 的所有 Script 组件中查找
    const scripts = this.owner.getComponents(Laya.Script);
    for (const script of scripts) {
        const method = (script as any)[methodName];
        if (method && typeof method === 'function') {
            method.call(script);  // 找到!调用并停止
            return;
        }
    }

    // 2️⃣ 如果 Script 中没找到,在 owner 自身上查找
    const ownerMethod = (this.owner as any)[methodName];
    if (ownerMethod && typeof ownerMethod === 'function') {
        ownerMethod.call(this.owner);  // 找到!调用并停止
        return;
    }

    // 3️⃣ 未找到,输出警告
    console.warn(`[ButtonAnimComponent] 未找到方法: ${methodName}`);
}

方式一:通过方法名绑定(推荐)

在脚本中定义方法:

const {regClass} = Laya;

@regClass()
export class ClickScript extends Laya.Script {
    onClick(): void {
        console.log("点击了按钮");
    }
}

然后在 IDE 中:

  1. ClickScript 脚本添加到按钮节点(或其父节点)
  2. ButtonAnimComponentonClickMethodName 属性中输入 onClick

查找示例

// 场景结构
Button (Button)
├── ButtonAnimComponent  (onClickMethodName = "handleClick")
└── ClickScript (Script)
    └── handleClick()  // ✅ 在这里找到并调用

多组件场景

// 场景结构
Button (Button)
├── ButtonAnimComponent  (onClickMethodName = "onMenuClick")
├── MenuScript (Script)
│   └── onMenuClick()  // ✅ 优先在 Script 组件中查找
└── AnotherScript (Script)
    └── onMenuClick()  // ✅ 找到第一个后停止

// 查找顺序:MenuScript → AnotherScript

在 owner 自身上定义方法

const {regClass} = Laya;

@regClass()
export class CustomButton extends Laya.Button {
    // 在 Button 自身上定义方法
    onButtonClick(): void {
        console.log("按钮被点击,方法在 owner 自身上");
    }
}
// 场景结构
CustomButton (继承自 Button)
├── ButtonAnimComponent  (onClickMethodName = "onButtonClick")
└── (没有 Script 组件)

// 查找顺序:
// 1. Script 组件:❌ 未找到
// 2. owner 自身:✅ 在 CustomButton 上找到并调用

方法名冲突处理

// ⚠️ 如果多个 Script 组件有同名方法
Button (Button)
├── ButtonAnimComponent  (onClickMethodName = "handleClick")
├── MenuScript (Script)
│   └── handleClick()  // ✅ 第一个找到的被调用
└── AnotherScript (Script)
    └── handleClick()  // ❌ 不会被调用

// 解决方案:使用不同的方法名
onClickMethodName = "onMenuClick"     // MenuScript.handleMenuClick
onClickMethodName = "onItemClick"     // AnotherScript.handleItemClick

参数传递限制

// ❌ 不支持:方法不能有参数
handleClick(event: Laya.Event): void {
    // onClickMethodName 不支持参数传递
}

// ✅ 正确:方法必须无参数
handleClick(): void {
    // 可以通过 this.owner 访问节点
    const btn = this.owner as Laya.Button;
    console.log("按钮标签:", btn.label);
}

完整示例:游戏 UI 菜单

const {regClass} = Laya;

@regClass()
export class MenuScript extends Laya.Script {
    /** 开始按钮 */
    @property(Laya.Button)
    public startButton: Laya.Button;

    /** 设置按钮 */
    @property(Laya.Button)
    public settingsButton: Laya.Button;

    /** 退出按钮 */
    @property(Laya.Button)
    public quitButton: Laya.Button;

    onEnable(): void {
        // 可以在代码中额外配置
        this.startButton.label = "开始游戏";
        this.settingsButton.label = "设置";
        this.quitButton.label = "退出";
    }

    /** 开始游戏 */
    onStartClick(): void {
        console.log("开始游戏");
        Laya.Scene.open("Game.ls");
    }

    /** 打开设置 */
    onSettingsClick(): void {
        console.log("打开设置");
        Laya.Scene.open("Settings.ls");
    }

    /** 退出游戏 */
    onQuitClick(): void {
        console.log("退出游戏");
        Laya.Browser.close();
    }
}

IDE 配置

场景结构:
Scene
├── StartButton (Button)
│   ├── ButtonAnimComponent (onClickMethodName: "onStartClick")
│   └── MenuScript (Script)
├── SettingsButton (Button)
│   ├── ButtonAnimComponent (onClickMethodName: "onSettingsClick")
│   └── MenuScript (Script)
└── QuitButton (Button)
    ├── ButtonAnimComponent (onClickMethodName: "onQuitClick")
    └── MenuScript (Script)

方式二:代码中动态设置

const {regClass} = Laya;

@regClass()
export class GameScript extends Laya.Script {
    @property({type: Laya.Button})
    public startButton: Laya.Button;

    onEnable(): void {
        // 获取按钮上的组件
        const animComp = this.startButton.getComponent(ButtonAnimComponent);

        // 设置点击回调(代码方式,支持闭包)
        animComp.onClick = Laya.Handler.create(this, () => {
            this.startGame();
        });
    }

    startGame(): void {
        console.log("开始游戏");
        Laya.Scene.open("Game.ls");
    }
}

完整示例:ClickScript.ts

脚本定义

const {regClass} = Laya;

@regClass()
export class ClickScript extends Laya.Script {
    onClick(): void {
        console.log("点击了按钮");

        // 可以访问 owner 获取节点信息
        console.log("按钮名称:", this.owner.name);

        // 可以获取组件上的其他组件
        const btn = this.owner as Laya.Button;
        console.log("按钮标签:", btn.label);
    }
}

IDE 配置步骤

  1. 在场景层级中选中 Button 节点
  2. 添加 ButtonAnimComponent 组件
  3. 配置动画参数:
    • animType: Scale
    • sound: resources/audio/click.mp3
    • duration: 100
  4. 添加 ClickScript 脚本到同一节点(或父节点)
  5. ButtonAnimComponentonClickMethodName 中输入 onClick

高级用法:运行时配置

const {regClass} = Laya;

@regClass()
export class DynamicButtonScript extends Laya.Script {
    onEnable(): void {
        const button = this.owner as Laya.Button;

        // 获取或添加动画组件
        let animComp = button.getComponent(ButtonAnimComponent);
        if (!animComp) {
            animComp = button.addComponent(ButtonAnimComponent);
        }

        // 应用配置
        animComp.applyConfig({
            type: ButtonAnimType.Rotate,
            sound: "resources/audio/click.mp3",
            soundVolume: 0.8,
            duration: 200,
            rotation: 360
        });

        // 设置点击回调
        animComp.onClick = Laya.Handler.create(this, () => {
            this.onButtonClick();
        });
    }

    onButtonClick(): void {
        console.log("按钮被点击");

        // 手动触发动画
        const animComp = (this.owner as Laya.Button).getComponent(ButtonAnimComponent);
        animComp.triggerAnimation();
    }
}

组件清理

组件会自动管理生命周期,无需手动清理:

onDisable(): void {
    // 组件自动清理动画和事件监听
}

方式三:IDE 面板注册事件

最简单的方式,直接在 IDE 面板中注册按钮点击事件。

特点

  • ✅ 零代码配置
  • ✅ 快速原型开发
  • ✅ 设计师友好
  • ⚠️ 仅支持简单逻辑

使用步骤

1. 创建脚本方法
const {regClass} = Laya;

@regClass()
export class MainScript extends Laya.Script {
    /** 按钮引用 */
    @property(Laya.Button)
    public startButton: Laya.Button;

    onEnable(): void {
        // 可以在这里进行额外初始化
    }

    /** 开始游戏方法 */
    onGameStart(): void {
        console.log("开始游戏");
        Laya.Scene.open("Game.ls");
    }

    /** 打开设置方法 */
    onOpenSettings(): void {
        console.log("打开设置");
        Laya.Scene.open("Settings.ls");
    }
}
2. 在 IDE 中绑定事件
  1. 选中场景中的 Button 节点
  2. 在属性检查器中找到"组件"列表
  3. 找到 Button 组件的 事件 部分
  4. 点击 click 事件旁边的 + 按钮
  5. 选择节点和脚本方法(如 MainScript.onGameStart

图示说明

┌─────────────────────────────┐
│ Button 组件属性              │
├─────────────────────────────┤
│ skin: button.png            │
│ label: 开始游戏              │
│ stateNum: 3                 │
├─────────────────────────────┤
│ 事件                         │
├─────────────────────────────┤
│ click: [+]                   │
│   └─ MainScript.onGameStart │
└─────────────────────────────┘

完整示例

场景结构

Scene
├── StartButton (Button)
│   └── MainScript (Script)
└── SettingsButton (Button)
    └── MainScript (Script)

脚本代码

const {regClass, property} = Laya;

@regClass()
export class MainScript extends Laya.Script {
    /** 开始按钮 */
    @property(Laya.Button)
    public startButton: Laya.Button;

    /** 设置按钮 */
    @property(Laya.Button)
    public settingsButton: Laya.Button;

    onEnable(): void {
        // 可选:在代码中设置按钮属性
        this.startButton.labelSize = 24;
        this.startButton.labelColors = "#ffffff,#ffff00,#cccccc";
    }

    /** 开始游戏 */
    onGameStart(): void {
        console.log("开始游戏");
        Laya.Scene.open("Game.ls");
    }

    /** 打开设置 */
    onOpenSettings(): void {
        console.log("打开设置");
        Laya.Scene.open("Settings.ls");
    }
}

IDE 配置

  1. 选中 StartButton 节点
  2. 在 Button 组件的 事件click 中,选择 MainScript.onGameStart
  3. 选中 SettingsButton 节点
  4. 在 Button 组件的 事件click 中,选择 MainScript.onOpenSettings

优缺点

优点

  • 最简单,无需编写事件绑定代码
  • 可视化配置,一目了然
  • 适合快速原型

缺点

  • 只能绑定一个方法
  • 不支持传递参数
  • 复杂逻辑需要额外处理

API 参考

ButtonHelper.setupButton()

static setupButton(
    button: Laya.Button,
    config: ButtonAnimConfig | ButtonAnimType
): void

配置按钮的点击动画和音效效果。

参数:

  • button - 按钮实例
  • config - 动画配置对象或动画类型枚举

ButtonAnimConfig

interface ButtonAnimConfig {
    type: ButtonAnimType;           // 动画类型
    sound?: string;                 // 音效路径
    soundVolume?: number;           // 音量 (0-1)
    duration?: number;              // 动画时长(ms)
    scale?: number;                 // 缩放比例
    rotation?: number;              // 旋转角度
    ease?: Function;                // 缓动函数
    customAnim?: (target: Laya.Button) => void;  // 自定义动画
    onComplete?: () => void;        // 动画完成回调
}

ButtonAnimComponent 主要方法

方法 说明
applyConfig(config) 从配置对象快速设置属性
triggerAnimation() 手动触发动画

最佳实践

1. 选择合适的使用方式

场景 推荐方式
运行时动态创建按钮 ButtonHelper
Unity 背景,习惯组件化 ButtonAnimComponent
快速原型,简单交互 IDE 面板注册

2. 事件监听对比

方式 优点 缺点
clickHandler Button 内置,自动清理 只能设置一个处理器
on(Event.CLICK) 支持多个监听器,更灵活 需要手动管理清理

推荐

  • 简单按钮使用 clickHandler
  • 需要多个监听器时使用 on(Event.CLICK)

3. 动画系统使用

LayaAir 中链式动画的正确用法:

// ❌ 错误 - Tween.to 不支持链式调用
Laya.Tween.to(btn, { scaleX: 0.9 }, 50)
    .to(btn, { scaleX: 1 }, 100);

// ✅ 正确 - 使用 TimeLine
Laya.TimeLine.to(btn, { scaleX: 0.9 }, 50)
    .to(btn, { scaleX: 1 }, 100, Laya.Ease.elasticOut)
    .play();

4. 内存管理

  • 按钮销毁时,事件监听器会自动清理
  • ButtonHelper 内部使用 WeakSet 跟踪按钮,不会造成内存泄漏
  • ButtonAnimComponent 会在 onDisable 时自动清理动画

5. 性能优化

// ✅ 推荐:使用对象池复用按钮
let button = Laya.Pool.getItemByClass("Button", Laya.Button);
button.skin = "atlas/comp/button.png";

// ✅ 推荐:避免在 onUpdate 中频繁操作按钮
onUpdate(): void {
    // ❌ 避免
    this.button.alpha = Math.sin(Laya.timer.now * 0.001);
}

6. 组件设计原则

ButtonAnimComponent 设计参考

@regClass()
export class ButtonAnimComponent extends Laya.Component {
    // 1. 使用 @property 暴露可配置属性
    @property({type: ButtonAnimType})
    animType: ButtonAnimType = ButtonAnimType.Scale;

    @property({type: String, isAsset: true, assetTypeFilter: "Audio"})
    sound: string = "";

    // 2. 在生命周期中管理资源
    onEnable(): void {
        // 初始化
    }

    onDisable(): void {
        // 清理资源
        this.clearAllAnimations();
    }

    // 3. 提供公共方法供外部调用
    public applyConfig(config: ButtonAnimConfig): void {
        // 批量设置属性
    }

    public triggerAnimation(): void {
        // 手动触发动画
    }
}

注意事项

事件监听

// ✅ 推荐:使用 clickHandler
btn.clickHandler = Laya.Handler.create(this, () => {
    console.log("按钮被点击");
});

// ✅ 也可以:使用事件监听
btn.on(Laya.Event.CLICK, this, () => {
    console.log("按钮被点击");
});

文本颜色设置

// 格式:"弹起色,经过色,按下色"
btn.labelColors = "#ffffff,#ffff00,#cccccc";
btn.labelStroke = 2;
btn.labelStrokeColor = "#000000";

Toggle 按钮

const toggleBtn = new Laya.Button();
toggleBtn.toggle = true;
toggleBtn.on(Laya.Event.CLICK, toggleBtn, () => {
    console.log("选中状态:", toggleBtn.selected);
});

状态切换

// 两态按钮
const btn2 = new Laya.Button();
btn2.stateNum = 2;
btn2.skin = "resources/two_state.png";

// 单态按钮
const btn1 = new Laya.Button();
btn1.stateNum = 1;
btn1.skin = "resources/one_state.png";

相关文档

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐