Programming · Building & coding
cocos-code-driven-scrollview-ui
/cocos-code-driven-scrollview-ui
Use when building code-driven scrollable UI panels in Cocos Creator 3.x.
For whom
- Author
- chrislamdev ↗
- Repository
- cocos-creator-debug-skills ↗
- Licence
- MIT
- Last repository change
- 04.07.2026
Assessment and security
96/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability21 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
- Files in this package
- 1
- Scripts
- 0
- HTML comments
- 0
- URLs in SKILL.md
- 0
Deprecation
No signals detected. Repository changed on 04.07.2026, without references to retired models or APIs.
Licence
MIT, open: use and modify while retaining author attribution.
What it does and when to use it
Use when building code-driven scrollable UI panels in Cocos Creator 3.x.
Original author description
Use when building code-driven scrollable UI panels in Cocos Creator 3.x.
How it works
- When To Use
- Architecture Pattern
- ScrollView Construction (Critical)
- Touch Dispatch Pattern
- Lifecycle Management
- cc.d.ts Declarations Needed
- Label Creation Pattern (no isSystemFontUsed)
- Dark Mode Color Constants
- Steps to Add a New Code-Driven Panel
Original SKILL.md headings · 257 lines, 1,213 words
SKILL.md preview
---
name: cocos-code-driven-scrollview-ui
description: Use when building code-driven scrollable UI panels in Cocos Creator 3.x.
version: 1.0.0
author: Hermes Agent
tags: [cocos-creator, code-driven, ui, scrollview, dynamic-node, phase7]
triggers:
- scrollview
- scroll view
- cocos scroll
- list scroll
---
# Cocos Creator 3.x Code-Driven ScrollView UI Panel
## When To Use
When you need to build a complex UI panel (ScrollView + TabBar + Header + interactive cards) in Cocos Creator 3.x **without any Editor manual binding**. The user only needs to create one empty Node in the scene and attach the script.
Best for:
- Phase 7 content migration panels (Scripture Library, Story Engine, Recitation Hall)
- Any temporary test UI that shouldn't clutter the Editor scene
- Panels that need clean lifecycle management (create/destroy without leaks)
## Architecture Pattern
### File Structure (3-file module)
```
assets/scripts/ModuleName/
├── ModuleTypes.ts — Constants, enums, state interfaces
├── ModuleManager.ts — Singleton Cocos Component, data loading + query API
└── ModuleUI.ts — Cocos Component, all dynamic node generation + rendering
```
### Full Node Hierarchy (code-generated in onLoad)
```
ScripturePanel (ScriptureUI Component)
├── header (Node)
│ └── title (Label) — "📚 藏經閣"
├── tabBar (Node)
│ ├── tab_classic1 (Label) — "📜 無量壽經"
│ ├── tab_classic2 (Label) — "📜 觀經"
│ └── ...
├── scrollView (ScrollView)
│ └── view (UITransform + Mask Type.RECT)
│ └── content (UITransform + Layout Type.VERTICAL, ResizeMode.CONTAINER)
│ └── [dynamic child nodes: cards, headings, text, spacers]
└── closeBtn (Label) — "✕"
```
## ScrollView Construction (Critical)
The correct node hierarchy for a working Cocos 3.x ScrollView is:
```typescript
// 1. ScrollView outer node
const svNode = new Node('scrollView');
svNode.setPosition(x, y, 0);
parent.addChild(svNode);
const svTrans = svNode.addComponent(UITransform);
svTrans.width = PANEL_W;
svTrans.height = svH;
// 2. ScrollView component (not on child — on the outer node)
const scrollView = svNode.addComponent(ScrollView);
scrollView.horizontal = false;
scrollView.vertical = true;
scrollView.inertia = true;
scrollView.brake = 0.85;
scrollView.elastic = true;
scrollView.verticalScrollBar = null as any; // hide scrollbar
// ⚠️ CRITICAL: View node MUST have Mask for clipping
const viewNode = new Node('view');
viewNode.setPosition(0, 0, 0);
svNode.addChild(viewNode);
const viewTrans = viewNode.addComponent(UITransform);
viewTrans.width = PANEL_W;
viewTrans.height = svH;
const mask = viewNode.addComponent(Mask);
mask.type = Mask.Type.RECT;
// ⚠️ CRITICAL: Content anchor MUST be (0.5, 1) for vertical scroll from top
const contentNode = new Node('content');
contentNode.setPosition(0, svH / 2, 0); // top-center of view
viewNode.addChild(contentNode);
const contentTrans = contentNode.addComponent(UITransform);
contentTrans.width = PANEL_W - PADDING * 2;
contentTrans.height = svH; // initial, auto-resized by Layout
contentTrans.anchorX = 0.5;
contentTrans.anchorY = 1;
// ⚠️ CRITICAL: Layout with CONTAINER resize mode auto-grows content
const layout = contentNode.addComponent(Layout);
layout.type = Layout.Type.VERTICAL;
layout.resizeMode = Layout.ResizeMode.CONTAINER;
layout.horizontalDirection = Layout.HorizontalDirection.LEFT_TO_RIGHT;
layout.verticalDirection = Layout.VerticalDirection.TOP_TO_BOTTOM;
layout.paddingTop = 30;
layout.paddingLeft = PADDING;
layout.paddingRight = PADDING;
layout.spacingY = 20;
// Link scrollView.content
scrollView.content = contentNode;
```
### ScrollView Pitfalls
| Mistake | Symptom | Fix |
|---------|---------|-----|
| No Mask on View node | Content overflows visible area | Add `viewNode.addComponent(Mask)` with `type = Mask.Type.RECT` |
| Content anchor (0.5, 1) wrong | Content starts from center instead of top | Set `contentTrans.anchorX = 0.5; anchorY = 1` |
| Missing Layout CONTAINER | Content doesn't auto-grow | Add Layout, set `resizeMode = CONTAINER` |
| Setting content height manually | Layout CONTAINER + manual height conflict | Don't set content height — Layout handles it |
| Not linking scrollView.content | ScrollView doesn't know what to scroll | `scrollView.content = contentNode` |
| Forgetting `as any` on scrollBar | null assignment type error | `scrollView.verticalScrollBar = null as any` |
| `scrollView` placed on wrong node | ScrollView doesn't scroll | ScrollView component goes on the OUTER node, NOT the view node |
## Touch Dispatch Pattern
Since all nodes are code-generated, use node **name string prefix** for touch identification (no Editor event system):
```typescript
// Constants for node name prefixes
const TAG_TAB = 'tab_';
const TAG_CARD = 'card_';
const TAG_BACK = 'btn_back';
const TAG_CLOSE = 'btn_close';
onLoad(): void {
this.node.on(Node.EventType.TOUCH_END, this._onTouchEnd, this);
}
// When creating nodes
const tabNode = new Node(TAG_TAB + tab.id); // e.g. "tab_classic1"
const cardNode = new Node(TAG_CARD + classic.id); // e.g. "card_classic1"
backBtn.name = TAG_BACK;
closeBtn.name = TAG_CLOSE;
private _onTouchEnd(event: EventTouch): void {
const target = event.target;
if (!target) return;
const name = target.name;
if (name === TAG_CLOSE) { this.node.destroy(); return; }
if (name === TAG_BACK) { this._showCatalogue(); return; }
if (name.startsWith(TAG_TAB)) { ... }
if (name.startsWith(TAG_CARD)) { ... }
}
```
## Lifecycle Management
```typescript
// Clean content (remove all children) when switching views
private _clearContent(): void {
if (this._contentNode) {
this._contentNode.removeAllChildren();
}
}
// Clean full destruction
// When user clicks close: this.node.destroy()
// Cocos handles recursive child destruction
```
## cc.d.ts Declarations Needed
If your project has a custom `types/cc.d.ts` for `tsc --noEmit`, you need these declarations:
```typescript
// ===== ScrollView =====
export class ScrollView extends Component {
public content: Node | null;
public horizontal: boolean;
public vertical: boolean;
public inertia: boolean;
public brake: number;
public elastic: boolean;
public verticalScrollBar: Node | null;
}
// ===== Layout =====
export namespace Layout {
enum Type { NONE = 0, HORIZONTAL = 1, VERTICAL = 2, GRID = 3 }
enum ResizeMode { NONE = 0, CONTAINER = 1, CHILDREN = 2 }
enum HorizontalDirection { LEFT_TO_RIGHT = 0, RIGHT_TO_LEFT = 1 }
enum VerticalDirection { TOP_TO_BOTTOM = 0, BOTTOM_TO_TOP = 1 }
}
export class Layout extends Component { ... }
// ===== Mask =====
export namespace Mask { enum Type { RECT = 0, ELLIPSE = 1, IMAGE_STENCIL = 2 } }
export class Mask extends Component { public type: Mask.Type; }
// ===== Node setPosition overload =====
// Accept both Vec3 and (x, y, z)
public setPosition(x: number | Vec3, y?: number, z?: number): void;
// ===== UITransform setContentSize overload =====
public setContentSize(w: number, h?: number): void;
public setContentSize(s: Size): void;
// ===== EventTouch =====
export class EventTouch { public target: Node; }
```
## Label Creation Pattern (no `isSystemFontUsed`)
Cocos 3.x Label does NOT have `isSystemFontUsed` property in all versions. Use this safe pattern:
```typescript
private _makeLabel(text: string, fontSize: number, hexColor: string): Node {
const node = new Node('label');
const label = node.addComponent(Label);
label.string = text;
label.fontSize = fontSize;
label.lineHeight = fontSize * 1.6;
label.color = this._hexToColor(hexColor);
label.horizontalAlign = Label.HorizontalAlign.CENTER;
const trans = node.getComponent(UITransform);
if (trans) trans.width = CARD_W;
return node;
}
private _hexToColor(hex: string): Color {
return Color.fromHEX(new Color(), hex);
}
private _wrapText(text: string, charsPerLine: number): string {
// Simple char-count wrapping
let result = '', count = 0;
for (const ch of text) { result += ch; count++; if (count >= charsPerLine) { result += '\n'; count = 0; } }
return result;
}
```
## Dark Mode Color Constants
Place at module top-level for easy global adjustment:
```typescript
const C_BG = '#1A1A2E';
const C_SURFACE = '#16213E';
const C_TEXT_PRIMARY = '#F0EAD6';
const C_TEXT_SECONDARY = '#B8B0A0';
const C_GOLD = '#E8C96A';
const C_PINK = '#D98C7A';
const C_TAB_INACTIVE = '#4A5A7A';
const C_TAB_ACTIVE = '#E8C96A';
```
## Steps to Add a New Code-Driven Panel
1. **Create `Types.ts`** — Tab definitions, UI state interface, defaults
2. **Create `Manager.ts`** — Singleton Component with data loading (async) + query API
3. **Create `UI.ts`** — Component with:
- `onLoad()`: buildHeader(), buildTabBar(), buildScrollView(), buildCloseButton()
- Display methods: showCatalogue(), showClassicContent(), showDailySutra()
- Helper methods: makeLabel(), makeSpacer(), wrapText(), hexToColor()
- Touch handler: _onTouchEnd() with name-based dispatch
4. **Update Bootstrap.ts** — Add import + switch case
5. **Update cc.d.ts** — Add any missing Cocos API declarations
6. **Run `tsc --noEmit`** — Confirm zero errors on new files
7. **Git commit**
8. **User test**: Open Creator → Preview → click button
Versions
The database has no other skills named cocos-code-driven-scrollview-ui.
Database snapshot: 13.11.2026 · package version fc462f8cbdef (SHA-256 digest of the entire package)
Downloads in the last 30 days: 0 · ranking
Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.
Similar skills
- 100cocos-dynamic-ui-panel
Use when building full runtime UI panels in Cocos Creator 3.x. triggers: - ui panel - dynamic ui - cocos ui - cocos panel - 100cocos-code-driven-ui-common-pitfalls
Use when code-driven UI nodes in Cocos Creator 3.x fail to render text or colors. triggers: - cocos ui bug - ui not appear - code driven ui - dynamic node - 100cocos2d
Use this skill when the user says 'cocos2d', 'cocos2d-x', 'cocos creator', 'cocos game', 'cocos build'. Guides Cocos Creator 3.x / Cocos2d-x projects: node tree and components, rendering and batching, physics, UI, multi-platform builds and mobile performance. Do NOT use for:… - 100cocos-creator
Cocos Creator 3.8.x 与 COCOS 4 跨平台 2D/3D 游戏引擎开发助手。用于编写与调试 TypeScript 组件、节点与组件体系、事件系统、Tween/Animation 动画、物理与碰撞、UI(Label/Sprite/Button/Widget/Layout)、资源加载与 AssetBundle、场景管理、性能与 DrawCall 优化,以及发布到微信小游戏、抖音小游戏、H5、iOS、Android、HarmonyOS Next 等平台。当用户提到 Cocos、Cocos Creator、Creator… - 100cocos2d-patterns
Use this skill when the user says 'cocos2d-x internals', 'cocos director', 'cocos scene graph', 'cocos render queue', 'cocos memory management'. Explains Cocos2d-x internals — Director loop, scene graph, render queue and auto-batching, event dispatch, reference-counted memory —… - 100douyin-minigame-helper
抖音小游戏开发助手(Cocos + JavaScript)。当用户咨询抖音小游戏(minigame)的开发、接入、发布、变现、审核问题,或需要 tt.* API 用法、广告/支付/分享/排行榜接入、性能与包体优化、开发者工具使用时引用本技能。