ScrollViewInterceptor | CoUI
LogoCoUI

ScrollViewInterceptor

데스크톱 트랙패드·휠 스크롤을 가로채 스크롤 뷰를 구동하는 래퍼 (인프라)

ScrollViewInterceptor#

데스크톱 포인터(트랙패드·마우스 휠) 스크롤을 가로채 child 스크롤 뷰를 부드럽게 구동하는 인프라 래퍼입니다. 스크롤 가능한 영역을 감싸 데스크톱 스크롤 감도/속도를 디자인 시스템 토큰으로 통일합니다. enabledfalse 면 가로채지 않고 네이티브 스크롤로 패스합니다.

Live Preview#

사용법#

ScrollViewInterceptor(
  child: ScrollArea(
    scrollAreaStyle: const CoreScrollAreaStyle(maxHeight: 160),
    child: Column(children: [/* 긴 콘텐츠 */]),
  ),
)

Props#

파라미터타입기본값설명
child Widget / Component required 스크롤 가로채기를 적용할 스크롤 뷰
enabled bool true false 면 가로채지 않고 네이티브 스크롤로 패스
scrollViewInterceptorStyle CoreScrollViewInterceptorStyle? null dragSpeed·maxScrollSpeed 등 동작 단일 진입점

스타일 시스템 (Style System)#

CoreScrollViewInterceptorStyle 필드#

필드타입설명
dragSpeed double? Multiplier applied to the pointer offset before the easing curve.
maxScrollSpeed double? Maximum absolute scroll velocity per frame (logical px).

사용 가이드라인 (Usage Guidelines)#

✅ Do#

가속하고 싶은 스크롤 영역 하나만 좁게 감싸기

ScrollViewInterceptor(
  child: ScrollArea(
    scrollAreaStyle: const CoreScrollAreaStyle(maxHeight: 240),
    child: content,
  ),
)

"가장 가까운 스크롤 가능한 조상"을 명령형으로 움직이는 방식이라, 실제로 가속하려는 스크롤 뷰 하나만 감싸야 어떤 스크롤 영역이 반응할지 모호해지지 않습니다.


❌ Don't#

유일한 스크롤 수단으로 의존하지 않기

// ❌ 필수 동선인데 ScrollViewInterceptor 에만 의존
ScrollViewInterceptor(
  child: criticalScrollableContent,
)

마우스 가운데 버튼(Flutter PointerEvent.buttons != 4, Web MouseEvent.button != 1)에서만 동작합니다 — 터치·키보드·트랙패드 전용 사용자에게는 이 경로가 존재하지 않으므로, 감싼 스크롤 뷰 자체의 기본 스크롤이 항상 동작해야 하고 이 컴포넌트는 부가 가속 수단으로만 취급해야 합니다.

접근성 (Accessibility)#

역할 (Semantics)#

양 플랫폼 모두 역할을 내보내지 않습니다. Flutter 는 Stacks 안에 Listener(그리고 자동 스크롤 중에만 커서 오버레이)를 두고 Semantics 를 만들지 않으며, Web 은 호출자가 넘긴 attributes 만 통과시키는 <div> 를 내보냅니다 — enabled: false 경로도 마찬가지로 빈 래퍼입니다. 시맨틱상 완전히 투명한 포인터 제스처 래퍼라, 감싼 콘텐츠의 시맨틱이 곧 전체 안내입니다.

키보드#

처리하는 키가 없습니다. Flutter 는 onPointerDown / onPointerMove / onPointerUp 만, Web 은 pointerdown / pointermove / pointerup / pointercancel 만 등록합니다 (Web 의 onKeyDown / onKeyUp 은 호출자 통과 슬롯). 자동 스크롤 제스처에 대응하는 키보드 경로는 양 플랫폼 모두 존재하지 않습니다.

포커스#

포커스를 받지 않습니다. FocusNode / Focus / tabindex 가 없고 포커스 상태를 그리지도 않습니다. 이 컴포넌트가 렌더하는 유일한 상태는 자동 스크롤 중의 커서 변경입니다 (Flutter SystemMouseCursors.allScroll, Web cursor-all-scroll 클래스).

스크린 리더#

아무것도 안내하지 않습니다. 자동 스크롤을 쓸 수 있다는 사실, 세션이 시작됐다는 사실, 지금 스크롤 중이라는 사실 중 무엇도 알려지지 않습니다.

알려진 제약#

  • 마우스 가운데 버튼 전용입니다 — Flutter 는 PointerEvent.buttons != 4, Web 은 MouseEvent.button != 1 에서 곧바로 빠져나옵니다. 터치 · 키보드 · 트랙패드 전용 입력에는 대응 경로가 없으므로, 마우스 가운데 버튼을 쓸 수 없는 사용자에게는 이 기능이 존재하지 않는 것과 같습니다. 감싼 스크롤 뷰 자체의 스크롤은 그대로 동작하니, 이 래퍼는 부가 가속 수단으로만 취급하고 필수 동선에 두지 마세요.
  • Web 은 event.preventDefault()브라우저 자체의 미들클릭 자동 스크롤을 대체합니다. 그 기본 동작에 의존하던 사용자는 이 구현의 감도/속도 토큰을 대신 받게 됩니다.
  • 스크롤은 가장 가까운 스크롤 가능한 조상을 명령형으로 이동시키는 방식이라 포커스가 따라가지 않고 어떤 안내도 발생하지 않습니다 — 화면은 움직였는데 리더의 위치는 그대로입니다.
  • enabled: false 면 양 플랫폼 모두 아무것도 하지 않는 통과 래퍼가 됩니다.

reduced motion 등 컴포넌트를 가로지르는 축은 전역 접근성 축에서 다룹니다.