Version: Unity 6.0 (6000.0)
언어 : 한국어
복합 리스트 뷰 생성
스크롤 뷰 안에 콘텐츠 래핑

리스트 뷰 런타임 UI 생성

버전: 2022.3+

이 예시에서는 리스트 뷰 런타임 UI를 생성하는 방법을 보여 줍니다. 이 예시에서는 UXML 및 USS 파일을 직접 사용하여 UI의 구조와 스타일을 생성합니다. UI 툴킷을 처음 사용하고__ UI__(사용자 인터페이스) 사용자가 애플리케이션과 상호 작용하도록 해 줍니다. Unity는 현재 3개의 UI 시스템을 지원합니다. 자세한 정보
See in Glossary
빌더를 사용하여 UI를 생성하려는 경우 UI 빌더로 예시 UI 생성을 참조하십시오.

개요 예시

이 예시에서는 간단한 캐릭터 선택 화면을 생성합니다. 왼쪽에 있는 리스트에서 캐릭터 이름을 클릭하면 캐릭터의 세부 정보가 오른쪽에 표시됩니다.

최종 런타임 UI 뷰
최종 런타임 UI 뷰

이 예시에서 만든 완성된 파일은 이 GitHub 저장소에서 찾을 수 있습니다.

선행 조건

이 가이드는 Unity 에디터, UI 툴킷, C# 스크립팅에 익숙한 개발자를 위한 가이드입니다. 시작하기 전에 먼저 다음을 숙지하십시오.

메인 UI 문서 생성

메인 뷰 UI 문서와 USS 파일을 생성하여 시각적 요소의 스타일을 지정합니다. UI 문서에서 두 개의 시각적 요소를 컨테이너로 추가합니다. 하나는 캐릭터 이름의 리스트를 포함하는 컨테이너이고 다른 하나는 선택한 캐릭터의 세부 정보를 포함하는 컨테이너입니다.

메인 뷰의 UI 레이아웃 설정
메인 뷰의 UI 레이아웃 설정
  1. 템플릿을 사용하여 Unity에서 프로젝트를 생성합니다.

  2. 프로젝트 창에서 UI라는 폴더를 생성하여 모든 UI 문서와 스타일시트 파일을 저장합니다.

  3. UI 폴더에 다음 콘텐츠가 포함된 MainView.uxml이라는 UI 문서를 생성합니다.

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
        <Style src="MainView.uss" />
        <ui:VisualElement name="background">
            <ui:VisualElement name="main-container">
                <ui:ListView focusable="true" name="character-list" />
                <ui:VisualElement name="right-container">
                    <ui:VisualElement name="details-container">
                        <ui:VisualElement name="details">
                            <ui:VisualElement name="character-portrait" />
                        </ui:VisualElement>
                        <ui:Label text="Label" name="character-name" />
                        <ui:Label text="Label" display-tooltip-when-elided="true" name="character-class" />
                    </ui:VisualElement>
                </ui:VisualElement>
            </ui:VisualElement>
        </ui:VisualElement>
    </ui:UXML>
    
  4. UI 폴더에 다음 콘텐츠가 포함된 MainView.uss라는 USS 스타일시트를 생성합니다.

#background {
    flex-grow: 1;
    align-items: center;
    justify-content: center;
    background-color: rgb(115, 37, 38);
}

#main-container {
    flex-direction: row;
    height: 350px;
}

#character-list {
    width: 230px;
    border-color: rgb(49, 26, 17);
    border-width: 4px;
    background-color: rgb(110, 57, 37);
    border-radius: 15px;
    margin-right: 6px;
}

#character-name {
    -unity-font-style: bold;
    font-size: 18px;
}

#character-class {
    margin-top: 2px;
    margin-bottom: 8px;
    padding-top: 0;
    padding-bottom: 0;
}

#right-container {
    justify-content: space-between; 
    align-items: flex-end;
}

#details-container {
    align-items: center; 
    background-color: rgb(170, 89, 57); 
    border-width: 4px; 
    border-color: rgb(49, 26, 17);
    border-radius: 15px;
    width: 252px; 
    justify-content: center; 
    padding: 8px;
    height: 163px;
}

#details {
    border-color: rgb(49, 26, 17); 
    border-width: 2px; 
    height: 120px; 
    width: 120px; 
    border-radius: 13px; 
    padding: 4px;
    background-color: rgb(255, 133, 84);
}

#character-portrait {
    flex-grow: 1; 
    -unity-background-scale-mode: scale-to-fit;
}

.unity-collection-view__item {
    justify-content: center;
}

리스트 엔트리 UI 문서 생성

리스트의 개별 엔트리에 대한 UI 문서와 스타일시트를 생성합니다. 캐릭터 리스트 엔트리는 컬러가 지정된 배경 프레임과 캐릭터 이름으로 구성됩니다.

