brunch

You can make anything
by writing

C.S.Lewis

by Sung Jae Ryu Dec 18. 2017

IScroll 라이브러리

네이티브 스크롤을 대신해서

차량용 인포테인먼트 앱에서 스크롤 동작은 운전에 방해가 되어서는 안 된다. 특히 운전 중일 때와 그렇지 않을 때의 스크롤 동작은 달라질 수 있다. 따라서 스크롤과 스크롤바의 동작을 커스터마이징하고 관리할 수 있어야 한다. 네이티브 스크롤에는 한계가 있기에 스크롤 라이브러리를 사용한다.


iScroll을 사용한 이유

자바스크립트 라이브러리로 굉장히 많은 스크롤 라이브러리들이 존재한다. 하지만 , 대부분 CSS를 이용한 애니메이션 효과와 이펙트에만 치중해있다 보니 스크롤 본연의 기능에 미흡한 부분이 없지 않아 있다. 우리에게 필요한 건 스크롤 기능이다. 화려한 효과가 아니다. 때문에 다양한 스크롤 기능과 인터페이스를 제공하는 라이브러리를 찾고 있었고 그에 부합하는 것이 iScroll이었다. 사실 이전 프로젝트부터 iScroll을 사용해 왔다. 그리고 github의 많은 start점수 갖고 있다 :)


Snap

가장 필요한 동작은 Snap동작이다. 스크롤이 특정 엘리먼트 단위 혹은 px단위로 스크롤되기를 원한다. iscroll 생성 시 snap옵션 주어 특정 엘리먼트 단위로 snap동작이 되게 할 수 있다. 이제 원하는 snap동작을 얻을 수 있다.

new IScroll('#scroll-container' {
  snap: '.item'
})


snap 스크롤 동작


성능 개선점 in snap

자 이제 스크롤을 특정 엘리먼트 단위로 스크롤되게 할 수 있다. 하지만 snap동작을 위해서 iScroll 내부에서는 스크롤 생성 시점과 업데이트 시점에 특정 데이터들을 저장한다. 그리고 스크롤링 할 때 이 데이터를 이용해 특정 작업을 수행한다. 이 또한 성능에 영향을 줄 수 있다. 스크롤은 자고로 부드러운 동작을 요구하는데, 이 연산이 부드러운 동작에 방해가 될 수 있다.

snap 옵션을 줄 경우 위의 코드가 동작한다. _initSnap 함수 내에서 동작하고 this.pages 객체에 모든 아이템들의 정보를 저장한다. 이 작업을 위해 아이템 개수만큼 반복문을 돌린다. 이동작은 스크롤을 초기화하거나 refresh 함수를 호출하여 스크롤을 업데이트할 때 동작된다.


스크롤 동작을 수행할 경우에는 저장된 this.pages 객체에서 목적지 엘리먼트를 찾는다.

y는 스크롤 플리킹 동작으로 얻어진 목적지 y좌표이다. 목적지 y좌표에서 가장 가까운 아이템을 찾는다. 0번째 인덱스부터 찾아 나가기 때문에 리스트 처음 위치에서 스크롤할 경우 성능에 부하는 없다. 하지만 리스트 아이템이 많아질수록, 아래로 스크롤하여 계속 내려갈 경우 위 반복문 동작 횟수는 증가하게 된다.

 

이 부분이 PC / mobile 환경에서는 큰 영향을 주지는 않는다. 하지만 내가 진행하는 프로젝트에서 사용되는 하드웨어는 이 보다 훨씬 열악한 환경이고 전체 리소스를 모두 사용하는 데에 제한이 있다. 따라서 이 부분을 약간 개선해보았다.


개선방향

리스트의 아이템들이 모두 같다는 가정하에 snap동작을 수정했다. snap 매개변수를 element나 selector로 받지 않고 높이로 바꾸었다.

new IScroll('#scroll-container' {
  snap: 50
})

스크롤 생성 및 업데이트 시점에 _initSnap 함수를 호출하지 않고 _nearestSnap 함수와 this.pages를 더 이상 사용하지 않게 수정한다. 그리고 스크롤 동작시 목적지 y좌표를 읽어와 아래와 같이 단순 계산을 이용해 snap이 적용된 최종 스크롤 목적지 좌표를 계산한다.

이렇게 수정된 스크롤은 더 이상 스크롤 시 리스트 아이템을 순회할 필요가 없어진다. 사실 이런 방식의 스크롤링 기법을 사용하는 라이브러리는 존재한다. zynga 스크롤이 리스트 아이템 높이 단위로 snap 된다. 그래서 리스트 아이템의 정보를 저장할 필요가 없게 되었지만, iscroll보다 적은 인터페이스를 갖는 것은 사실이다.


개선, 그러나 잃게 되는 것들

iscroll내부에서 this.pages 객체의 영향력이 크다. 많은 곳에서 이 객체를 참조한다. 특히 snap이 적용된 스크롤에서 특정 엘리먼트 또는 위치로 스크롤하는 함수에서 사용된다. 때문에 this.pages 객체를 생성하지 않고 iscroll을 사용하면 많은 스크롤 인터페이스를 잃게 된다. 글 처음 부분에서 언급한 iscroll 채택 목적 중 가장 중요한 “다양한 스크롤  인터페이스”를 사용할 수 없게 된다. 단순 스크롤 동작만 구현한다면 큰 문제는 없겠지만, 필요한 인터페이스를 사용할 수 없게 되니 잃는 것이 얻는 것에 비해 너무 크다고 생각된다.


그리고 iscroll에서 snap의 오버헤드 이슈는 리스트 아이템들이 굉장히 많을 경우에만 발생한다. 이렇게 리스트 아이템이 너무 많은 경우에는 UI/UX차원에서 해결하거나 가상 스크롤을 사용하는 방법이 더 최선일 것이라 생각한다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari