본문으로 건너뛰기

© 2026 Molayo

YouTube요약2026. 06. 15. 09:40

UI Toolkit 런타임 데이터 바인딩 (Data Binding): 동적 데이터

요약

Unity의 UI Toolkit을 사용하여 런타임 시점에 동적으로 데이터를 바인딩하는 방법을 설명합니다. ScriptableObject를 활용해 정적 바인딩을 넘어 실제 게임플레이 데이터와 UI를 연결하는 컨트롤러 구현 워크플로를 다룹니다.

핵심 포인트

  • 런타임 시점에 실제 게임플레이 데이터와 UI를 연결하는 동적 바인딩 구현
  • C# 컨트롤러 스크립트를 통한 데이터 소스 할당 및 바인딩 설정 방법
  • ScriptableObject를 템플릿으로 사용하여 런타임 인스턴스 생성 및 관리
  • SetBinding 구문을 활용한 UI 요소와 데이터 경로 간의 관계 정의

비디오: UI Toolkit 런타임 데이터 바인딩 (Data Binding): 동적 데이터
채널: Unity
길이: 13분 20초
출처: 자막 (수동, en-US)

지난 비디오에서는 UI Builder를 사용하여 단일 데이터 객체를 바인딩했습니다. 이제 동일한 UI를 런타임 (runtime) 시점의 실제 데이터에 연결해 보겠습니다. 컨트롤러 (controller) 스크립트를 만들고 C#에서 바인딩을 다시 구현한 다음, 워크플로 (workflow)를 단순화하는 방법을 보여드리겠습니다.

그전에, 이전 예제에서 바인딩을 제거했습니다. 따라서 이것은 데이터 바인딩 (data binding)이 없는 동일한 UXML입니다. 시작 메뉴에서 이전 바인딩을 제거하고 데이터 소스 (data source) 객체를 완전히 해제할 수도 있습니다. 우리는 이 모든 동일한 바인딩을 C#에서 다시 구축할 것입니다.

첫 번째 파트에서는 플레이어 이름(player name) 및 현재 체력(current health) 레이블과 같은 UI 요소들을 연결했습니다. 바인딩을 설정하고 데이터 객체를 할당하면 UI가 자동으로 업데이트되었습니다. 하지만 그 설정은 정적 (static)이었습니다. UI는 항상 디스크에 있는 하나의 Scriptable Object 에셋을 가리켰습니다. 실제 게임에서는 게임플레이 데이터가 변경됩니다. 우리는 런타임에 데이터를 할당하고 교체할 수 있는 방법이 필요합니다.

이를 달성하기 위해, 데이터 바인딩 시스템과 함께 작동하는 작은 컨트롤러 스크립트를 사용할 것입니다. 이 컨트롤러를 실제로 작업하기 전에, 플레이어 데이터를 업데이트해야 합니다. 이전에는 UI가 데이터로부터 읽기만 했습니다. 이제 런타임에 이를 수정해야 합니다. CurrentHealth에는 세터 (setter)가 필요합니다. 따라서 값을 설정하고 값을 제한(clamp)하는 메서드를 노출합니다. 이렇게 하면 값이 항상 범위 내에 머물게 됩니다. 이제 단순히 읽는 것이 아니라 런타임에 해당 값을 변경할 수 있습니다. 또한 체력을 증가시키거나 감소시키는 헬퍼 메서드 (helper methods)도 준비했습니다. 게임플레이 시스템은 플레이어에게 피해를 주거나 체력을 회복시키기 위해 이 메서드들을 호출할 수 있습니다.

우리는 이 메서드들을 사용하여 현재 체력 속성 (property)을 업데이트하고 런타임에서 바인딩을 테스트할 것입니다. 우리는 간단한 컨트롤러 스크립트로 데이터 바인딩을 관리할 것입니다. 여기 있는 것은 체력 바 컨트롤러 (health bar controller)입니다. 이것은 프레젠터 (presenter)가 아닙니다. UI에 값을 밀어넣는 방식이 아닙니다. 데이터 바인딩 시스템과 함께 작동합니다. UI 문서 (UI document)로부터 참조를 가져오고, 바인딩을 설정하며, 데이터 소스를 할당합니다.

먼저 바인딩하고자 하는 요소들을 찾기 위해 XML을 쿼리(querying)하는 것부터 시작하겠습니다. 우선 현재 체력 레이블(health label)에 하나의 바인딩을 설정해 보겠습니다. 그런 다음 다음과 같이 SetBinding 구문을 사용하여 바인딩 자체를 정의합니다. Text는 대상 속성(target property)인 첫 번째 매개변수입니다. 그리고 두 번째 매개변수로 새로운 데이터 바인딩 객체(data binding object)를 생성합니다. 이는 일종의 관계를 설명합니다. 데이터 객체를 가져오면, 현재 체력 데이터 경로(health data path)에 있는 값을 읽어와서 해당 값을 text 속성에 할당하게 됩니다. 이 시점에서는 데이터 소스(data source)가 없기 때문에 아무 일도 일어나지 않습니다. 그래서 런타임 인스턴스(runtime instance)를 생성합니다. 파트 1에서는 ScriptableObject 에셋을 직접 사용했습니다. 하지만 런타임 중에 그것을 수정하고 싶지는 않습니다. 대신, 직렬화된 플레이어 데이터(serialized player data)를 템플릿으로 사용할 수 있습니다. 이를 인스펙터(Inspector)에 드래그하여 초기 값을 정의한 다음, 런타임에 복사본을 생성합니다. 이렇게 하면 안전하게 수정할 수 있는 새로운 인스턴스를 얻을 수 있습니다. 인스턴스가 준비되면 데이터 소스를 할당할 수 있습니다. VisualElement.dataSource = playerData와 같이 설정합니다. 그러면 UI Toolkit은 해당 객체를 기준으로 모든 바인딩을 해결(resolve)합니다. 또한 이번 데모를 위해 런타임 인스턴스를 속성(property)으로 노출하겠습니다. 이를 통해 다른 스크립트가 데이터를 수정하고 실제 프로젝트에서 바인딩을 테스트할 수 있습니다. 이는 단순히 여러분의 게임플레이 시스템이나 체력 매니저(health manager)로부터 전달될 것입니다. 현재 우리는 하나의 활성화된 바인딩을 가지고 있습니다. 이것을 저장한 다음 체력 바(health bar) 게임 오브젝트(GameObject)에 부착합니다. 인스펙터에서 UI 문서(UI document)와 ScriptableObject 템플릿을 할당하기만 하면 됩니다. 우리는 런타임 인스턴스를 사용하고 있으므로, 원래의 ScriptableObject를 직접 편집할 수는 없습니다. 대신 작은 테스터 스크립트를 사용하여 런타임 데이터를 수정할 것이며, 이는 게임플레이 시스템이 플레이어의 체력을 어떻게 변경하는지를 시뮬레이션할 것입니다. 이 테스터는 하단의 플러스(+) 및 마이너스(-) 버튼을 연결합니다. 런타임 시, 이 버튼들은 플레이어 데이터 인스턴스의 incrementHealthdecrementHealth를 호출합니다. 버튼을 누를 때 플레이 모드(play mode)에서 체력 바 컨트롤러(health bar controller)와 VisualElement ID에 대한 참조를 제공하기만 하면 됩니다.

