움직임은 클립이 아니라 두 값 사이에서 만들어진다
이벤트는 루트에서 내려갔다가 다시 올라온다에서 입력을 받는 쪽을 봤습니다. 이번은 그 입력에 화면이 반응하는 쪽입니다.
uGUI 에서 버튼 하나를 움직이려면 붙는 것이 셋이었습니다. Animator 컴포넌트, Animator Controller 에셋, 애니메이션 클립. Animator 는 붙어 있는 동안 계속 일한다에서 그게 왜 부담인지를 봤습니다. UI Toolkit 에는 그 자리가 아예 없습니다.
값이 바뀔 때 이어서 가라고 한 줄 적습니다
문서 정의가 짧습니다. “A USS transition changes property values over a given duration.”
움직임을 따로 만들지 않습니다. 평소 값과 바뀐 값을 적어 두고, 그 사이를 이어서 가라고만 적습니다.
.card {
background-color: rgb(32, 36, 44);
scale: 1;
transition-property: scale, background-color;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
.card:hover {
background-color: rgb(47, 111, 237);
scale: 1.04;
}
:hover 가 붙는 순간 값이 바뀌고, transition 이 그 사이를 채웁니다. 뗄 때도 같은 규칙으로 돌아옵니다. 돌아오는 것을 따로 적지 않았다는 점이 클립과 다릅니다.
적는 속성은 넷입니다.
| 속성 | 문서 설명 |
|---|---|
transition-property |
“Which USS properties the transition applies to” |
transition-duration |
“How long the transition takes to complete” |
transition-timing-function |
“How the property moves between values over time” |
transition-delay |
“When the transition starts” |
단축형 transition 도 있습니다. 문서는 값 순서를 “property, delay, duration, and timing function” 이라고 적어 뒀습니다. CSS 쪽 순서와 헷갈리기 쉬우니 처음에는 네 줄로 나눠 적는 편이 안전합니다.
값이 여럿이면 쉼표로 늘어놓습니다. transition-property 에 둘을 적었으면 transition-duration 에도 둘을 적어서 따로 줄 수 있습니다.
무엇을 전환하느냐가 비용을 가릅니다
여기가 이 편에서 제일 중요한 부분입니다. 문서가 권고를 분명하게 적어 뒀습니다.
“It’s recommended that you use transitions with the USS transform properties. Although you can use transitions on other USS properties, it might result in animations with low frame rates because value changes on these properties might cause layout recalculations.”
색도 안전합니다. “all color properties, such as color, background-color, tint, and opacity, also have a fast pass that prevents the regeneration of the geometry.”
정리하면 이렇습니다.
| 걸어도 되는 것 | 조심할 것 |
|---|---|
translate scale rotate |
width height |
color background-color |
margin padding |
opacity |
font-size |
한 칸이 바뀌면 그 캔버스는 통째로 다시 계산된다에서 본 것과 같은 이야기입니다. 체계가 바뀌었어도 자리를 바꾸는 값은 배치를 다시 잡게 만든다 는 구조는 그대로입니다.
그래서 카드를 옆으로 미는 연출이 있으면 margin-left 가 아니라 translate 를 씁니다. 눈에는 같아 보이는데 한쪽만 매 프레임 배치를 다시 잡습니다.
전환이 끝났을 때를 알고 싶으면
전환에도 이벤트가 옵니다. 넷입니다.
| 이벤트 | 문서 설명 |
|---|---|
TransitionRunEvent |
“Sent when a transition is created” |
TransitionStartEvent |
“Sent when a transition’s delay phase ends and the transition starts” |
TransitionEndEvent |
“Sent when a transition ends” |
TransitionCancelEvent |
“Sent when an a transition is canceled” |
넷 다 올라오는 길에서만 옵니다. 내려가는 길에서는 안 옵니다.
TransitionCancelEvent 가 따로 있다는 게 중요합니다. 도중에 값이 또 바뀌면 전환은 취소됩니다. 그러니 “전환이 끝나면 창을 닫는다” 같은 코드는 TransitionEndEvent 만 믿고 쓰면 안 됩니다. 취소된 경우에 창이 영영 안 닫힙니다.
popup.RegisterCallback<TransitionEndEvent>(_ => popup.style.display = DisplayStyle.None);
popup.RegisterCallback<TransitionCancelEvent>(_ => { /* 여기도 처리해야 합니다 */ });
의사 클래스로 안 되는 상태는 클래스로 만듭니다
이름을 붙여야 스타일을 걸 수 있다에서 :hover 같은 의사 클래스는 새로 만들 수 없다고 했습니다. “선택된 카드”, “새로 들어온 항목” 같은 우리 쪽 상태는 클래스를 직접 붙였다 뗍니다.
card.EnableInClassList("card--selected", isSelected);
이 한 줄이 클래스를 붙이면 값이 바뀌고, 값이 바뀌면 transition 이 알아서 걸립니다. 전환을 시작하는 코드가 따로 없습니다. 클립을 재생하던 자리에 있는 것이 이 줄입니다.
눌리는 것은 전부 같은 상태 다섯 개를 쓴다에서 본 Selectable 의 다섯 상태가, 여기서는 :hover :active :disabled :checked 와 내가 만든 클래스로 흩어집니다. 컴포넌트가 상태를 들고 있는 게 아니라 클래스가 상태입니다.
값이 바뀌면 화면이 따라오게 하려면
uGUI 에서 체력바를 갱신하려면 값이 바뀌는 쪽에서 slider.value = hp 를 불러 줘야 했습니다. 부르는 것을 잊으면 화면이 안 바뀌고, 매 프레임 부르면 안 바뀌어도 계속 부릅니다.
UI Toolkit 에는 데이터 바인딩 이 있습니다. 17편 비교표에서 UI Toolkit 쪽에만 있던 항목입니다.
먼저 데이터 쪽에 표식을 답니다. [CreateProperty] 가 붙은 것만 바인딩할 수 있습니다.
using Unity.Properties;
public class PlayerData
{
[CreateProperty]
public string playerName { get; set; }
[CreateProperty]
public float hp { get; set; }
}
그다음 요소에 데이터 원본과 경로를 걸어 줍니다.
root.dataSource = data;
var label = root.Q<Label>("name");
label.SetBinding("text", new DataBinding
{
dataSourcePath = new PropertyPath(nameof(PlayerData.playerName)),
});
uxml 에도 같은 것을 적을 수 있습니다. 이쪽이 UI Builder 에서 만들었을 때 나오는 모양입니다.
<engine:Label text="Label" data-source="ExampleObject.asset" data-source-path="simpleLabel">
<Bindings>
<engine:DataBinding property="text" binding-mode="ToTarget" />
</Bindings>
</engine:Label>
방향은 넷 중에 고릅니다.
| 모드 | 문서 설명 |
|---|---|
TwoWay |
“Changes are replicated from the data source to the UI and from the UI to the data source. This is the default binding mode” |
ToTarget |
“Changes are replicated from the data source to the UI only” |
ToSource |
“Changes are replicated from the UI to the data source only” |
ToTargetOnce |
“Changes are replicated from the data source to the UI only once, unless it’s marked as dirty” |
체력바처럼 보여 주기만 하는 것은 ToTarget 이고, 입력 칸처럼 사용자가 고치는 것은 TwoWay 입니다. 기본값이 TwoWay 라서, 읽기 전용으로 두고 싶으면 적어 줘야 합니다.
언제 갱신할지도 정합니다. 매 프레임 갱신, 원본이 바뀐 것을 감지했을 때 갱신, 더럽다고 표시했을 때 갱신 셋입니다. 변화 감지가 안 되는 형태면 매 프레임으로 떨어지니, 자주 안 바뀌는 값에는 표시해 주는 쪽을 쓰는 게 낫습니다.
정리
- Animator 도 컨트롤러도 클립도 없습니다. 평소 값과 바뀐 값을 적고 그 사이를 이어 가라고 uss 에 적습니다
- 적는 것은
transition-propertytransition-durationtransition-timing-functiontransition-delay넷입니다 - 문서가 transform 계열에 걸기를 권합니다. 다른 속성은 배치를 다시 계산하게 만들 수 있습니다
- 색과
opacity에는 빠른 경로가 있어서 메시를 다시 안 만듭니다 - 옆으로 미는 연출은
margin이 아니라translate입니다. 보기에 같고 비용이 다릅니다 - 전환 이벤트는 넷이고 올라오는 길에서만 옵니다.
TransitionCancelEvent를 빼먹으면 도중에 값이 바뀐 경우가 막힙니다 - 우리 쪽 상태는
EnableInClassList로 클래스를 붙였다 뗍니다. 전환을 시작하는 코드는 따로 없습니다 - 데이터 바인딩은
[CreateProperty]+dataSource+SetBinding셋입니다. 기본 모드가TwoWay라서 읽기 전용은 적어 줘야 합니다