cocosCreator Tab内容布局组件(支持编辑器环节使用)

TypeScript 复制代码
const { ccclass, property, menu, disallowMultiple } = cc._decorator;

//tab位置的类型
enum TabType {
    LEFT = 1,
    RIGHT = 2,
    TOP = 3,
    BOTTOM = 4,
}

//tab内部布局
enum TabLayoutType {
    CENTER = 1,
    IN_START = 2,
}
/**
 * tab内容布局组件(支持编辑器环节使用)
 */
@ccclass('TabContentLayoutInRestore')
@menu('组件/tab内容布局组件')
@disallowMultiple
export default class TabContentLayoutInRestore extends cc.Component {
    @property({ type: cc.String, displayName: 'tab关键字', readonly: true })
    tabName = 'tab';

    @property({ type: cc.String, displayName: 'content关键字', readonly: true })
    contentName = 'content';

    @property({ type: Boolean, displayName: '是否按名字内数字排序' })
    isSortByNumber = true;

    _tabWidth = 100;

    @property({ type: Number, displayName: 'tab幅度' })
    get tabWidth() {
        return this._tabWidth;
    }

    set tabWidth(width: number) {
        this._tabWidth = width;
        this.emitOnRestore();
    }

    _tabType = TabType.RIGHT;

    @property({ type: cc.Enum(TabType), displayName: 'tab位置' })
    get tabType() {
        return this._tabType;
    }

    set tabType(type: TabType) {
        this._tabType = type;
        this.emitOnRestore();
    }

    _tabLayoutType = TabLayoutType.CENTER;

    @property({ type: cc.Enum(TabLayoutType), displayName: 'tab布局' })
    get tabLayoutType() {
        return this._tabLayoutType;
    }

    set tabLayoutType(type: TabLayoutType) {
        this._tabLayoutType = type;
        this.emitOnRestore();
    }

    _space = 22;

    @property({
        type: Number,
        displayName: '间距',
        visible() {
            return this.tabLayoutType === TabLayoutType.IN_START;
        },
    })
    get space() {
        return this._space;
    }

    set space(space: number) {
        this._space = space;
        this.emitOnRestore();
    }

    getTabs(node: cc.Node, tabs: cc.Node[]) {
        node.children.forEach((child) => {
            if (child.name.includes(this.tabName)) {
                tabs.push(child);
            }
            if (child.name.includes('Group')) {
                child.children.forEach((item) => {
                    if (item.name.includes(this.tabName)) {
                        tabs.push(item);
                    }
                });
            }
        });
    }

    getContents(node: cc.Node, contents: cc.Node[]) {
        node.children.forEach((child) => {
            if (child.name.includes(this.contentName)) {
                contents.push(child);
            }
            if (child.name.includes('Group')) {
                child.children.forEach((item) => {
                    if (item.name.includes(this.contentName)) {
                        contents.push(item);
                    }
                });
            }
        });
    }

    updateNode(tabs: Array<cc.Node>, contents: Array<cc.Node>) {
        tabs.forEach((tab) => {
            if (tab.parent.uuid !== this.node.uuid) {
                tab.setParent(this.node);
            }
        });
        contents.forEach((content) => {
            if (content.parent.uuid !== this.node.uuid) {
                content.setParent(this.node);
            }
        });
        this.node.children.forEach((child) => {
            if (!tabs.includes(child) && !contents.includes(child)) {
                child.destroy();
            }
        });
    }

    private initTabNodeInLeftRight(tabGroupNode: cc.Node, tabs: Array<cc.Node>) {
        if (this.tabLayoutType === TabLayoutType.CENTER) {
            const allHeight = tabs.reduce((acc, tab) => acc + tab.height, 0);
            const diff = this.node.height - allHeight;
            if (diff > 0) {
                const count = tabs.length + 1;
                tabGroupNode.getComponent(cc.Layout).spacingY = diff / count;
                tabGroupNode.getComponent(cc.Layout).paddingTop = diff / count;
                tabGroupNode.getComponent(cc.Layout).paddingBottom = diff / count;
            }
        }
        if (this.tabLayoutType === TabLayoutType.IN_START) {
            tabGroupNode.getComponent(cc.Layout).paddingTop = this.space;
            tabGroupNode.getComponent(cc.Layout).spacingY = this.space;
        }
    }