우리는 런타임 (runtime) 중에 데이터를 수정하고 있으며,
UI는 자동으로 업데이트됩니다.
우리가 수정하고 있는 것은 UI가 아니라
데이터라는 점을 기억하세요.
레이블 (label)은 런타임 플레이어 데이터의
현재 체력에 바인딩 (bound)되어 있으므로,
스스로 업데이트됩니다.
이제 컨트롤러 (controller)로 돌아가서
나머지 바인딩 (bindings)을 추가할 수 있습니다.
단순한 경우에는,
동일한 SetBinding 패턴을 반복합니다.
이 속성들은 익숙해 보일 것입니다.
첫 번째 파트에서 XML에 설정했던 것과 일치합니다.
컨버터 그룹 (converter groups)을 사용할 때는,
구문이 더 복잡해집니다.
먼저 바인딩을 생성합니다.
참조를 유지하세요.
실제 컨버터 그룹을 적용한 다음,
그제서야 SetBinding을 호출합니다.
이것은 데이터 바인딩을 설정하는
완벽하게 유효한 방법이며,
런타임에 바인딩을 생성해야 할 때
때로는 필수적입니다.
이를 실행하면, C#에서 전체 체력 바
데이터 바인딩을 다시 구축한 것이 됩니다.
체력이 변하면,
UI가 올바르게 업데이트됩니다.
하지만 여기서 문제는 규모 (scale)입니다.
각 요소는 바인딩을 생성하는 것과 비교했을 때,
자신만의 PropertyPath
때로는 컨버터 설정이 필요합니다.
새로운 XML입니다.
이 버전은 더 장황하며 (verbose),
UI Builder의 대화형 워크플로 (interactive workflow)도
가지고 있지 않습니다.
따라서 우리는 하이브리드 접근 방식 (hybrid approach)을 사용할 수 있습니다.
UI Toolkit은
USS나 XML에서 바인딩을 정의할 수 있게 해줍니다.
하지만 특정 객체를 할당하는 대신,
데이터 소스 유형 (data source type)을 설정하고,
'Select Type'을 클릭한 뒤,
이름이나 네임스페이스 (namespace)로 필터링하여
Player Data ScriptableObject를 선택합니다.
이렇게 하면 실제 인스턴스를 아직 할당하지 않고도,
UI에 어떤 종류의 데이터를 기대할지
알려주게 됩니다.
그런 다음 첫 번째 파트에서 했던 것과
정확히 동일하게 바인딩을 설정합니다.
바인딩을 생성할 때,
'type' 옵션을 선택하면
바인딩이 XML에 존재하게 되지만,
런타임 전까지는 해결 (resolve)되지 않습니다.
UI Builder에서 보면,
바인딩 아이콘이 비어 있고
이전처럼 화면에 데이터가 채워지지 않는 것을
알 수 있을 것입니다.
데이터 바인딩이 아직 완전히 해결되지 않았다는 뜻이며,
이는 다른 무언가, 이 경우에는 컨트롤러가
런타임에 실제 데이터를 제공할 것임을 의미합니다.