캐릭터의 이름이 표시되는 리스트 엔트리
캐릭터의 이름이 표시되는 리스트 엔트리
  1. UI 폴더에 다음 콘텐츠가 포함된 ListEntry.uxml이라는 UI 문서를 생성합니다.

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <Style src="ListEntry.uss" />
    <ui:VisualElement name="list-entry">
        <ui:Label text="Label" display-tooltip-when-elided="true" name="character-name" />
    </ui:VisualElement>
    </ui:UXML>
    
  2. UI 폴더에 다음 콘텐츠가 포함된 ListEntry.uss라는 스타일시트 파일을 생성합니다.

#list-entry {
    height: 41px;
    align-items: flex-start;
    justify-content: center;
    padding-left: 10px;
    background-color: rgb(170, 89, 57);
    border-color: rgb(49, 26, 17);
    border-width: 2px;
    border-radius: 15px;
}

#character-name {
    -unity-font-style: bold;
    font-size: 18px;
    color: rgb(49, 26, 17);
}

표시할 샘플 데이터 만들기

UI에 캐릭터 리스트를 채울 샘플 데이터를 생성합니다. 캐릭터 리스트의 경우 캐릭터 이름, 클래스, 세로 이미지가 포함된 클래스를 생성합니다.

  1. Asset 폴더에 Scripts라는 폴더를 만들어 C# 스크립트를 저장합니다.

  2. Scripts 폴더에 다음 내용을 포함하는 CharacterData.cs라는 C# 스크립트를 생성합니다.

    using UnityEngine;
        
    public enum ECharacterClass
    {
        Knight, Ranger, Wizard
    }
        
    [CreateAssetMenu]
    public class CharacterData : ScriptableObject
    {
        public string CharacterName;
        public ECharacterClass Class;
        public Sprite PortraitImage;
    }
    
  3. Assets 폴더에 Resources라는 폴더를 만듭니다.

  4. Resources 폴더에 Characters라는 폴더를 만들어 모든 샘플 캐릭터 데이터를 저장합니다.

  5. Characters 폴더에서 오른쪽 클릭하고 Create > Character Data를 선택하여 ScriptableObject의 인스턴스를 생성합니다.

  6. CharacterData 인스턴스를 더 생성하고 플레이스홀더 데이터로 채웁니다.

씬 설정

SampleScene에서 UIDocument 게임 오브젝트를 생성하고 UI 문서를 소스 에셋으로 추가합니다.

  1. SampleScene에서 GameObject > UI Toolkit > UI Document를 선택합니다.
  2. 계층 창에서 UIDocument 게임 오브젝트를 선택합니다.
  3. 프로젝트 창의 MainView.uxml을 인스펙터 창에 있는 UI Document 컴포넌트의 Source Asset 필드로 드래그합니다. 이렇게 하면 소스 에셋을 UXML 파일로 참조합니다.

리스트 엔트리 및 메인 뷰의 컨트롤러 생성

다음 클래스를 포함한 두 개의 C# 스크립트를 생성합니다.

  • 리스트 엔트리의 UI에 캐릭터 인스턴스의 데이터를 표시하는 CharacterListEntryController 클래스. 캐릭터 이름의 레이블에 액세스하고 특정 캐릭터 인스턴스의 이름을 표시하도록 설정해야 합니다.
  • 메인 뷰의 캐릭터 리스트를 위한 CharacterListController 클래스와 인스턴스화하고 시각적 트리에 할당하는 MonoBehaviour 스크립트.

