為了更貼近游戲實際ui的效果和使用環境, 從而討論上一節遺留的問題, 列表顯示是必不可少的
參考
修改之前的HomeRoute,
private Widget CreateListTest()
{
ListView listView = ListView.builder(
scrollDirection: Axis.vertical,
itemExtent: 20,
itemCount: 100,
itemBuilder: (context, index) =>
{
return new Text(data: index.ToString());
}
);
return listView;
}
private Widget GetWidget()
{
Scaffold scaffold = new Scaffold(
appBar: new AppBar(
title: new Text("首頁")
),
body: CreateListTest()
);
return scaffold;
}
創建了一個列表, 顯示從0到99的數字, 每個列表項高度為20(邏輯高度), 效果如下
通過UIWidgets Inspector可以看到列表項是循環回收的(即看不到的列表項不作為一個UI節點存在), 但這個節點大概已經嵌套了四五十層... 對性能不太信任
顯示背包道具
下面要做的是模擬一個顯示背包道具的操作, 一個簡單的列表顯示玩家背包中的每種道具的名字和一句說明(為簡化, 道具通通不可疊加)
即提前准備好state, 暫時沒有action
首先我准備了幾個道具
// Item.cs
using System.Collections.Generic;
namespace Data
{
// 道具的數據類, 非常簡單
public class Item
{
public int id;
public string name;
public string description;
// 臨時模擬一個配置表
public static Dictionary<int, Item> Table = new Dictionary<int, Item>()
{
{ 1, new Item { id = 1, name = "木棍", description = "一根沒什么用的木棍" } },
{ 2, new Item { id = 2, name = "石頭", description = "一塊沒什么用的石頭" } },
{ 3, new Item { id = 3, name = "干草", description = "一把沒什么用的干草" } },
};
}
}
然后給主角的背包里塞了10個木棍, 10個石頭, 5個干草
// GlobalState.cs
using System.Collections.Generic;
namespace UI
{
public class GlobalState
{
public List<int> Items;
public GlobalState()
{
Items = new List<int>
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3,
};
}
}
}
修改列表顯示
// HomeRoute.cs
private Widget CreateListTest()
{
var widget = new StoreConnector<GlobalState, List<int>>(
converter: (state) => state.Items,
builder: (context, list, dispatcher) => ListView.builder(
itemExtent: 20,
itemCount: list.Count,
itemBuilder: (context2, index) =>
{
int itemId = list[index];
Data.Item data = Data.Item.Table[itemId];
return new Text(data: $"道具名稱: {data.name}, 說明: {data.description}");
}
)
);
return widget;
}
這么寫從直覺上不太對, 但目前成功了
修改背包道具
參照前面的寫法給增加兩個功能: 點擊道具列表項使用\獲取一個新道具
為了更直觀刪除了大部分道具
GlobalState.cs
using System.Collections.Generic;
namespace UI
{
public class GlobalState
{
public List<int> Items;
public GlobalState()
{
UnityEngine.Debug.Log("創建了新的GlobalState");
Items = new List<int>
{
1, 2, 3,
};
}
public GlobalState(List<int> items)
{
UnityEngine.Debug.Log("創建了新的GlobalState, 傳遞了items");
Items = items;
}
}
}
// Actions.cs
namespace UI
{
public class UseBagItemAction
{
public int positionIndex;
}
public class GetItemAction
{
public int itemId;
}
}
// HomeRoute.cs
public static GlobalState Reducer(GlobalState state, object action)
{
if (action is UseBagItemAction)
{
int posId = ((UseBagItemAction)action).positionIndex;
// 這里參照了Redux規范, 復制一份新的再修改, 下同
List<int> items = new List<int>(state.Items);
items.RemoveAt(posId);
return new GlobalState(items);
}
if (action is GetItemAction)
{
int itemId = ((GetItemAction)action).itemId;
List<int> items = new List<int>(state.Items);
items.Add(itemId);
return new GlobalState(items);
}
return state;
}
private Widget CreateListTest()
{
var showList = new StoreConnector<GlobalState, List<int>>(
converter: (state) => state.Items,
builder: (context, list, dispatcher) => ListView.builder(
//itemExtent: 20,
itemCount: list.Count,
itemBuilder: (context2, index) =>
{
int itemId = list[index];
Data.Item data = Data.Item.Table[itemId];
return new RaisedButton(
child: new Text(data: $"{index} - 道具名稱: {data.name}, 說明: {data.description}"),
onPressed: () =>
{
dispatcher.dispatch(new UseBagItemAction { positionIndex = index });
}
);
}
)
);
var btn = new StoreConnector<GlobalState, object>(
converter: (state) => null,
builder: (context, _, dispathcer) => new RaisedButton(
child: new Text("獲得一根木棍"),
onPressed: () =>
{
dispathcer.dispatch(new GetItemAction { itemId = 1 });
}
)
);
var widget = new Column(
children: new List<Widget> {
// 畫面溢出時直接報錯, 限制一下高度
new Container(
child: showList,
height: 400
),
btn,
}
);
return widget;
}
使用三個道具, 獲得三個木棍, 沒什么問題
之后就需要討論ListItem更復雜化\動效\效率優化\代碼重構等等問題了, 和這次的主題沒有關系