그런 다음 바인딩이 필요한 UI의 모든 부분,
예를 들어 현재 체력(current health), 최대 체력(max health), 진행 바(progress bar)의 색상 등을 살펴볼 것입니다.
이전과 정확히 동일하게 바인딩을 설정할 수 있지만,
이번에는 데이터 소스(data source) 유형을 사용합니다.
모든 동일한 속성들이
dataSourcePath에서 사용 가능할 것입니다.
필요하다면 동일한 컨버터 (converters)를 적용하십시오.
여기서 모든 바인딩을 다시 적용하고 UXML을 적용하면,
바인딩이 완전히 정의되지만
여전히 실제 데이터를 기다리는 상태가 됩니다.
아직 아무것도 연결되지 않았습니다.
그것은 오직 런타임 (runtime)에만 발생합니다.
다시 컨트롤러 (controller)로 돌아가면,
스크립트가 훨씬 단순해집니다.
우리는 더 이상
C#에서 바인딩을 생성하지 않습니다.
그것들은 이미 UXML에 정의되어 있습니다.
따라서 이 하이브리드 워크플로 (hybrid workflow)에서는
이 모든 코드를 제거할 수 있습니다.
바인딩은 대화형으로 설정할 수 있으며
컨트롤러는 단순히 데이터만 제공합니다.
컨트롤러가 실제로 하는 일은 이것뿐입니다:
루트 (root)의 데이터 소스를
플레이어 데이터 (player data)로 설정하는 것이며, 이것만으로
UI의 모든 바인딩을 활성화하기에 충분합니다.
컨트롤러 스크립트는 매우 최소화되어 있으며,
필요할 때 헬퍼 (helpers)를 사용하여 확장할 수 있습니다.
예를 들어, 런타임에 데이터 소스를 교체하는
메서드를 만들고 싶을 수도 있습니다.
다음과 같이 할 수 있습니다.
이 하이브리드 접근 방식은
책임을 분리합니다.
바인딩은 UXML에서 작성되고,
컨트롤러는 런타임에 데이터를 공급합니다.
플레이 모드 (play mode)에서, 우리는 체력 바의
동작을 복구했습니다.
체력이 변하면 UI가 즉시 업데이트되며,
모든 것이 이전과 동일하게 작동합니다.
이것은 세 가지 접근 방식을 다룹니다:
데이터 바인딩 UXML,
UI Builder와 스택 데이터 (stack data)를 사용하는 C# API,
그리고 컨트롤러 스크립트를 사용하는 방식,
그리고 이 세 가지를 모두 결합한
이 하이브리드 워크플로입니다. 이 세 가지 모두 동일한 결과를 얻습니다.
데이터를 업데이트하면 UI가 동기화된 상태를 유지합니다.
지금까지
우리의 바인딩은 자동으로 업데이트되었습니다.
하지만 UI가 커짐에 따라, 바인딩이 언제 새로고침될지,
그리고 모든 것을 동기화하기 위해 시스템이 얼마나 많은 작업을 수행할지에 대해
더 많은 제어권을 원할 수도 있습니다.
UI Toolkit은 이미 업데이트 사이클 (update cycle) 동안
데이터를 확인하지만,
버전 관리 (versioning)와 변경 추적 (change tracking)을 통해
그 프로세스를 더 효율적으로 만들 수 있습니다.

목표는 간단합니다.
먼저 빠르고 비용이 적게 드는 확인을 수행하고,
실제로 무언가가 변경되었을 때만
UI를 새로고침하는 것입니다.
우리는 이를 데이터 모델 (data model)에 구현할 것이므로,
ScriptableObject를 열고
방해되는 코드들을 접어두겠습니다.
그 다음, 체력 바 (health bar)를 구동하는
현재 체력 (current health)에 집중해 보겠습니다.
먼저,
데이터 소스 뷰 프로바이더 (data source view provider)를 추가합니다.
이 인터페이스는
get view hashCode 메서드를 요구합니다.
우리는 이를 단순한 버전 번호 (version number)와 뷰 버전 (view version)으로 구현하여
get view hashCode에서 반환하겠습니다.
이것이 즉시 UI를 업데이트하지는 않습니다.
대신, 바인딩 시스템 (binding system)에
가벼운 버전 정보를 제공하여,
다음 바인딩 패스 (binding pass)에서
확인할 수 있게 합니다.
UI Toolkit은
해당 값을 이전 값과 비교하며,
만약 변경되었다면 시스템은
이 데이터 소스가 새로고침되어야 함을 알게 됩니다.
다음으로,
publish라고 불리는 헬퍼 메서드 (helper method)를 추가합니다.
우리는 그저 버전 번호를 증가시킬
무언가가 필요할 뿐입니다.
버전이 변경되면,
바인딩 시스템은 다음 패스에서
그 변경을 감지할 수 있습니다.
get view hashCode를 통해서 말이죠.
이는 UI가 모든 중간 단계의 변화에
반응하도록 강제하는 대신,
업데이트를 버퍼링 (buffering)할 수 있게 해줍니다.
이제 이를 세터 (setter)의
현재 체력에 적용해 보겠습니다.
값이 같다면 조기에 종료합니다.
만약 변경되었다면, 백킹 필드 (backing field)를 업데이트한 후
publish를 호출합니다.
이렇게 하면 데이터 소스에 새로운 버전이 부여되어,
바인딩 시스템이 다음 바인딩 패스에서
새로고침해야 함을 알게 됩니다.
이것이 버전 관리 (versioning)입니다.
이제 INotifyBindablePropertyChanged를 사용하여
더 정밀하게 만들어 보겠습니다.
이것은 속성 변경 이벤트 (property changed event)를 추가합니다.
그리고 이를 notify라는 헬퍼 메서드로
감쌀 수 있습니다.
current health 내부에서
변경 속성에 대해 notify를 호출합니다.
이런 식으로 말이죠. current health의 이름입니다.
만약 CallerMemberName 어트리뷰트 (attribute)를 사용한다면,
속성 이름을 수동으로 전달할 필요조차 없습니다.
그저 notify만 호출하면 됩니다.
이제 우리는 두 가지 신호를 갖게 되었습니다.
get view hashCode는 시스템에
소스가 변경되었음을 알려주고,
notify를 통한 속성 변경 이벤트는
어떤 속성이 변경되었는지를 알려줍니다.

