Unity - 在运行时以编程方式创建 UI 列表
Unity - Creating a UI list at runtime programmatically
我有一个场景,我应该能够从项目列表中 select 一个 3D 模型,然后将其加载到下一个场景中。我想根据已存储在本地数据库中的内容,以编程方式生成项目列表。但是我在获取要在场景中显示的项目列表时遇到问题...
所以我有一个 class 的项目:
[System.Serializable] public class Item {
public string ObjectGuid;
public string Name;
public string Description;
public Sprite Icon;
public Button.ButtonClickedEvent SelectObject;
}
我的场景脚本,其中包含项目列表和我调用以从数据库加载对象的方法:
public class ObjectSelectionScript : MonoBehaviour {
public List<Item> itemList;
public Transform contentPanel;
void LoadObjects() {
StreamReader str = new StreamReader (Application.persistentDataPath + "/" + DataManager.LOCATION_XML_PATH);
string result = str.ReadToEnd ();
str.Close();
var jo = SimpleJSON.JSON.Parse (result);
if (jo ["Objects"] != null) {
for (int i = 0; i < jo["Objects"].Count; i++) {
if (!string.IsNullOrEmpty(jo["Objects"][i]["FileGuid"])) {
Item newObject = new Item();
newObject.ObjectGuid = jo["Objects"][i]["ObjectGuid"];
newObject.Name = jo["Objects"][i]["Name"];
newObject.Description = jo["Objects"][i]["Description"];
//newObject.SelectObject = new Button.ButtonClickedEvent();
itemList.Add(newObject);
}
}
}
}
一个模型对象class:
public class ModelObject : MonoBehaviour {
public Button button;
public Text Name;
public Text Description;
public Image Icon;
}
还有一个包含名称、描述和缩略图的预制件 ModelObjectPrefab,已添加到我的资产文件夹中。
PopulateList() 方法是我的问题。我无法实例化预制件,然后创建可以放入界面中的 contentPanel 的 ModelObjects。这是我的代码:
void PopulateList()
{
try {
foreach (var item in itemList)
{
GameObject newModel = Instantiate(ModelObject) as GameObject;
ModelObject myModelObject = newModel.GetComponent<ModelObject>();
myModelObject.Name.text = item.Name;
myModelObject.Description.text = item.IDescription;
myModelObject.icon.sprite = item.Icon;
myModelObject.button.onClick = item.selectObject;
newModel.transform.SetParent(contentPanel);
}
} catch (System.Exception ex) {
}
}
我目前在实例化时得到空指针。我尝试了 Resources.Load 和 Instatiate 方法的变体,但我没有找到解决方案。
谁能告诉我问题出在哪里? PopulateList() 应该如何将项目获取到界面?
请注意,Instantiate()
方法不应将类型(例如 ModelObject
)作为参数。相反,您应该向它传递一个对象实例(在本例中,您的预制件 GameObject
"ModelObjectPrefab")。该文档明确指出它需要:
An existing object that you want to make a copy of
否则,您可能会遇到这样的意外行为。在您的代码中,我们需要传递对 "ModelObjectPrefab" 的引用作为 Instantiate()
调用的参数。我建议将包含 PopulateList()
的 class 修改为:
// New variable to hold prefab object
public GameObject modelObjectPrefab;
// ...
void PopulateList()
{
try {
foreach (var item in itemList)
{
// Reference prefab variable instead of class type
GameObject newModel = Instantiate(modelObjectPrefab) as GameObject;
ModelObject myModelObject = newModel.GetComponent<ModelObject>();
myModelObject.Name.text = item.Name;
myModelObject.Description.text = item.IDescription;
myModelObject.icon.sprite = item.Icon;
myModelObject.button.onClick = item.selectObject;
newModel.transform.SetParent(contentPanel);
}
} catch (System.Exception ex) {
}
}
然后,在编辑器 window 中,将您的预制件 "ModelObjectPrefab" 从资产面板拖到脚本属性中新的 Model Object Prefab
字段中,以形成脚本和预制件。
希望对您有所帮助!如果您有任何问题,请告诉我。
读者注意。 "GUI" 在 Unity 中不再可用。只需使用新的 UI 系统。示例 http://www.folio3.com/blog/creating-dynamic-scrollable-lists-with-new-unity-canvas-ui/
唯一可行的是通过编程方式创建整个 GUI。
我创建了一个 GUI.matrix
并在其中添加了所有内容。它看起来不太好,所以我花了很多时间试图让它看起来更好并在移动设备上响应,但最后这是唯一有效的解决方案。
作为可能遇到相同问题的人的快速参考,解决方案具有以下结构:
public void OnGUI ()
{
var savedMatrix = GUI.matrix;
scrollPosition = GUI.BeginScrollView (new Rect (10f, 10f, Screen.width - 10f, Screen.height - 10f), scrollPosition, new Rect (10f, 10f, Screen.width - 10f, (_files.Count + 2) * 200f));
if (Input.touchCount == 1) {
Vector2 touchDelta2 = Input.GetTouch (0).deltaPosition;
scrollPosition.y += touchDelta2.y;
}
var selected = GUILayout.SelectionGrid (gridInt, _files.ToArray (), 1, MyStyle);
if (selected >= 0) {
if (selected == 0) {
if (selectedItem != null )
if (selectedItem.Parent != null)
selectedItem = selectedItem.Parent;
else
selectedItem = null;
} else {
SelectFolder (selected);
}
RefreshViewModel ();
}
GUI.EndScrollView ();
GUI.matrix = savedMatrix;
}
我有一个场景,我应该能够从项目列表中 select 一个 3D 模型,然后将其加载到下一个场景中。我想根据已存储在本地数据库中的内容,以编程方式生成项目列表。但是我在获取要在场景中显示的项目列表时遇到问题...
所以我有一个 class 的项目:
[System.Serializable] public class Item {
public string ObjectGuid;
public string Name;
public string Description;
public Sprite Icon;
public Button.ButtonClickedEvent SelectObject;
}
我的场景脚本,其中包含项目列表和我调用以从数据库加载对象的方法:
public class ObjectSelectionScript : MonoBehaviour {
public List<Item> itemList;
public Transform contentPanel;
void LoadObjects() {
StreamReader str = new StreamReader (Application.persistentDataPath + "/" + DataManager.LOCATION_XML_PATH);
string result = str.ReadToEnd ();
str.Close();
var jo = SimpleJSON.JSON.Parse (result);
if (jo ["Objects"] != null) {
for (int i = 0; i < jo["Objects"].Count; i++) {
if (!string.IsNullOrEmpty(jo["Objects"][i]["FileGuid"])) {
Item newObject = new Item();
newObject.ObjectGuid = jo["Objects"][i]["ObjectGuid"];
newObject.Name = jo["Objects"][i]["Name"];
newObject.Description = jo["Objects"][i]["Description"];
//newObject.SelectObject = new Button.ButtonClickedEvent();
itemList.Add(newObject);
}
}
}
}
一个模型对象class:
public class ModelObject : MonoBehaviour {
public Button button;
public Text Name;
public Text Description;
public Image Icon;
}
还有一个包含名称、描述和缩略图的预制件 ModelObjectPrefab,已添加到我的资产文件夹中。
PopulateList() 方法是我的问题。我无法实例化预制件,然后创建可以放入界面中的 contentPanel 的 ModelObjects。这是我的代码:
void PopulateList()
{
try {
foreach (var item in itemList)
{
GameObject newModel = Instantiate(ModelObject) as GameObject;
ModelObject myModelObject = newModel.GetComponent<ModelObject>();
myModelObject.Name.text = item.Name;
myModelObject.Description.text = item.IDescription;
myModelObject.icon.sprite = item.Icon;
myModelObject.button.onClick = item.selectObject;
newModel.transform.SetParent(contentPanel);
}
} catch (System.Exception ex) {
}
}
我目前在实例化时得到空指针。我尝试了 Resources.Load 和 Instatiate 方法的变体,但我没有找到解决方案。
谁能告诉我问题出在哪里? PopulateList() 应该如何将项目获取到界面?
请注意,Instantiate()
方法不应将类型(例如 ModelObject
)作为参数。相反,您应该向它传递一个对象实例(在本例中,您的预制件 GameObject
"ModelObjectPrefab")。该文档明确指出它需要:
An existing object that you want to make a copy of
否则,您可能会遇到这样的意外行为。在您的代码中,我们需要传递对 "ModelObjectPrefab" 的引用作为 Instantiate()
调用的参数。我建议将包含 PopulateList()
的 class 修改为:
// New variable to hold prefab object
public GameObject modelObjectPrefab;
// ...
void PopulateList()
{
try {
foreach (var item in itemList)
{
// Reference prefab variable instead of class type
GameObject newModel = Instantiate(modelObjectPrefab) as GameObject;
ModelObject myModelObject = newModel.GetComponent<ModelObject>();
myModelObject.Name.text = item.Name;
myModelObject.Description.text = item.IDescription;
myModelObject.icon.sprite = item.Icon;
myModelObject.button.onClick = item.selectObject;
newModel.transform.SetParent(contentPanel);
}
} catch (System.Exception ex) {
}
}
然后,在编辑器 window 中,将您的预制件 "ModelObjectPrefab" 从资产面板拖到脚本属性中新的 Model Object Prefab
字段中,以形成脚本和预制件。
希望对您有所帮助!如果您有任何问题,请告诉我。
读者注意。 "GUI" 在 Unity 中不再可用。只需使用新的 UI 系统。示例 http://www.folio3.com/blog/creating-dynamic-scrollable-lists-with-new-unity-canvas-ui/
唯一可行的是通过编程方式创建整个 GUI。
我创建了一个 GUI.matrix
并在其中添加了所有内容。它看起来不太好,所以我花了很多时间试图让它看起来更好并在移动设备上响应,但最后这是唯一有效的解决方案。
作为可能遇到相同问题的人的快速参考,解决方案具有以下结构:
public void OnGUI ()
{
var savedMatrix = GUI.matrix;
scrollPosition = GUI.BeginScrollView (new Rect (10f, 10f, Screen.width - 10f, Screen.height - 10f), scrollPosition, new Rect (10f, 10f, Screen.width - 10f, (_files.Count + 2) * 200f));
if (Input.touchCount == 1) {
Vector2 touchDelta2 = Input.GetTouch (0).deltaPosition;
scrollPosition.y += touchDelta2.y;
}
var selected = GUILayout.SelectionGrid (gridInt, _files.ToArray (), 1, MyStyle);
if (selected >= 0) {
if (selected == 0) {
if (selectedItem != null )
if (selectedItem.Parent != null)
selectedItem = selectedItem.Parent;
else
selectedItem = null;
} else {
SelectFolder (selected);
}
RefreshViewModel ();
}
GUI.EndScrollView ();
GUI.matrix = savedMatrix;
}