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);
}
}