Files
18xchat/assets/Scripts/chat18x/ui/components/DialogBubble.ts
T

198 lines
5.6 KiB
TypeScript
Raw Normal View History

2025-08-15 18:17:12 +08:00
import {
_decorator,
Component,
Label,
Node,
Overflow,
Size,
2025-09-16 16:55:39 +08:00
Sprite,
2025-08-15 18:17:12 +08:00
UITransform,
2025-08-27 16:12:19 +08:00
view,
2025-08-15 18:17:12 +08:00
} from "cc";
2025-08-11 16:08:59 +08:00
import Tools from "../../utils/tools";
2025-09-16 16:55:39 +08:00
import { GirlData } from "../../data/GirlData";
import { DataId, DataManager } from "../../data/DataManager";
import { NavigationManager } from "../../manager/NavigationManager";
import ResManager from "../../../Main/Manager/ResManager";
2025-09-16 19:23:12 +08:00
import { EnvData } from "../../data/EnvData";
2025-10-11 14:59:05 +08:00
import { WalletData } from "../../data/WalletData";
2025-07-21 22:14:06 +08:00
const { ccclass, property } = _decorator;
@ccclass("DialogBubble")
export class DialogBubble extends Component {
2025-09-16 16:55:39 +08:00
@property(Sprite)
avatar: Sprite = null;
2025-07-21 22:14:06 +08:00
@property(UITransform)
bg: UITransform = null;
@property(Label)
content: Label = null;
@property(UITransform)
contentT: UITransform = null;
2025-10-11 14:59:05 +08:00
@property(Node)
vipFrame: Node = null;
2025-08-15 18:17:12 +08:00
fixMaxWidth: number;
2025-09-16 16:55:39 +08:00
uiTransform: UITransform;
2025-08-27 16:12:19 +08:00
init(maxWidth?: number) {
2025-09-16 16:55:39 +08:00
this.uiTransform = this.node.getComponent(UITransform);
2025-08-27 16:12:19 +08:00
// 如果没有提供maxWidth,使用屏幕宽度的80%
if (maxWidth === undefined) {
this.fixMaxWidth = view.getVisibleSize().width * 0.8;
} else {
this.fixMaxWidth = maxWidth;
}
2025-08-15 18:17:12 +08:00
}
2025-09-10 18:12:26 +08:00
updateBubbleContent(
str: string,
2025-09-16 16:55:39 +08:00
isPlayer: boolean = false,
2025-09-10 18:12:26 +08:00
callback?: (actualHeight: number) => void,
isLoading: boolean = false
) {
2025-08-27 16:12:19 +08:00
// 停止之前的加载动画
this.stopLoadingAnimation();
2025-09-10 18:12:26 +08:00
2025-08-15 18:17:12 +08:00
this.content.overflow = Overflow.NONE;
2025-09-10 18:12:26 +08:00
2025-10-11 14:59:05 +08:00
let isVip = false;
2025-09-20 20:37:31 +08:00
//设置头像
if (isPlayer) {
2025-10-11 14:59:05 +08:00
const walletData = DataManager.I.getDataById<WalletData>(DataId.Wallet);
isVip = walletData.isVip;
2025-09-20 20:37:31 +08:00
//获取玩家头像,等接入luffa
} else {
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
const path = girlData.getGrilAvatar(
NavigationManager.Instance.getSelectedCategoryId().toString(),
NavigationManager.Instance.getSelectedGirlId()
);
// 加载远程资源
const envData = DataManager.I.getDataById<EnvData>(DataId.Env);
let newPath = envData.cdn + "/" + "Girls/" + path + ".png";
ResManager.I.changeRemoteSpriteFrame(this.avatar, newPath, () => {
this.scaleToFillItem(this.avatar, new Size(90, 90));
});
}
2025-08-27 16:12:19 +08:00
// 如果是加载状态,使用固定的"..."
2025-09-17 16:12:54 +08:00
if (isLoading) {
2025-08-27 16:12:19 +08:00
this.content.string = "...";
// 设置固定尺寸用于加载显示
const contentWidth = 60;
this.contentT.setContentSize(new Size(contentWidth, 40));
this.bg.setContentSize(new Size(contentWidth + 30, 50));
2025-09-10 18:12:26 +08:00
2025-08-27 16:12:19 +08:00
if (callback) {
callback(40); // 返回固定高度
}
return;
}
2025-10-11 14:59:05 +08:00
if (this.vipFrame) this.vipFrame.active = isVip;
2025-09-10 18:12:26 +08:00
2025-08-13 12:55:27 +08:00
// 设置文本内容
2025-07-21 22:14:06 +08:00
this.content.string = str;
2025-08-13 12:55:27 +08:00
// 计算最大宽度(估算)
const lines = str.split("\n");
let maxWidth = 0;
2025-07-21 22:14:06 +08:00
2025-08-13 12:55:27 +08:00
for (const line of lines) {
let lineWidth = 0;
if (Tools.IsChinese(line)) {
2025-08-15 18:17:12 +08:00
lineWidth = 30 * line.length;
2025-08-13 12:55:27 +08:00
} else {
2025-08-15 18:17:12 +08:00
lineWidth = 18 * line.length;
2025-08-13 12:55:27 +08:00
}
maxWidth = Math.max(maxWidth, lineWidth);
}
2025-08-15 18:17:12 +08:00
if (maxWidth > this.fixMaxWidth)
this.content.overflow = Overflow.RESIZE_HEIGHT;
2025-08-13 12:55:27 +08:00
// 限制最大宽度
2025-08-15 18:17:12 +08:00
const contentWidth = Math.min(maxWidth, this.fixMaxWidth);
2025-08-13 12:55:27 +08:00
// 设置内容区域宽度,让Label自动计算高度
this.contentT.setContentSize(new Size(contentWidth, 0));
2025-09-10 18:12:26 +08:00
this.bg.setContentSize(new Size(contentWidth + 37, 0));
2025-09-16 16:55:39 +08:00
this.uiTransform.setContentSize(new Size(contentWidth + 37, 0));
2025-08-13 12:55:27 +08:00
// 强制更新Label的渲染数据以获取正确的高度
this.content.updateRenderData(true);
// 等待一帧后获取Label的实际高度
this.scheduleOnce(() => {
2025-08-15 18:17:12 +08:00
const actualSize =
this.content.node.getComponent(UITransform).contentSize;
2025-08-13 12:55:27 +08:00
// 更新内容区域的实际大小
2025-08-15 18:17:12 +08:00
//this.contentT.setContentSize(new Size(contentWidth, actualHeight));
2025-08-13 12:55:27 +08:00
// 根据内容大小调整背景大小,添加适当的内边距
2025-08-15 18:17:12 +08:00
//const bgHeight = actualHeight + 17;
2025-09-10 18:12:26 +08:00
this.bg.setContentSize(new Size(actualSize.x + 40, actualSize.y + 30));
2025-09-16 16:55:39 +08:00
this.uiTransform.setContentSize(
new Size(actualSize.x + 40, actualSize.y + 30)
);
2025-08-15 18:17:12 +08:00
2025-08-13 12:55:27 +08:00
// 回调通知实际高度
if (callback) {
2025-08-15 18:17:12 +08:00
callback(actualSize.y);
2025-08-13 12:55:27 +08:00
}
}, 0);
// 返回预估的背景高度(用于同步计算)
const estimatedHeight = Math.max(lines.length * 35 + 20, 60); // 最小高度60
2025-09-16 16:55:39 +08:00
2025-09-20 20:37:31 +08:00
return estimatedHeight;
}
2025-09-16 19:23:12 +08:00
2025-09-20 20:37:31 +08:00
scaleToFillItem(img: Sprite, size: Size) {
if (!img || !img.spriteFrame) return;
// 延迟一帧确保UI布局完成
this.doScaleToFill(img, size);
}
doScaleToFill(img: Sprite, size: Size) {
if (!img || !img.spriteFrame) return;
const itemSize = size;
const imageSize = img.spriteFrame.originalSize;
if (
itemSize.width === 0 ||
itemSize.height === 0 ||
imageSize.width === 0 ||
imageSize.height === 0
) {
return;
2025-09-16 16:55:39 +08:00
}
2025-09-20 20:37:31 +08:00
const scaleX = itemSize.width / imageSize.width;
const scaleY = itemSize.height / imageSize.height;
const scale = Math.max(scaleX, scaleY);
// 设置Sprite的sizeMode为CUSTOM,允许自定义大小
img.sizeMode = Sprite.SizeMode.CUSTOM;
// 获取图片节点的UITransform并设置大小
const imgTransform = img.node.getComponent(UITransform);
if (imgTransform) {
imgTransform.setContentSize(
imageSize.width * scale,
imageSize.height * scale
);
}
2025-07-21 22:14:06 +08:00
}
2025-08-27 16:12:19 +08:00
private stopLoadingAnimation() {
// 预留方法,当前实现中不需要动画,但保留接口以备将来使用
}
2025-07-21 22:14:06 +08:00
}