perf: 接入预览页面
This commit is contained in:
@@ -478,6 +478,10 @@
|
|||||||
"__uuid__": "3b33c592-ea62-4449-84ed-bf72416d7457",
|
"__uuid__": "3b33c592-ea62-4449-84ed-bf72416d7457",
|
||||||
"__expectedType__": "cc.Prefab"
|
"__expectedType__": "cc.Prefab"
|
||||||
},
|
},
|
||||||
|
"pagePreviewLevelsPrefab": {
|
||||||
|
"__uuid__": "4e73abff-cd5a-42dd-bdfd-34c55645f6ea",
|
||||||
|
"__expectedType__": "cc.Prefab"
|
||||||
|
},
|
||||||
"toastPrefab": {
|
"toastPrefab": {
|
||||||
"__uuid__": "cff2809d-6daa-4749-a911-bb99e97b4b54",
|
"__uuid__": "cff2809d-6daa-4749-a911-bb99e97b4b54",
|
||||||
"__expectedType__": "cc.Prefab"
|
"__expectedType__": "cc.Prefab"
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export class main extends Component {
|
|||||||
@property({ type: Prefab, tooltip: '写关卡页面预制体' })
|
@property({ type: Prefab, tooltip: '写关卡页面预制体' })
|
||||||
pageWriteLevelsPrefab: Prefab | null = null;
|
pageWriteLevelsPrefab: Prefab | null = null;
|
||||||
|
|
||||||
|
@property({ type: Prefab, tooltip: '预览试卷页面预制体' })
|
||||||
|
pagePreviewLevelsPrefab: Prefab | null = null;
|
||||||
|
|
||||||
@property({ type: Prefab, tooltip: 'Toast 预制体' })
|
@property({ type: Prefab, tooltip: 'Toast 预制体' })
|
||||||
toastPrefab: Prefab | null = null;
|
toastPrefab: Prefab | null = null;
|
||||||
|
|
||||||
@@ -61,6 +64,14 @@ export class main extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.pagePreviewLevelsPrefab) {
|
||||||
|
ViewManager.instance.register('PagePreviewLevels', {
|
||||||
|
prefab: this.pagePreviewLevelsPrefab,
|
||||||
|
cache: true,
|
||||||
|
zIndex: 3
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化 Toast 管理器
|
// 初始化 Toast 管理器
|
||||||
if (this.toastPrefab) {
|
if (this.toastPrefab) {
|
||||||
ToastManager.instance.init(this.toastPrefab, this.node);
|
ToastManager.instance.init(this.toastPrefab, this.node);
|
||||||
|
|||||||
2700
assets/prefabs/PagePreviewLevels.prefab
Normal file
2700
assets/prefabs/PagePreviewLevels.prefab
Normal file
File diff suppressed because it is too large
Load Diff
13
assets/prefabs/PagePreviewLevels.prefab.meta
Normal file
13
assets/prefabs/PagePreviewLevels.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.50",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "4e73abff-cd5a-42dd-bdfd-34c55645f6ea",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "PagePreviewLevels"
|
||||||
|
}
|
||||||
|
}
|
||||||
246
assets/prefabs/PagePreviewLevels.ts
Normal file
246
assets/prefabs/PagePreviewLevels.ts
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
import { _decorator, Node, Button, Sprite, Label, ScrollView, instantiate, UITransform, Vec2 } from 'cc';
|
||||||
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
|
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览试卷页面
|
||||||
|
* 垂直滚动展示用户在 PageWriteLevels 中选中的 6 个关卡
|
||||||
|
* 每个关卡展示:封面图、提示1、提示2、答案
|
||||||
|
*
|
||||||
|
* prefab 节点结构(已在编辑器中搭建):
|
||||||
|
* PagePreviewLevels
|
||||||
|
* ├── Bg
|
||||||
|
* ├── IconBack ← backBtn (返回按钮)
|
||||||
|
* ├── PKTitle ← 标题 "挑战"
|
||||||
|
* ├── ScrollView ← scrollView
|
||||||
|
* │ ├── scrollBar
|
||||||
|
* │ └── view
|
||||||
|
* │ └── content ← listContent
|
||||||
|
* ├── ListTpl ← listTemplate (关卡模板)
|
||||||
|
* │ ├── LevelCover ← Sprite 封面图
|
||||||
|
* │ ├── Tips1 ← Label 提示1
|
||||||
|
* │ ├── Tips2 ← Label 提示2
|
||||||
|
* │ └── Answer ← Label 答案
|
||||||
|
* └── BackButton ← backButton (底部返回按钮)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 布局配置 — 垂直列表 */
|
||||||
|
const LAYOUT = {
|
||||||
|
/** 关卡项高度(与 ListTpl UITransform 高度一致) */
|
||||||
|
ITEM_HEIGHT: 300,
|
||||||
|
/** 关卡项之间的垂直间距 */
|
||||||
|
SPACING_Y: 30,
|
||||||
|
/** 列表顶部内边距 */
|
||||||
|
PADDING_TOP: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
@ccclass('PagePreviewLevels')
|
||||||
|
export class PagePreviewLevels extends BaseView {
|
||||||
|
@property({ type: Node, tooltip: '返回按钮(左上角)' })
|
||||||
|
backBtn: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: 'ScrollView 节点' })
|
||||||
|
scrollView: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '列表 content 节点' })
|
||||||
|
listContent: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '关卡模板节点' })
|
||||||
|
listTemplate: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '底部返回按钮' })
|
||||||
|
backButton: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '标题Label节点' })
|
||||||
|
pkTitle: Node | null = null;
|
||||||
|
|
||||||
|
/** 已创建的 item 节点列表 */
|
||||||
|
private _itemNodes: Node[] = [];
|
||||||
|
|
||||||
|
// ─── 生命周期 ───────────────────────────────────────
|
||||||
|
|
||||||
|
onViewLoad(): void {
|
||||||
|
console.log('[PagePreviewLevels] onViewLoad');
|
||||||
|
this._initButtons();
|
||||||
|
this._initScrollView();
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewShow(): void {
|
||||||
|
console.log('[PagePreviewLevels] onViewShow');
|
||||||
|
this._buildList();
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewHide(): void {
|
||||||
|
console.log('[PagePreviewLevels] onViewHide');
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewDestroy(): void {
|
||||||
|
console.log('[PagePreviewLevels] onViewDestroy');
|
||||||
|
this._offButtons();
|
||||||
|
this._clearList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 初始化 ─────────────────────────────────────────
|
||||||
|
|
||||||
|
private _initButtons(): void {
|
||||||
|
if (this.backBtn) {
|
||||||
|
this.backBtn.on(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
|
}
|
||||||
|
if (this.backButton) {
|
||||||
|
this.backButton.on(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _offButtons(): void {
|
||||||
|
if (this.backBtn) {
|
||||||
|
this.backBtn.off(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
|
}
|
||||||
|
if (this.backButton) {
|
||||||
|
this.backButton.off(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _initScrollView(): void {
|
||||||
|
if (!this.listContent) return;
|
||||||
|
const contentTransform = this.listContent.getComponent(UITransform);
|
||||||
|
if (contentTransform) {
|
||||||
|
contentTransform.setAnchorPoint(0.5, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 列表构建 ───────────────────────────────────────
|
||||||
|
|
||||||
|
private _buildList(): void {
|
||||||
|
this._clearList();
|
||||||
|
|
||||||
|
const params = this.getParams();
|
||||||
|
if (!params || !params.selectedIndices || params.selectedIndices.length === 0) {
|
||||||
|
console.warn('[PagePreviewLevels] 未传入选中关卡数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示用户输入的标题
|
||||||
|
if (this.pkTitle) {
|
||||||
|
const label = this.pkTitle.getComponent(Label);
|
||||||
|
if (label) {
|
||||||
|
label.string = params.shareTitle || '挑战';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const indices: number[] = params.selectedIndices;
|
||||||
|
console.log('[PagePreviewLevels] 选中关卡索引:', indices);
|
||||||
|
|
||||||
|
// 更新 content 高度
|
||||||
|
this._updateContentSize(indices.length);
|
||||||
|
|
||||||
|
// 创建每个关卡 item
|
||||||
|
for (let i = 0; i < indices.length; i++) {
|
||||||
|
const levelIndex = indices[i];
|
||||||
|
const itemNode = this._createItem(i);
|
||||||
|
if (itemNode) {
|
||||||
|
this.listContent!.addChild(itemNode);
|
||||||
|
this._itemNodes.push(itemNode);
|
||||||
|
this._loadLevelData(itemNode, levelIndex, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动到顶部
|
||||||
|
const scrollComp = this.scrollView?.getComponent(ScrollView);
|
||||||
|
if (scrollComp) {
|
||||||
|
scrollComp.scrollToTop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _clearList(): void {
|
||||||
|
for (const node of this._itemNodes) {
|
||||||
|
if (node && node.isValid) {
|
||||||
|
node.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._itemNodes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateContentSize(count: number): void {
|
||||||
|
if (!this.listContent) return;
|
||||||
|
const contentTransform = this.listContent.getComponent(UITransform);
|
||||||
|
if (!contentTransform) return;
|
||||||
|
|
||||||
|
const totalHeight = LAYOUT.PADDING_TOP
|
||||||
|
+ count * LAYOUT.ITEM_HEIGHT
|
||||||
|
+ (count > 0 ? (count - 1) * LAYOUT.SPACING_Y : 0)
|
||||||
|
+ LAYOUT.PADDING_TOP;
|
||||||
|
|
||||||
|
contentTransform.setContentSize(contentTransform.contentSize.width, totalHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建单个关卡展示项
|
||||||
|
* content anchor=(0.5, 1),y 轴负向下
|
||||||
|
*/
|
||||||
|
private _createItem(displayIndex: number): Node | null {
|
||||||
|
if (!this.listTemplate) return null;
|
||||||
|
|
||||||
|
const item = instantiate(this.listTemplate);
|
||||||
|
item.active = true;
|
||||||
|
item.name = `preview_item_${displayIndex}`;
|
||||||
|
|
||||||
|
// 垂直居中排列:x=0(水平居中于 content),y 负向下
|
||||||
|
const y = -(LAYOUT.PADDING_TOP + displayIndex * (LAYOUT.ITEM_HEIGHT + LAYOUT.SPACING_Y) + LAYOUT.ITEM_HEIGHT / 2);
|
||||||
|
item.setPosition(0, y, 0);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步加载关卡数据并填充到 item 节点
|
||||||
|
*/
|
||||||
|
private async _loadLevelData(item: Node, levelIndex: number, displayIndex: number): Promise<void> {
|
||||||
|
const config = await LevelDataManager.instance.ensureLevelReady(levelIndex);
|
||||||
|
if (!config || !item.isValid) return;
|
||||||
|
|
||||||
|
// 填充封面图
|
||||||
|
const levelCover = item.getChildByName('LevelCover');
|
||||||
|
if (levelCover) {
|
||||||
|
const sprite = levelCover.getComponent(Sprite);
|
||||||
|
if (sprite && config.spriteFrame) {
|
||||||
|
sprite.spriteFrame = config.spriteFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充提示1
|
||||||
|
const tips1 = item.getChildByName('Tips1');
|
||||||
|
if (tips1) {
|
||||||
|
const label = tips1.getComponent(Label);
|
||||||
|
if (label) {
|
||||||
|
label.string = `线索一:${config.clue1 || ''}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充提示2
|
||||||
|
const tips2 = item.getChildByName('Tips2');
|
||||||
|
if (tips2) {
|
||||||
|
const label = tips2.getComponent(Label);
|
||||||
|
if (label) {
|
||||||
|
label.string = `线索二:${config.clue2 || ''}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充答案
|
||||||
|
const answer = item.getChildByName('Answer');
|
||||||
|
if (answer) {
|
||||||
|
const label = answer.getComponent(Label);
|
||||||
|
if (label) {
|
||||||
|
label.string = `答案:${config.answer || ''}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 事件处理 ───────────────────────────────────────
|
||||||
|
|
||||||
|
private _onBackClick(): void {
|
||||||
|
console.log('[PagePreviewLevels] 返回');
|
||||||
|
ViewManager.instance.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
assets/prefabs/PagePreviewLevels.ts.meta
Normal file
9
assets/prefabs/PagePreviewLevels.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "507c235b-e447-4428-aca5-da55550860a0",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -38,19 +38,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 88
|
"__id__": 88
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 122
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 122
|
"__id__": 128
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 124
|
"__id__": 130
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": {
|
"_prefab": {
|
||||||
"__id__": 126
|
"__id__": 132
|
||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
@@ -875,7 +878,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -730.03,
|
"y": -754.45,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -1250,7 +1253,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": -561.958,
|
"y": -588.057,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -2065,7 +2068,7 @@
|
|||||||
"node": {
|
"node": {
|
||||||
"__id__": 68
|
"__id__": 68
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": false,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 84
|
"__id__": 84
|
||||||
},
|
},
|
||||||
@@ -2933,7 +2936,7 @@
|
|||||||
},
|
},
|
||||||
"clickEvents": [],
|
"clickEvents": [],
|
||||||
"_interactable": true,
|
"_interactable": true,
|
||||||
"_transition": 0,
|
"_transition": 3,
|
||||||
"_normalColor": {
|
"_normalColor": {
|
||||||
"__type__": "cc.Color",
|
"__type__": "cc.Color",
|
||||||
"r": 255,
|
"r": 255,
|
||||||
@@ -2988,6 +2991,165 @@
|
|||||||
"targetOverrides": null,
|
"targetOverrides": null,
|
||||||
"nestedPrefabInstanceRoots": null
|
"nestedPrefabInstanceRoots": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "SelectedLabel",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 123
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 125
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": {
|
||||||
|
"__id__": 127
|
||||||
|
},
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": -330.984,
|
||||||
|
"y": -503.184,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 1,
|
||||||
|
"y": 1,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_mobility": 0,
|
||||||
|
"_layer": 1073741824,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 122
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 124
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 127.572265625,
|
||||||
|
"height": 50.4
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "daK8L6+JFAgYoLC0pXgvHl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"node": {
|
||||||
|
"__id__": 122
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 126
|
||||||
|
},
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_string": "请选择6关",
|
||||||
|
"_horizontalAlign": 1,
|
||||||
|
"_verticalAlign": 1,
|
||||||
|
"_actualFontSize": 28,
|
||||||
|
"_fontSize": 28,
|
||||||
|
"_fontFamily": "Arial",
|
||||||
|
"_lineHeight": 40,
|
||||||
|
"_overflow": 0,
|
||||||
|
"_enableWrapText": true,
|
||||||
|
"_font": null,
|
||||||
|
"_isSystemFontUsed": true,
|
||||||
|
"_spacingX": 0,
|
||||||
|
"_isItalic": false,
|
||||||
|
"_isBold": false,
|
||||||
|
"_isUnderline": false,
|
||||||
|
"_underlineHeight": 2,
|
||||||
|
"_cacheMode": 0,
|
||||||
|
"_enableOutline": false,
|
||||||
|
"_outlineColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_outlineWidth": 2,
|
||||||
|
"_enableShadow": false,
|
||||||
|
"_shadowColor": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_shadowOffset": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 2,
|
||||||
|
"y": 2
|
||||||
|
},
|
||||||
|
"_shadowBlur": 2,
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "6dSEpB9SdA56LwZVP7Ldvd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.PrefabInfo",
|
||||||
|
"root": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"asset": {
|
||||||
|
"__id__": 0
|
||||||
|
},
|
||||||
|
"fileId": "20QMEOOT1Dhb91nKMWbNy/",
|
||||||
|
"instance": null,
|
||||||
|
"targetOverrides": null,
|
||||||
|
"nestedPrefabInstanceRoots": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "d186e8ImsZEVoLE1rP4kkAX",
|
"__type__": "d186e8ImsZEVoLE1rP4kkAX",
|
||||||
"_name": "",
|
"_name": "",
|
||||||
@@ -2998,7 +3160,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 123
|
"__id__": 129
|
||||||
},
|
},
|
||||||
"backBtn": {
|
"backBtn": {
|
||||||
"__id__": 10
|
"__id__": 10
|
||||||
@@ -3012,6 +3174,18 @@
|
|||||||
"listTemplate": {
|
"listTemplate": {
|
||||||
"__id__": 88
|
"__id__": 88
|
||||||
},
|
},
|
||||||
|
"selectedLabel": {
|
||||||
|
"__id__": 122
|
||||||
|
},
|
||||||
|
"completeBtn": {
|
||||||
|
"__id__": 20
|
||||||
|
},
|
||||||
|
"previewBtn": {
|
||||||
|
"__id__": 34
|
||||||
|
},
|
||||||
|
"shareTitleEditBox": {
|
||||||
|
"__id__": 48
|
||||||
|
},
|
||||||
"_id": ""
|
"_id": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3028,7 +3202,7 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": {
|
"__prefab": {
|
||||||
"__id__": 125
|
"__id__": 131
|
||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { _decorator, Node, Button, Sprite, Label, Toggle, ScrollView, instantiate, UITransform, Vec2, EventTouch } from 'cc';
|
import { _decorator, Node, Button, Sprite, Label, Toggle, ScrollView, EditBox, instantiate, UITransform, Vec2, EventTouch } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
||||||
|
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +27,9 @@ const LAYOUT_CONFIG = {
|
|||||||
VIEW_HEIGHT: 1300,
|
VIEW_HEIGHT: 1300,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 必须选择的关卡数量 */
|
||||||
|
const MAX_SELECTION = 6;
|
||||||
|
|
||||||
const PAGE_CONFIG = {
|
const PAGE_CONFIG = {
|
||||||
/** 滑动距离超过页宽的这个比例就翻页 */
|
/** 滑动距离超过页宽的这个比例就翻页 */
|
||||||
SWIPE_THRESHOLD: 0.2,
|
SWIPE_THRESHOLD: 0.2,
|
||||||
@@ -49,6 +53,18 @@ export class PageWriteLevels extends BaseView {
|
|||||||
@property({ type: Node, tooltip: '列表项模板' })
|
@property({ type: Node, tooltip: '列表项模板' })
|
||||||
listTemplate: Node | null = null;
|
listTemplate: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '已选关卡提示Label节点' })
|
||||||
|
selectedLabel: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '完成按钮节点' })
|
||||||
|
completeBtn: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '预览按钮节点' })
|
||||||
|
previewBtn: Node | null = null;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: '分享标题输入框节点' })
|
||||||
|
shareTitleEditBox: Node | null = null;
|
||||||
|
|
||||||
private _selectedIndices: Set<number> = new Set();
|
private _selectedIndices: Set<number> = new Set();
|
||||||
private _currentPage: number = 0;
|
private _currentPage: number = 0;
|
||||||
private _totalPages: number = 0;
|
private _totalPages: number = 0;
|
||||||
@@ -66,12 +82,16 @@ export class PageWriteLevels extends BaseView {
|
|||||||
console.log('[PageWriteLevels] onViewLoad');
|
console.log('[PageWriteLevels] onViewLoad');
|
||||||
this._initButtons();
|
this._initButtons();
|
||||||
this._initScrollView();
|
this._initScrollView();
|
||||||
|
this._updateSelectionUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initButtons(): void {
|
private _initButtons(): void {
|
||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
this.backBtn.on(Button.EventType.CLICK, this._onBackClick, this);
|
this.backBtn.on(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
}
|
}
|
||||||
|
if (this.previewBtn) {
|
||||||
|
this.previewBtn.on(Button.EventType.CLICK, this._onPreviewClick, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initScrollView(): void {
|
private _initScrollView(): void {
|
||||||
@@ -291,16 +311,7 @@ export class PageWriteLevels extends BaseView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _setupItemClick(item: Node, index: number): void {
|
private _setupItemClick(item: Node, index: number): void {
|
||||||
const isSelected = item.getChildByName('IsSelected');
|
// 只用 Button click 统一处理选中/取消,避免 Toggle 事件与 Button 事件同时触发导致双重调用
|
||||||
if (isSelected) {
|
|
||||||
const toggle = isSelected.getComponent(Toggle);
|
|
||||||
if (toggle) {
|
|
||||||
toggle.node.on('toggle', () => {
|
|
||||||
this._onItemToggle(index, toggle.isChecked);
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const button = item.getComponent(Button);
|
const button = item.getComponent(Button);
|
||||||
if (button) {
|
if (button) {
|
||||||
button.node.on(Button.EventType.CLICK, () => {
|
button.node.on(Button.EventType.CLICK, () => {
|
||||||
@@ -325,13 +336,34 @@ export class PageWriteLevels extends BaseView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onItemToggle(index: number, selected: boolean): void {
|
private _onItemToggle(index: number, selected: boolean): void {
|
||||||
|
// 如果要选中但已达上限,阻止选中
|
||||||
|
if (selected && this._selectedIndices.size >= MAX_SELECTION) {
|
||||||
|
// 恢复 toggle 的视觉状态为未选中
|
||||||
|
const item = this._itemNodes[index];
|
||||||
|
if (item) {
|
||||||
|
const isSelected = item.getChildByName('IsSelected');
|
||||||
|
if (isSelected) {
|
||||||
|
const toggle = isSelected.getComponent(Toggle);
|
||||||
|
if (toggle) {
|
||||||
|
toggle.isChecked = false;
|
||||||
|
}
|
||||||
|
const checkmark = isSelected.getChildByName('Checkmark');
|
||||||
|
if (checkmark) {
|
||||||
|
checkmark.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(`[PageWriteLevels] 已达最大选择数量 ${MAX_SELECTION},无法继续选择`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
this._selectedIndices.add(index);
|
this._selectedIndices.add(index);
|
||||||
} else {
|
} else {
|
||||||
this._selectedIndices.delete(index);
|
this._selectedIndices.delete(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[PageWriteLevels] item切换选中:', index, selected);
|
console.log('[PageWriteLevels] item切换选中:', index, selected, '当前已选:', this._selectedIndices.size);
|
||||||
|
|
||||||
const item = this._itemNodes[index];
|
const item = this._itemNodes[index];
|
||||||
if (item) {
|
if (item) {
|
||||||
@@ -347,6 +379,48 @@ export class PageWriteLevels extends BaseView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._updateSelectionUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据当前选中数量更新 SelectedLabel 文本和按钮可用状态。
|
||||||
|
* - 未选择任何关卡时:显示 "请选择6关"
|
||||||
|
* - 已选但不足6关时:显示 "已选 x 关,还差 y 关"
|
||||||
|
* - 恰好选满6关时:显示 "已选满6关",启用按钮
|
||||||
|
*/
|
||||||
|
private _updateSelectionUI(): void {
|
||||||
|
const count = this._selectedIndices.size;
|
||||||
|
const remaining = MAX_SELECTION - count;
|
||||||
|
const isFull = remaining <= 0;
|
||||||
|
|
||||||
|
// 更新 SelectedLabel 文本
|
||||||
|
if (this.selectedLabel) {
|
||||||
|
const label = this.selectedLabel.getComponent(Label);
|
||||||
|
if (label) {
|
||||||
|
if (count === 0) {
|
||||||
|
label.string = `请选择${MAX_SELECTION}关`;
|
||||||
|
} else if (isFull) {
|
||||||
|
label.string = `已选满${MAX_SELECTION}关`;
|
||||||
|
} else {
|
||||||
|
label.string = `已选${count}关,还差${remaining}关`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 CompleteButton 和 PreviewButton 的可用状态
|
||||||
|
if (this.completeBtn) {
|
||||||
|
const btn = this.completeBtn.getComponent(Button);
|
||||||
|
if (btn) {
|
||||||
|
btn.interactable = isFull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.previewBtn) {
|
||||||
|
const btn = this.previewBtn.getComponent(Button);
|
||||||
|
if (btn) {
|
||||||
|
btn.interactable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onBackClick(): void {
|
private _onBackClick(): void {
|
||||||
@@ -354,6 +428,22 @@ export class PageWriteLevels extends BaseView {
|
|||||||
ViewManager.instance.back();
|
ViewManager.instance.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _onPreviewClick(): void {
|
||||||
|
if (this._selectedIndices.size < MAX_SELECTION) {
|
||||||
|
const remaining = MAX_SELECTION - this._selectedIndices.size;
|
||||||
|
ToastManager.instance.show(`还需选择${remaining}个关卡`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const shareTitle = this.shareTitleEditBox?.getComponent(EditBox)?.string?.trim() || '';
|
||||||
|
console.log('[PageWriteLevels] 预览按钮点击,标题:', shareTitle, '已选关卡:', Array.from(this._selectedIndices));
|
||||||
|
ViewManager.instance.open('PagePreviewLevels', {
|
||||||
|
params: {
|
||||||
|
selectedIndices: Array.from(this._selectedIndices),
|
||||||
|
shareTitle: shareTitle
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onViewHide(): void {
|
onViewHide(): void {
|
||||||
console.log('[PageWriteLevels] onViewHide');
|
console.log('[PageWriteLevels] onViewHide');
|
||||||
}
|
}
|
||||||
@@ -363,6 +453,9 @@ export class PageWriteLevels extends BaseView {
|
|||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
this.backBtn.off(Button.EventType.CLICK, this._onBackClick, this);
|
this.backBtn.off(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
}
|
}
|
||||||
|
if (this.previewBtn) {
|
||||||
|
this.previewBtn.off(Button.EventType.CLICK, this._onPreviewClick, this);
|
||||||
|
}
|
||||||
if (this.scrollView) {
|
if (this.scrollView) {
|
||||||
this.scrollView.off(Node.EventType.TOUCH_START, this._onTouchStart, this);
|
this.scrollView.off(Node.EventType.TOUCH_START, this._onTouchStart, this);
|
||||||
this.scrollView.off(Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
this.scrollView.off(Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
||||||
|
|||||||
Reference in New Issue
Block a user