그리고 이 둘이 결합되면,
UI Toolkit이 새로고침이 필요함을 감지하고,
해당 변경사항의 영향을 받는 바인딩(bindings)만
업데이트할 수 있음을 의미합니다.
또한, 실제로 변경된 모든 속성과
그에 의존하는 모든 계산된 속성(computed properties)에 대해
notify를 호출해야 합니다.
예를 들어, 현재 체력(current health)이 변경되면
체력 백분율(health percentage)과
현재 체력 진행도(current health progress)도
함께 변경됩니다.
이것들이 우리의 계산된 값(computed values)입니다.
따라서 현재 체력의 setter(설정자)에서
이 값들을 여기에 notify 해줍니다.
이때 메서드의 이름이 필요할 것입니다.
이 패턴을 사용하면, UI Toolkit은 더 이상
이 속성들로부터 스스로 변경 사항을 추론하기만 하지 않습니다.
대신 여러분이 제공하는 이러한 신호(signals)에 의존하게 됩니다.
그러므로 현재 체력이 변경되면,
영향을 받는 속성들에 대해 notify를 호출한 다음,
버전을 올리기 위해 publish를 호출해야 합니다.
그렇지 않으면,
다른 무언가가 UI 새로고침을 트리거할 때까지
해당 업데이트가 반영되지 않을 수도 있습니다.
이것이 바로 버전 관리(versioning)와 변경 추적(change tracking)을 구현하는 방법입니다.
물론, 이는 런타임(runtime)에 업데이트되는 바인딩에만 해당됩니다.
만약 바인딩이 값을 한 번 읽은 후 단 한 번만 실행되도록 설정되어 있다면 말이죠.
따라서 플레이어 이름(player name)이나 최대 체력(max health)과 같은
값들에 대해서는 변경 추적이 전혀 필요하지 않을 수도 있습니다.
작은 UI에서는 이러한 효율성을 체감하지 못할 수도 있지만,
더 크고 데이터 중심적인(data driven) 인터페이스에서는
UI가 언제 새로고침될지에 대해 더 나은 제어권을 제공합니다.

이것이 UI Toolkit의 런타임 데이터 바인딩(runtime data binding)입니다.
우리는 UI Builder에서 바인딩을 정의하는 것으로 시작하여,
경량 컨트롤러(lightweight controller)를 통해 실시간 데이터를 연결했습니다.
그리고 마지막으로 버전 관리와 변경 추적을 추가하여
UI가 더 효율적으로 업데이트되도록 했습니다.
여러분의 UI는 필요한 것을 기술하고,
여러분의 데이터는 그것을 제공하며,
바인딩 시스템이 모든 것을 동기화 상태로 유지합니다.
이제 여러분은 모든 요소를 수동으로 업데이트하지 않고도
더 역동적인 UI를 구축할 수 있습니다.
UI Toolkit과 런타임 데이터 바인딩에 대해 더 자세히 알고 싶다면,
설명란의 링크를 꼭 확인해 주세요.
시청해 주셔서 감사합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 YouTube Unity 공식의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0