Cheondi
개발 · Unity

창 크기만 바꿨는데 로직까지 흔들렸다

재사용 리스트를 리사이즈하면서 보이는 항목 수와 스크롤 위치까지 함께 바뀌던 문제를 정리한 기록입니다.

  • #unity
  • #responsive-ui
  • #scroll-view

재사용 스크롤을 적용한 뒤 목록을 여는 속도는 좋아졌다. 이제 끝났다고 생각했는데 창 크기를 줄였다 늘리면 항목이 겹치거나 빈 공간이 생겼다. 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의 데이터 목록에서는 화면 크기가 보이는 데이터 범위와 오브젝트 재사용 수를 바꿨다. 즉 리사이즈는 비즈니스 로직은 아니지만 화면 로직의 입력이었다.

이후 크기 대응 기능을 볼 때 프리팹만 확인하지 않는다. 크기 변경 뒤 선택 상태, 스크롤 위치, 아이템 풀, 늦게 온 데이터가 어떻게 다시 그려지는지 함께 본다. 창 크기만 바꿨을 뿐인데 왜 버그가 많았는지 이제는 조금 설명할 수 있게 됐다.