    private initTabNodeInTopBottom(tabGroupNode: cc.Node, tabs: Array<cc.Node>) {
        if (this.tabLayoutType === TabLayoutType.CENTER) {
            const allWidth = tabs.reduce((acc, tab) => acc + tab.width, 0);
            const diff = this.node.width - allWidth;
            if (diff > 0) {
                const count = tabs.length + 1;
                tabGroupNode.getComponent(cc.Layout).spacingX = diff / count;
                tabGroupNode.getComponent(cc.Layout).paddingLeft = diff / count;
                tabGroupNode.getComponent(cc.Layout).paddingRight = diff / count;
            }
        }
        if (this.tabLayoutType === TabLayoutType.IN_START) {
            tabGroupNode.getComponent(cc.Layout).paddingLeft = this.space;
            tabGroupNode.getComponent(cc.Layout).spacingX = this.space;
        }
    }

    initTabNode(tabs: Array<cc.Node>) {
        const tabGroupNode = new cc.Node('tGroup');
        tabGroupNode.setParent(this.node);

        tabGroupNode.addComponent(cc.Layout);
        tabGroupNode.addComponent(cc.Widget);

        tabGroupNode.getComponent(cc.Layout).resizeMode = cc.Layout.ResizeMode.NONE;

        tabGroupNode.getComponent(cc.Widget).isAlignRight = true;
        tabGroupNode.getComponent(cc.Widget).isAlignTop = true;
        tabGroupNode.getComponent(cc.Widget).isAlignBottom = true;
        tabGroupNode.getComponent(cc.Widget).isAlignLeft = true;

        if (this.tabType === TabType.LEFT) {
            tabGroupNode.getComponent(cc.Widget).left = 0;
            tabGroupNode.getComponent(cc.Widget).right = this.node.width - this.tabWidth;
            tabGroupNode.getComponent(cc.Widget).top = 0;
            tabGroupNode.getComponent(cc.Widget).bottom = 0;
            tabGroupNode.getComponent(cc.Layout).type = cc.Layout.Type.VERTICAL;
            tabGroupNode.width = this.tabWidth;
            this.initTabNodeInLeftRight(tabGroupNode, tabs);
        }
        if (this.tabType === TabType.RIGHT) {
            tabGroupNode.getComponent(cc.Widget).left = this.node.width - this.tabWidth;
            tabGroupNode.getComponent(cc.Widget).right = 0;
            tabGroupNode.getComponent(cc.Widget).top = 0;
            tabGroupNode.getComponent(cc.Widget).bottom = 0;
            tabGroupNode.getComponent(cc.Layout).type = cc.Layout.Type.VERTICAL;
            tabGroupNode.width = this.tabWidth;
            this.initTabNodeInLeftRight(tabGroupNode, tabs);
        }
        if (this.tabType === TabType.TOP) {
            tabGroupNode.getComponent(cc.Widget).left = 0;
            tabGroupNode.getComponent(cc.Widget).right = 0;
            tabGroupNode.getComponent(cc.Widget).top = 0;
            tabGroupNode.getComponent(cc.Widget).bottom = this.node.height - this.tabWidth;
            tabGroupNode.getComponent(cc.Layout).type = cc.Layout.Type.HORIZONTAL;
            tabGroupNode.height = this.tabWidth;
            this.initTabNodeInTopBottom(tabGroupNode, tabs);
        }
        if (this.tabType === TabType.BOTTOM) {
            tabGroupNode.getComponent(cc.Widget).left = 0;
            tabGroupNode.getComponent(cc.Widget).right = 0;
            tabGroupNode.getComponent(cc.Widget).top = this.node.height - this.tabWidth;
            tabGroupNode.getComponent(cc.Widget).bottom = 0;
            tabGroupNode.getComponent(cc.Layout).type = cc.Layout.Type.HORIZONTAL;
            tabGroupNode.height = this.tabWidth;
            this.initTabNodeInTopBottom(tabGroupNode, tabs);
        }

        tabs.forEach((tab) => {
            tab.setParent(tabGroupNode);
            tab.setPosition(0, 0);
        });
    }

