info_outline
# CookPixiUI
這是一個主要用於 Code.Gamelet Pixi v5 的 UI 模組。
# 元件介紹
## ScrollView(滑動容器元件)
**ScrollView** 是一個可捲動的容器元件,適用於清單、選單、物品欄等場景。
支援以下功能:
- 指定顯示區域的寬度與高度
- 垂直或水平滑動方向(可選)
- 拖曳滑動內容(支援滑鼠與觸控)
- 慣性滾動(速度遞減)
- 自動遮罩超出區域的內容
- 可動態加入或清除內容項目
### `ScrollView.addContent(...child: PIXI.DisplayObject[]): void;`
添加內容到滑動容器中。
- `child` — 要加入的顯示物件(例如卡片、格子、圖片等)
### `ScrollView.clearContent(): void;`
清除內容容器內的所有子物件。
### 使用範例
```ts
// 請先確保該檔案頂層有 import(引入)ScrollView class(類別)
import ScrollView = CG.CookPixiUI.Components.ScrollView;
```
#### 建立垂直滑動區域
```ts
// 建立一個 300 x (畫面高度 - 100) 的垂直滑動區域
const scrollView_V = new ScrollView(300, CG.Base.pixi.stageHeight - 100, 'vertical');
scrollView_V.position.set(50, 50);
CG.Base.pixi.root.addChild(scrollView_V);
// 單元格尺寸設定(寬 300、高 50)
const rowCellSize = { width: 300, height: 50 };
// 加入 20 個垂直排列的矩形內容
for (let i = 0; i < 20; i++) {
const item = getRowItemCell(i);
scrollView_V.addContent(item);
}
/**
* 建立一個垂直列表用的彩色矩形區塊(含文字)
* @param index 第幾個項目(用來標示文字與計算 Y 座標)
*/
function getRowItemCell(index: number): PIXI.Graphics {
const item = new PIXI.Graphics()
.beginFill(0xFFFFFF * Math.random()) // 隨機顏色
.drawRect(0, 0, rowCellSize.width, rowCellSize.height)
.endFill();
// 設定位置(x 固定,y 根據索引排列)
item.position.set(10, index * (rowCellSize.height + 10));
// 建立文字物件並加入 item 內
const label = new PIXI.Text(`Item ${index + 1}`, {
fontSize: 20,
fill: 0xFFFFFF,
stroke: 0,
strokeThickness: 4,
lineJoin: 'round',
} as PIXI.TextStyle);
label.anchor.set(0, 0.5);
label.position.set(10, 25);
item.addChild(label);
return item;
}
```
#### 建立水平滑動區域
```ts
// 建立一個 (畫面寬度 - 450) x 150 的水平滑動區域
const scrollView_H = new ScrollView(CG.Base.pixi.stageWidth - 450, 150, 'horizontal');
scrollView_H.position.set(400, CG.Base.pixi.stageHeight * 0.5 - 75);
CG.Base.pixi.root.addChild(scrollView_H);
// 單元格尺寸設定(寬 80、高 100)
const colCellSize = { width: 80, height: 100 };
// 加入 15 個水平排列的彩色方塊
for (let i = 0; i < 15; i++) {
const item = getColItemCell(i);
scrollView_H.addContent(item);
}
/**
* 建立一個水平列表用的彩色方塊(含文字)
* @param index 第幾個項目(用來標示文字與計算 X 座標)
*/
function getColItemCell(index: number): PIXI.Graphics {
const item = new PIXI.Graphics()
.beginFill(0x66ccff + (index * 0x111111)) // 每個項目不同顏色
.drawRoundedRect(0, 0, colCellSize.width, colCellSize.height, 12)
.endFill();
// 設定位置(y 固定,x 根據索引排列)
item.position.set(index * (colCellSize.width + 20), 25);
// 建立文字物件並加入 item 內
const label = new PIXI.Text(`${index + 1}`, {
fontSize: 25,
fill: 0xFFFFFF,
stroke: 0,
strokeThickness: 5,
lineJoin: 'round',
} as PIXI.TextStyle);
label.anchor.set(0.5);
label.position.set(40, 50);
item.addChild(label);
return item;
}
```
## ListViewCell(清單項目元件)
**ListViewCell** 是 `ListView` 所使用的 Cell 元件基底類別。
每個 Cell 對應一筆資料,並由 `ListView` 控制其建立、重用與位置配置。
主要功能:
- 儲存並暴露該筆資料與索引(`data` 與 `index`)
- 提供 `setItem(index, data)` 方法,用於資料更新
- 可透過 `this.view` 取得所屬 `ListView` 實例,取得 cell 尺寸或其他設定
使用方式:
- 請繼承此類別並實作 UI 邏輯
- 必須實作 `setItem()`,並在內部呼叫 `super.setItem(index, data)`
- 不需手動設定尺寸,請使用 `view.cellWidth` / `view.cellHeight`
注意事項:
- 每個 Cell 僅代表一筆資料,不持有整份列表
- 請勿在 Cell 內進行與其他 Cell 相關的操作
### `ListViewCell.view: ListView<ListViewCell<T>, T>;`
`ListView` 實例,可經由此取得 `cellWidth`, `cellHeight`
### 使用範例
```ts
// 請先確保該檔案頂層有 import(引入)下列 class(類別)
import ListViewCell = CG.CookPixiUI.Components.ListViewCell;
import ListView = CG.CookPixiUI.Components.ListView;
```
#### 建立用於垂直清單的項目
```ts
/** 一個簡單的 Cell 實作,顯示數字(垂直版)。 */
export class NumberCell_V extends ListViewCell<number> { // <number> 是指這個 Cell 使用的資料格式
private _background: PIXI.Graphics;
private _label: PIXI.Text;
constructor(view: ListView<NumberCell_V>) {
super(view);
this._background = new PIXI.Graphics();
this.addChild(this._background);
this._label = new PIXI.Text('', {
fontSize: 20,
fill: 0x333333,
});
this._label.anchor.set(0.5);
this._label.position.set(view.cellWidth / 2, view.cellHeight / 2);
this.addChild(this._label);
}
/**
* 設定 Cell 資料並更新顯示內容。
* @param index - 資料在列表中的位置
* @param data - 對應的資料內容,等同於上方 ListViewCell 後 <> 內的型別。
*/
setItem(index: number, data: number): void {
super.setItem(index, data); // 一定要呼叫,讓父類別記住 index 和 data,ListView 才能正確管理 Cell
// 從 this.view 裡面取出 cell 的寬高屬性。
const { cellWidth, cellHeight } = this.view;
// 重新繪製底色
this._background.clear()
.beginFill(index % 2 === 0 ? 0xeeeeee : 0xdddddd) // 依據 index 決定底色,用於交錯顯示兩種顏色
.drawRoundedRect(0.5, 0.5, cellWidth - 1, cellHeight - 1, 5)
.endFill();
this._label.text = `#${index} → ${data}`;
}
}
```
#### 建立用於水平清單的項目
```ts
/** 一個簡單的 Cell 實作,顯示數字(水平版)。 */
export class NumberCell_H extends ListViewCell<number> { // <number> 是指這個 Cell 使用的資料格式
private _background: PIXI.Graphics;
private _label: PIXI.Text;
constructor(view: ListView<NumberCell_H>) {
super(view);
this._background = new PIXI.Graphics();
this.addChild(this._background);
this._label = new PIXI.Text('', {
fontSize: 18,
fill: 0x224466
});
this._label.anchor.set(0.5);
this._label.position.set(view.cellWidth / 2, view.cellHeight / 2);
this.addChild(this._label);
}
/**
* 設定 Cell 資料並更新顯示內容。
* @param index - 資料在列表中的位置
* @param data - 對應的資料內容,等同於上方 ListViewCell 後 <> 內的型別。
*/
setItem(index: number, data: number): void {
super.setItem(index, data); // 一定要呼叫,讓父類別記住 index 和 data,ListView 才能正確管理 Cell
// 從 this.view 裡面取出 cell 的寬高屬性。
const { cellWidth, cellHeight } = this.view;
// 重新繪製底色
this._background.clear()
.beginFill(index % 2 === 0 ? 0xddeeff : 0xaabbcc) // 依據 index 決定底色,用於交錯顯示兩種顏色
.drawRoundedRect(0.5, 0.5, cellWidth - 1, cellHeight - 1, 6)
.endFill();
this._label.text = `${data}`;
}
}
```
## ListView(清單元件)
**ListView** 是一個高效能、可重用的清單元件,基於 `ScrollView` 擴充設計。
適用場景:
- 大量資料需要滾動顯示的 UI(如:排行榜、物品欄、列表選單等)
主要特性:
- 支援垂直與水平滾動
- 根據可視區動態建立與回收 Cell,節省效能
- Cell 實例由 `ListView` 自動管理與重用
- 每個 Cell 類別需繼承 `ListViewCell`,並實作 `setItem()`
- Cell 尺寸由建構時指定(`cellWidth`, `cellHeight`),支援動態設計
注意事項:
- 請勿手動新增或刪除 Cell 實例
- 若需支援自動調整 Cell 尺寸,可繼承此類別進一步擴充
### `ListView.addData(...data: U[]): void;`
加入一筆或多筆資料,並立即更新畫面。
- `data` — 欲加入的資料內容
### `ListView.refreshVisibleCells(): void;`
根據目前滾動位置更新可見 Cell。
- 回收不在顯示範圍內的 Cell
- 產生新的 Cell,設定資料與位置
### `ListView.jumpToIndex(index: number): void;`
瞬間跳轉到指定資料索引位置,讓該項目顯示在可視區起始處(上方或左方)。
- `index` — 欲顯示的資料索引
### 使用範例
```ts
// 請先確保該檔案頂層有 import(引入)ListView class(類別)
import ListView = CG.CookPixiUI.Components.ListView;
```
#### 建立垂直滑動區域
```ts
// 建立垂直 ListView 實例
const listView_V = new ListView<NumberCell_V, number>(
300, // 可視寬度
CG.Base.pixi.stageHeight - 100, // 可視高度
NumberCell_V, // Cell(項目條)的 Class(類別)
300, // Cell 的寬度
40, // Cell 的高度
ListView.DIRECTION.VERTICAL // ListView 的方向(垂直)
);
listView_V.position.set(50, 50);
CG.Base.pixi.root.addChild(listView_V);
// 填入資料,生成一個 [0, 1, 2, ... , 99] 的數字陣列
const numbers = Array.from({ length: 100 }, (item, i) => i + 1);
listView_V.addData(...numbers);
// 跳到第 26 筆
listView_V.jumpToIndex(26);
```
#### 建立水平滑動區域
```ts
// 建立水平 ListView 實例
const listView_H = new ListView<NumberCell_H, number>(
CG.Base.pixi.stageWidth - 400, // 可視寬度
100, // 可視高度
NumberCell_H, // Cell(項目條)的 Class(類別)
80, // Cell 的寬度
100, // Cell 的高度
ListView.DIRECTION.HORIZONTAL // ListView 的方向(水平)
);
listView_H.position.set(350, CG.Base.pixi.stageHeight * 0.5 - NumberCell_H.height * 0.5);
CG.Base.pixi.root.addChild(listView_H);
// 填入資料,生成一個 [0, 1, 2, ... , 99] 的數字陣列
const numbers = Array.from({ length: 100 }, (item, i) => i + 1);
listView_H.addData(...numbers);
// 跳到第 50 筆
listView_H.jumpToIndex(50);
```
---
## Authors
**[cook1470](/profile/cook1470)**