참고: CharacterListEntryController 클래스는 MonoBehaviour가 아닙니다. UI 툴킷의 시각적 요소는 게임 오브젝트가 아니므로 컴포넌트를 연결할 수 없습니다. 대신 CharacterListController 클래스의 userData 프로퍼티에 클래스를 연결합니다.

  1. Scripts 폴더에 다음 콘텐츠를 포함하는 CharacterListEntryController.cs라는 C# 스크립트를 생성합니다.

    using UnityEngine.UIElements;
        
    public class CharacterListEntryController
    {
        Label m_NameLabel;
        
        // This function retrieves a reference to the 
        // character name label inside the UI element.
        public void SetVisualElement(VisualElement visualElement)
        {
            m_NameLabel = visualElement.Q<Label>("character-name");
        }
        
        // This function receives the character whose name this list 
        // element is supposed to display. Since the elements list 
        // in a `ListView` are pooled and reused, it's necessary to 
        // have a `Set` function to change which character's data to display.
        public void SetCharacterData(CharacterData characterData)
        {
            m_NameLabel.text = characterData.CharacterName;
        }
    }
    
  2. Scripts 폴더에 다음 내용을 포함하는 CharacterListController.cs라는 C# 스크립트를 생성합니다.

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UIElements;
        
    public class CharacterListController
    {
        // UXML template for list entries
        VisualTreeAsset m_ListEntryTemplate;
        
        // UI element references
        ListView m_CharacterList;
        Label m_CharClassLabel;
        Label m_CharNameLabel;
        VisualElement m_CharPortrait;
        
        List<CharacterData> m_AllCharacters;
        
        public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
        {
            EnumerateAllCharacters();
        
            // Store a reference to the template for the list entries
            m_ListEntryTemplate = listElementTemplate;
        
            // Store a reference to the character list element
            m_CharacterList = root.Q<ListView>("character-list");
        
            // Store references to the selected character info elements
            m_CharClassLabel = root.Q<Label>("character-class");
            m_CharNameLabel = root.Q<Label>("character-name");
            m_CharPortrait = root.Q<VisualElement>("character-portrait");
        
            FillCharacterList();
        
            // Register to get a callback when an item is selected
            m_CharacterList.selectionChanged += OnCharacterSelected;
        }
        
        void EnumerateAllCharacters()
        {
            m_AllCharacters = new List<CharacterData>();
            m_AllCharacters.AddRange(Resources.LoadAll<CharacterData>("Characters"));
        }
        
        void FillCharacterList()
        {
            // Set up a make item function for a list entry
            m_CharacterList.makeItem = () =>
            {
                // Instantiate the UXML template for the entry
                var newListEntry = m_ListEntryTemplate.Instantiate();
        
                // Instantiate a controller for the data
                var newListEntryLogic = new CharacterListEntryController();
        
                // Assign the controller script to the visual element
                newListEntry.userData = newListEntryLogic;
        
                // Initialize the controller script
                newListEntryLogic.SetVisualElement(newListEntry);
        
                // Return the root of the instantiated visual tree
                return newListEntry;
            };
        
            // Set up bind function for a specific list entry
            m_CharacterList.bindItem = (item, index) =>
            {
                (item.userData as CharacterListEntryController)?.SetCharacterData(m_AllCharacters[index]);
            };
        
            // Set a fixed item height matching the height of the item provided in makeItem. 
            // For dynamic height, see the virtualizationMethod property.
            m_CharacterList.fixedItemHeight = 45;
        
            // Set the actual item's source list/array
            m_CharacterList.itemsSource = m_AllCharacters;
        }
        
        void OnCharacterSelected(IEnumerable<object> selectedItems)
        {
            // Get the currently selected item directly from the ListView
            var selectedCharacter = m_CharacterList.selectedItem as CharacterData;
        
            // Handle none-selection (Escape to deselect everything)
            if (selectedCharacter == null)
            {
                // Clear
                m_CharClassLabel.text = "";
                m_CharNameLabel.text = "";
                m_CharPortrait.style.backgroundImage = null;
        
                return;
            }
        
            // Fill in character details
            m_CharClassLabel.text = selectedCharacter.Class.ToString();
            m_CharNameLabel.text = selectedCharacter.CharacterName;
            m_CharPortrait.style.backgroundImage = new StyleBackground(selectedCharacter.PortraitImage);
        }
    }
    

메인 뷰에 컨트롤러 스크립트 연결

CharacterListControllerMonoBehaviour가 아니므로 게임 오브젝트에 직접 연결할 수 없습니다. 이 문제를 해결하려면 MonoBehaviour 스크립트를 생성하고 UIDocument와 동일한 게임 오브젝트에 연결합니다. 이 스크립트에서는 UIDocument 컴포넌트에 의해 이미 인스턴스화되어 있기 때문에 MainView.uxml을 인스턴스화할 필요가 없습니다. 대신 UIDocument 컴포넌트에 액세스하여 이미 인스턴스화된 시각적 트리의 레퍼런스를 가져옵니다. 그런 다음 CharacterListController의 인스턴스를 생성하고 시각적 트리의 루트 요소와 개별 리스트 요소에 사용되는 UXML 템플릿을 전달합니다.

참고: UI가 리로드되면 UIDocument 컴포넌트가 포함된 동일한 게임 오브젝트의 연결된 모든 MonoBehaviour 컴포넌트가 리로드 전에 비활성화되고 리로드 후 다시 활성화됩니다. 따라서 UI 관련 코드를 이 MonoBehaviourOnEnableOnDisable 메서드에 배치해야 합니다. 자세한 내용은 게임 뷰에서 UI 렌더링을 참조하십시오.

  1. Scripts 폴더에 다음 내용을 포함하는 MainView.cs라는 C# 스크립트를 생성합니다.

    using UnityEngine;
    using UnityEngine.UIElements;
        
    public class MainView : MonoBehaviour
    {
        [SerializeField]
        VisualTreeAsset m_ListEntryTemplate;
        
        void OnEnable()
        {
            // The UXML is already instantiated by the UIDocument component
            var uiDocument = GetComponent<UIDocument>();
        
            // Initialize the character list controller
            var characterListController = new CharacterListController();
            characterListController.InitializeCharacterList(uiDocument.rootVisualElement, m_ListEntryTemplate);
        }
    }
    
  2. SampleScene에서 UIDocument를 선택합니다.

  3. MainView.cs를 인스펙터 창의 Add Component로 드래그합니다.

  4. ListEntry.uxmlListEntry Template 필드로 드래그합니다.

  5. 플레이 모드로 전환하여 게임 뷰에 표시되는 UI를 확인합니다.

추가 리소스

복합 리스트 뷰 생성
스크롤 뷰 안에 콘텐츠 래핑