    initContentNode(contents: Array<cc.Node>) {
        const contentGroupNode = new cc.Node('cGroup');
        contentGroupNode.setParent(this.node);
        contentGroupNode.addComponent(cc.Widget);
        contentGroupNode.getComponent(cc.Widget).isAlignLeft = true;
        contentGroupNode.getComponent(cc.Widget).isAlignTop = true;
        contentGroupNode.getComponent(cc.Widget).isAlignBottom = true;
        contentGroupNode.getComponent(cc.Widget).isAlignRight = true;
        if (this.tabType === TabType.LEFT) {
            contentGroupNode.getComponent(cc.Widget).left = this.tabWidth;
            contentGroupNode.getComponent(cc.Widget).right = 0;
            contentGroupNode.getComponent(cc.Widget).top = 0;
            contentGroupNode.getComponent(cc.Widget).bottom = 0;
        }
        if (this.tabType === TabType.RIGHT) {
            contentGroupNode.getComponent(cc.Widget).left = 0;
            contentGroupNode.getComponent(cc.Widget).right = this.tabWidth;
            contentGroupNode.getComponent(cc.Widget).top = 0;
            contentGroupNode.getComponent(cc.Widget).bottom = 0;
        }
        if (this.tabType === TabType.TOP) {
            contentGroupNode.getComponent(cc.Widget).left = 0;
            contentGroupNode.getComponent(cc.Widget).right = 0;
            contentGroupNode.getComponent(cc.Widget).top = this.tabWidth;
            contentGroupNode.getComponent(cc.Widget).bottom = 0;
        }
        if (this.tabType === TabType.BOTTOM) {
            contentGroupNode.getComponent(cc.Widget).left = 0;
            contentGroupNode.getComponent(cc.Widget).right = 0;
            contentGroupNode.getComponent(cc.Widget).top = 0;
            contentGroupNode.getComponent(cc.Widget).bottom = this.tabWidth;
        }

        contents.forEach((content) => {
            content.setParent(contentGroupNode);
            if (!content.getComponent(cc.Widget)) {
                content.addComponent(cc.Widget);
            }

            content.getComponent(cc.Widget).isAlignLeft = true;
            content.getComponent(cc.Widget).isAlignTop = true;
            content.getComponent(cc.Widget).isAlignBottom = true;
            content.getComponent(cc.Widget).isAlignRight = true;
            content.getComponent(cc.Widget).left = 0;
            content.getComponent(cc.Widget).right = 0;
            content.getComponent(cc.Widget).top = 0;
            content.getComponent(cc.Widget).bottom = 0;
        });
    }

    sortNode(tabs: Array<cc.Node>) {
        if (this.isSortByNumber) {
            tabs.sort((a, b) => {
                const aNum = parseInt(a.name.match(/\d+/)[0]);

                const bNum = parseInt(b.name.match(/\d+/)[0]);
                return aNum - bNum;
            });
        }
    }

    emitOnRestore(): void {
        const arr = this.node.getComponentsInChildren(TabContentLayoutInRestore);
        this.play(arr);
    }

    play(arr) {
        arr.forEach((item, i) => {
            setTimeout(() => {
                item.render();
            }, 10 * i);
        });
    }

    render() {
        const tabs = [];
        this.getTabs(this.node, tabs);

        const contents = [];
        this.getContents(this.node, contents);

        this.sortNode(tabs);

        this.sortNode(contents);

        this.updateNode(tabs, contents);

        this.node.getComponent(cc.Layout) && this.node.getComponent(cc.Layout).destroy();

        if (tabs.length === 0 || contents.length === 0) {
            return;
        }

        this.initTabNode(tabs);

        this.initContentNode(contents);
    }
}
相关推荐
w风雨无阻w2 个月前
CocosCreator3.8 IOS 构建插屏无法去除的解决方案
ios·cocoscreator·cocoscreator3.8·插屏
w风雨无阻w2 个月前
CocosCreator 3.8 IOS 热更新失败问题解决方案
android·ios·cocoscreator·热更新·cocoscreator3.8
椰子糖莫莫3 个月前
游戏引擎详解——图片
游戏引擎·cocoscreator
Fuly10243 个月前
Cocos Creator2D游戏开发(14)---CocosCreator常用组件详解
cocoscreator
天马流星27193 个月前
cocosCreator3.X android 真机wifi 调试远程死活无效的问题
android·android studio·cocoscreator
Fuly10243 个月前
Cocos Creator2D游戏开发(5)-飞机大战(3)-手指操作玩家飞机移动
cocoscreator
Fuly10243 个月前
Cocos Creator2D游戏开发(4)-飞机大战(2)-编辑器界面
cocoscreator
平淡风云8 个月前
cocos creator 3.7.2使用shader实现图片扫光特效
前端·typescript·cocoscreator·游戏开发·shader·玩游戏·扫光
w风雨无阻w1 年前
Cocos Creator3.8 项目实战(八)2D UI DrawCall优化详解(上)
笔记·ui·cocoscreator·cocoscreator3.8