재사용 스크롤을 적용한 뒤 목록을 여는 속도는 좋아졌다. 이제 끝났다고 생각했는데 창 크기를 줄였다 늘리면 항목이 겹치거나 빈 공간이 생겼다. UI 크기만 바뀌는 문제라고 생각해 Anchor와 Layout Group을 계속 조정했지만 증상은 사라지지 않았다.
화면 높이가 바뀌면 한 번에 보이는 아이템 수가 달라진다. 재사용 오브젝트 개수와 첫 인덱스, 스크롤 범위도 다시 계산해야 했다. 레이아웃 변화가 데이터 표시 로직까지 영향을 주고 있었다.
화면 크기의 입력값 처리
기존 계산은 시작할 때 측정한 높이를 계속 사용했다.
visibleCount = Mathf.CeilToInt(viewportHeight / itemHeight);
창을 바꾼 뒤에도 visibleCount가 그대로이니 큰 화면에서는 아래가 비었고 작은 화면에서는 필요 없는 아이템이 겹쳤다. 크기 변경 이벤트에서 전체 계산을 다시 하되 현재 보고 있던 위치는 최대한 유지해야 했다.
비율과 위치의 보존 기준
리사이즈 전후에 normalizedPosition만 유지하면 데이터 개수가 적을 때 값이 불안정했다. 반대로 첫 데이터 인덱스만 유지하면 사용자가 항목 중간을 보고 있던 미세한 위치가 튀었다.
그래서 다음 두 값을 분리해서 생각했다.
- 현재 화면 맨 위에 가까운 데이터 인덱스
- 해당 아이템 안에서 얼마나 내려와 있었는지 나타내는 오프셋
var anchor = new ScrollAnchor(firstVisibleIndex, offsetInItem);
RebuildForNewSize();
Restore(anchor);
프로젝트 구현은 더 복잡했지만, 화면 비율 대신 사용자가 보고 있던 데이터 위치를 기준으로 복원한다는 생각이 도움이 됐다.
0 크기 경계값
스크롤 범위가 없거나 항목이 화면보다 적으면 정규화 값이 0 또는 1로 고정됐다. 평소 계산식을 그대로 쓰면 나눗셈 결과가 이상해지거나, 리사이즈할 때 목록이 반대편으로 튀었다.
if (contentHeight <= viewportHeight)
{
SetScrollOffset(0);
return;
}
일반적인 상황에서 잘 되는 계산보다 경계값에서 무엇을 할지 명확히 정하는 게 중요했다. 빈 목록, 한 개짜리 목록, 화면에 딱 맞는 목록을 따로 시험했다.
레이아웃을 넘어선 반응형 UI
웹에서 반응형이라는 말을 들으면 CSS처럼 모양이 바뀌는 걸 먼저 떠올렸다. Unity의 데이터 목록에서는 화면 크기가 보이는 데이터 범위와 오브젝트 재사용 수를 바꿨다. 즉 리사이즈는 비즈니스 로직은 아니지만 화면 로직의 입력이었다.
이후 크기 대응 기능을 볼 때 프리팹만 확인하지 않는다. 크기 변경 뒤 선택 상태, 스크롤 위치, 아이템 풀, 늦게 온 데이터가 어떻게 다시 그려지는지 함께 본다. 창 크기만 바꿨을 뿐인데 왜 버그가 많았는지 이제는 조금 설명할 수 있게 됐다.
유사 문제 대응 기준
작업 당시에는 눈앞의 오류를 먼저 고쳤지만, 이후 기술 문서와 맞춰 보며 확인 순서를 조금 더 구체화했다.
Rect Transform 문서의 anchor와 pivot을 기준으로 보면 해상도 대응은 좌표를 비율로 바꾸는 작업보다 부모 영역과 정렬 기준을 명시하는 작업에 가깝다. WCAG 2.1의 reflow와 orientation 기준도 특정 화면 크기를 맞추는 데서 끝나지 않고, 확대·회전 뒤에도 내용과 조작이 사라지지 않아야 한다는 관점을 준다.
그래서 기준 해상도 한 장만 통과하는 것보다 작은 폭, 긴 번역, 키보드가 올라온 상태를 별도 조건으로 두는 편이 낫다.
다음에 창 크기 변경과 로직 영향 같은 문제를 보면 아래 순서부터 확인하려고 한다.
- 최소 폭과 최대 글자 확대
- 회전 전후 선택·스크롤 위치
- safe area와 키보드가 줄인 가용 영역
- 이미지 비율과 대체 문구
안전 영역, 글자 확대, 소프트 키보드는 레이아웃 이후에 붙는 예외가 아니라 처음부터 가용 영역을 바꾸는 입력값이다.
공식 참고 자료
- Unity 2021.3 Rect Transform 문서 — 앵커·피벗과 부모 영역에 따른 UI 배치
- W3C WCAG 2.1 — 확대·reflow·orientation·입력 접근성