cocosCreator自适应气泡组件

/* eslint-disable @typescript-eslint/ban-ts-comment */

const { ccclass, menu } = cc._decorator;

/**
 * 自适应气泡组件
 *
 * 小于n字固定高度,自适应宽度
 * 大于n字固定宽度,自适应高度
 */
@ccclass
@menu('自定义组件/自适应气泡组件/BubbleComponent')
export default class BubbleComponent extends cc.Component {
    bg: cc.Node = nn<cc.Node>();

    pop: cc.Node = nn<cc.Node>();

    label: cc.Label = nn<cc.Label>();

    show(data: {
        str: string; //显示的文本
        model: 'left' | 'right'; //气泡尾巴的所在位置
        fontSize?: number; //字体大小
        lineHight?: number; //行高
        paddingLeft?: number; //左右边距
        paddingTop?: number; //上下边距
        fontCountLineMax?: number; //单行最大汉字占位数
    }): void {
        if (!this.bg) {
            this.bg = this.node.getChildByName('bg');
            this.pop = this.node.getChildByName('pop');
            this.label = this.node.getChildByName('label').getComponent(cc.Label);
        }
        if (!this.bg || !this.pop || !this.label) {
            console.error('child node is not found');
            return;
        }
        this.bg.getComponent(cc.Sprite).type = cc.Sprite.Type.SLICED;
        this.bg.getComponent(cc.Sprite).sizeMode = cc.Sprite.SizeMode.CUSTOM;
        this.label.horizontalAlign = cc.Label.HorizontalAlign.LEFT;
        const {
            str,
            fontSize = 24,
            lineHight = 33,
            paddingLeft = 24,
            paddingTop = 10,
            fontCountLineMax = 10,
        } = data;

        this.bg.setPosition(0, 0);
        this.pop.setAnchorPoint(1, 0);
        if (data.model === 'left') {
            this.bg.setAnchorPoint(0, 0);
            this.label.node.setAnchorPoint(0, 0);
            this.pop.scaleX = -1;
            this.label.node.setPosition(paddingLeft, paddingTop);
            this.pop.setPosition(fontSize, -this.pop.height);
        } else if (data.model === 'right') {
            this.bg.setAnchorPoint(1, 0);
            this.label.node.setAnchorPoint(1, 0);
            this.pop.scaleX = 1;
            this.label.node.setPosition(-paddingLeft, paddingTop);
            this.pop.setPosition(-fontSize, -this.pop.height);
        }
        this.label.fontSize = fontSize;
        this.label.lineHeight = lineHight;
        //获取实际需要几行来显示,考虑开头结尾的标点纠正情况
        const lineCount = this.calculateLabelLineCnt(str, fontSize * fontCountLineMax, fontSize);
        if (lineCount === 1) {
            this.label.overflow = cc.Label.Overflow.NONE;
        } else {
            this.label.node.width = fontSize * fontCountLineMax;
            this.label.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
        }
        this.label.string = str;
        //@ts-ignore
        this.label._forceUpdateRenderData(true);
        const width = this.label.node.width + paddingLeft * 2;
        const height = this.label.node.height + paddingTop * 2;
        this.node.height = height;
        this.node.width = width;
        this.bg.width = width;
        this.bg.height = height;
    }

    private calculateLabelLineCnt(content: string, labelWidth: number, fontSize: number) {
        const matchMark = /[!,.:;'}\]%?>、‘“》?。,!]/;
        const wordCnt = (labelWidth / fontSize) >> 0;
        const sentence = content.split('\n');
        let lineCnt = 0;
        for (let i = 0, len = sentence.length; i < len; i++) {
            const value = sentence[i];
            for (let mark = 0, len = value.length; mark < len; ) {
                lineCnt++;
                mark += wordCnt;
                matchMark.test(value[mark]) && mark--;
            }
        }
        return lineCnt;
    }
}

### Cocos Creator 2D 游戏引擎中的自适应布局与屏幕适配方法 #### 调整参考点位置以实现屏幕适配 为了使游戏能够在不同尺寸屏幕上正常显示,可以通过动态调整参考点的位置来确保界面元素相对稳定。当屏幕分辨率发生变化时,通过计算新的参考点坐标,使得UI元素能够跟随这些变化而自动调整位置[^2]。 对于Cocos Creator而言,内置有`Widget`组件可以帮助开发者轻松完成这一过程。此组件允许指定某个节点相对于父级或其他特定锚点的对齐方式以及边缘距离,在设计阶段就可预览效果,并且支持运行时根据实际渲染窗口大小实时更新布局参数。 #### 使用 Widget 组件进行全屏适配 针对希望占据整个可视区域的对象(比如背景图),可以为其添加`Widget`组件并将四个方向上的偏移量设为零像素(`0.00px`),同时勾选所有选项以锁定该对象始终贴紧屏幕边界[^3]。这样做不仅简化了编程工作量,还提高了视觉一致性,即使是在多种不同的终端设备上也能保持良好的用户体验。 #### ScrollView 子节点自适应增加 Content 高度 除了基本的屏幕适配外,有时还需要处理更复杂的交互场景,例如滚动视图内项目数量不定的情况。此时可通过脚本逻辑控制ScrollView的内容区(Content)高度随内部子项增多而扩展。具体做法涉及监听子项目的增删事件,并相应修改Content的高度属性值,从而触发重新排版流程[^1]。 ```javascript // 假定已获取到scrollView实例及其content节点引用 let scrollView = this.node.getComponent(cc.ScrollView); let contentNode = scrollView.content; function updateContentSize() { let totalHeight = 0; // 计算所有子节点所需总空间 for (const child of contentNode.children) { totalHeight += child.height; // 如果存在间距还需额外累加 } // 更新content节点的高度 contentNode.height = totalHeight; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值