GestureViewer Props
renderItem
renderItem은 data의 각 아이템을 렌더링하며, renderItem(item, index, { isActive, setItemDimensions }) 형태로 세 번째 인자에서 isActive와 setItemDimensions를 제공합니다.
비디오 재생처럼 활성 아이템에서만 필요한 작업은 isActive로 제어할 수 있습니다. 동작 방식과 예시는 renderItem 활성 상태 (isActive)를 참고하세요.
setItemDimensions({ width, height })는 렌더링된 콘텐츠의 원본 크기를 알 수 있게 된 뒤 호출하세요. 예시와 호출 시점은 콘텐츠 크기 가이드를 참고하세요.
enableLoop (기본값: false)
루프 모드를 활성화합니다. true일 때 마지막 아이템에서 다음으로 가면 첫 번째로, 첫 번째에서 이전으로 가면 마지막으로 돌아갑니다.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
enableLoop={true}
/>
);
}
enableSnapMode (기본값: false)
스냅 스크롤 모드를 활성화합니다.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
enableSnapMode={true}
/>
);
}
itemSpacing (기본값: 0)
아이템 간의 간격을 픽셀 단위로 설정합니다. enableSnapMode가 true일 때만 적용됩니다.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
data={data}
renderItem={renderItem}
enableSnapMode={true}
itemSpacing={16} // 16px spacing between items
/>
);
}
autoPlay (기본값: false)
자동 재생 모드를 활성화합니다. true일 때 지정된 간격 후 다음 아이템으로 자동으로 재생됩니다.
enableLoop이 활성화되면 마지막 아이템에서 다음으로 가면 첫 번째로, 첫 번째에서 이전으로 가면 마지막으로 돌아갑니다.
enableLoop이 비활성화되면 마지막 아이템에서 정지됩니다.
- 아이템이 하나만 있을 때 자동 재생이 비활성화됩니다.
- 줌 또는 회전 제스처가 감지되면 자동 재생이 일시 중지됩니다.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
autoPlay={true}
/>
);
}
autoPlayInterval (기본값: 3000)
자동 재생 간격을 밀리초 단위로 설정합니다.
양수 정수여야 합니다. 값이 250ms 미만이면 런타임에서 250ms로 제한됩니다.
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
return (
<GestureViewer
autoPlay={true}
autoPlayInterval={3000}
/>
);
}
onSingleTap
뷰어에서 싱글 탭이 확정되면 실행됩니다. 헤더, 푸터, 캡션, 액션 버튼처럼 뷰어 컨트롤 UI를 토글할 때 유용하며, 뷰어 위에 별도의 pressable을 덮지 않아도 됩니다.
- 더블 탭 줌이 활성화되어 있으면 더블 탭이 아닌지 확인한 뒤 실행되므로 약간 늦게 호출될 수 있습니다
- 스와이프, 핀치, dismiss, 더블 탭 줌 제스처에서는 호출되지 않습니다
import { GestureViewer } from 'react-native-gesture-image-viewer';
function App() {
const [showControls, setShowControls] = useState(true);
return (
<GestureViewer
data={images}
renderItem={renderImage}
onSingleTap={() => setShowControls((prev) => !prev)}
/>
);
}
getItemDimensions
콘텐츠의 원본 크기를 이미 알고 있을 때 반환합니다. renderItem에서 setItemDimensions로 런타임에 등록한 크기가 우선합니다. 예시는 콘텐츠 크기 가이드를 참고하세요.
getItemKey
같은 내용이 같은 슬롯에서 다른 객체로 다시 만들어질 수 있을 때 사용할 안정적인 논리 키를 반환합니다. setItemDimensions로 런타임에 등록한 크기와 함께 사용하세요. 자세한 내용은 콘텐츠 크기 가이드를 참고하세요.
initialIndex (기본값: 0)
뷰어가 표시할 아이템 인덱스를 설정할 수 있습니다. 이 값은 현재 data 길이에 맞게 정규화됩니다. 유한하지 않은 값과 음수는 0이 되고, 범위를 초과한 값은 마지막 인덱스가 되며, 빈 데이터는 0으로 처리됩니다.
뷰어가 이미 마운트된 뒤 initialIndex가 바뀌면 정규화된 인덱스로 다시 이동합니다.
maxZoomScale (기본값: 2)
최대 줌 배율을 제어할 수 있습니다.
GestureViewerProps interface
Go to source
GestureViewerProps
export type GestureViewerItemDimensions = Readonly<{
/** 콘텐츠의 원본 너비입니다. 유한한 양수여야 합니다. */
width: number;
/** 콘텐츠의 원본 높이입니다. 유한한 양수여야 합니다. */
height: number;
}>;
export type GestureViewerItemDimensionsResolver<ItemT> = (
item: ItemT,
index: number,
) => GestureViewerItemDimensions | undefined;
export type GestureViewerItemKey = string | number;
export type GestureViewerItemKeyResolver<ItemT> = (
item: ItemT,
index: number,
) => GestureViewerItemKey;
export type GestureViewerRenderItemInfo = {
/**
* 렌더링된 아이템이 현재 활성 상태인지 여부입니다.
* @remarks 페이지 전환 중에는 기존 아이템이 활성 상태를 유지합니다. 전환이 완료되어 다른 아이템으로 이동하면 해당 아이템이 활성화됩니다.
*/
readonly isActive: boolean;
/**
* 렌더링된 콘텐츠의 원본 크기를 사용할 수 있게 된 후 등록합니다.
* @remarks 이미지 로드 또는 이벤트 콜백에서 호출하거나, 커밋 이후의 일반 `useEffect`에서 호출하세요. 렌더링 중이나 하위 컴포넌트의 `useLayoutEffect`에서는 호출하지 마세요.
*/
readonly setItemDimensions: (dimensions: GestureViewerItemDimensions) => void;
};
export interface GestureViewerProps<ItemT, LC> {
/**
* 여러 개의 `GestureViewer` 인스턴스를 효율적으로 관리하고 싶다면 `id` prop을 사용해 각각의 `GestureViewer`를 구분할 수 있습니다.
* @remarks `GestureViewer`는 컴포넌트가 언마운트되면 인스턴스를 메모리에서 자동으로 제거하므로 별도의 수동 메모리 관리가 필요하지 않습니다.
* @defaultValue 'default'
*/
id?: string;
/**
* `GestureViewer`에 표시할 데이터입니다.
*/
data: ItemT[];
/**
* `GestureViewer`에 표시할 아이템의 인덱스입니다.
* @remarks
* - 현재 data 길이에 맞게 정규화됩니다. 유한하지 않은 값과 음수는 0, 범위를 초과한 값은 마지막 인덱스, 빈 데이터는 0이 됩니다.
* - prop이 바뀌면 이미 마운트된 viewer도 정규화된 인덱스로 다시 이동합니다.
* @defaultValue 0
*/
initialIndex?: number;
/**
* `GestureViewer`가 닫힐 때 호출되는 콜백 함수입니다.
*/
onDismiss?: () => void;
/**
* dismiss 인터랙션이 시작될 때 호출되는 콜백 함수입니다.
* @remarks dismiss 제스처/애니메이션이 진행되는 동안 외부 UI(예: 헤더, 버튼)를 숨길 때 유용합니다.
*/
onDismissStart?: () => void;
/**
* 아이템을 렌더링할 때 호출되는 콜백 함수입니다.
* @param item - 렌더링할 아이템입니다.
* @param index - 렌더링된 아이템의 리스트 인덱스입니다.
* @param info - 이 리스트 셀의 렌더링 상태입니다.
*/
renderItem: (item: ItemT, index: number, info: GestureViewerRenderItemInfo) => React.ReactElement;
/**
* 뷰어 콘텐츠에서 싱글 탭이 확정되었을 때 호출되는 콜백 함수입니다.
* @remarks
* - 이 콜백은 탭이 싱글 탭으로 확정된 뒤에만 실행되므로, 더블 탭 줌이 활성화되어 있으면 약간 지연될 수 있습니다.
* - 스와이프, 핀치, dismiss, 더블 탭 줌 제스처에서는 호출되지 않습니다.
* - 전체 화면 탭 처리가 필요하다면 `renderContainer`에서 pressable을 덮어씌우는 대신 이 콜백 사용을 권장합니다.
*/
onSingleTap?: (event: GestureViewerSingleTapEvent<ItemT>) => void;
/**
* 콘텐츠의 원본 크기를 이미 알고 있을 때 반환합니다.
* @remarks 크기를 아직 모르면 `undefined`를 반환하세요. 유효하지 않은 크기는 뷰어 셀 크기로 대체됩니다.
*/
getItemDimensions?: GestureViewerItemDimensionsResolver<ItemT>;
/**
* 같은 아이템이 같은 슬롯에서 다른 객체로 다시 만들어질 수 있을 때 사용할 안정적인 논리 키를 반환합니다.
* @remarks 객체 동일성이 리렌더링 사이에 유지되지 않을 때 사용하세요. 이 키는 같은 렌더 결과를 가리켜야 하며, 이미지 소스나 원본 크기가 바뀌면 함께 바뀌어야 합니다. 배열 인덱스만 그대로 반환하지 마세요. 아이템이 다른 위치로 이동하면 새 슬롯에서 크기를 다시 등록할 때까지 `getItemDimensions` 또는 뷰어 셀 크기를 사용합니다.
*/
getItemKey?: GestureViewerItemKeyResolver<ItemT>;
/**
* 컨테이너를 렌더링할 때 호출되는 콜백 함수입니다.
* @remarks 뷰어 주변에 추가 UI(예: 닫기 버튼, 툴바)를 구성할 때 유용합니다.
* 전체 화면 탭 처리는 뷰어 콘텐츠 위에 pressable을 덮어씌우기보다 `onSingleTap` 사용을 권장합니다.
* 두 번째 인자는 `dismiss()`처럼 뷰어를 닫을 수 있는 제어 헬퍼를 제공합니다.
*
* @param children - 컨테이너 내부에 렌더링할 뷰어 콘텐츠입니다.
* @param helpers - 뷰어 제어 헬퍼입니다. 현재는 `dismiss()`를 포함합니다.
* @returns 전달된 `children`을 감싸서 렌더링하는 React 엘리먼트입니다.
*/
renderContainer?: (
children: React.ReactElement,
helpers: { dismiss: () => void },
) => React.ReactElement;
/**
* `ListComponent` prop을 통해 `ScrollView`, `FlatList`, `FlashList` 같은 다양한 리스트 컴포넌트를 지원합니다.
*/
ListComponent: LC;
/**
* `GestureViewer`의 너비입니다.
* @remarks 이 prop을 지정하지 않으면 `GestureViewer`의 너비는 화면 너비와 동일해집니다.
* @defaultValue 화면 너비
*/
width?: number;
/**
* `GestureViewer`의 높이입니다.
* @remarks 이 prop을 지정하지 않으면 `GestureViewer`의 높이는 화면 높이와 동일해집니다.
* @defaultValue 화면 높이
*/
height?: number;
/**
* 리스트 컴포넌트에 전달할 props입니다.
* @remarks `listProps`는 **선택한 리스트 컴포넌트를 기준으로 타입 추론**을 제공하므로 IDE에서 더 정확한 자동완성과 타입 안정성을 보장합니다.
*/
listProps?: Partial<ConditionalListProps<ItemT, LC>>;
/**
* backdrop의 스타일입니다.
*/
backdropStyle?: StyleProp<ViewStyle>;
/**
* 컨테이너의 스타일입니다.
*/
containerStyle?: StyleProp<ViewStyle>;
/**
* 자동 재생 모드입니다.
* @remarks
* - `true`이면 지정된 간격 후 다음 아이템이 자동으로 재생됩니다.
* - `enableLoop`가 활성화되어 있으면 마지막 아이템 다음에 첫 번째 아이템으로 돌아갑니다.
* - `enableLoop`가 비활성화되어 있으면 마지막 아이템에서 멈춥니다.
* - 아이템이 하나뿐이면 자동 재생은 비활성화됩니다.
* - 줌 또는 회전 제스처가 감지되면 자동 재생이 일시 정지됩니다.
* @defaultValue false
*/
autoPlay?: boolean;
/**
* 자동 재생 간격입니다.
* @remarks
* - `autoPlay`가 활성화되어 있으면 지정된 간격(ms)마다 다음 아이템으로 이동합니다.
* - 양의 정수여야 합니다. 250ms 미만 값은 런타임에서 250ms로 보정됩니다.
* @defaultValue 3000
*/
autoPlayInterval?: number;
/**
* dismiss 제스처 옵션입니다.
* @remarks 위/아래 방향을 선택할 수 있는 수직 스와이프 닫기 제스처에 유용합니다.
*/
dismiss?: {
/**
* `false`이면 dismiss 제스처가 비활성화됩니다.
* @defaultValue true
*/
enabled?: boolean;
/**
* 어떤 수직 스와이프 방향에서 `onDismiss`를 호출할지 설정합니다.
* @remarks 기존 동작과 호환되는 `down`, 위로만 닫는 `up`, 양방향 모두 허용하는 `both`를 사용할 수 있습니다.
* @defaultValue 'down'
*/
direction?: GestureViewerDismissDirection;
/**
* `threshold`는 수직 제스처 중 임계값을 적용해 `onDismiss`가 호출되는 시점을 제어합니다.
* @defaultValue 80
*/
threshold?: number;
/**
* `resistance`는 dismiss 제스처 중 저항을 적용해 수직 이동 범위를 제어합니다.
* @defaultValue 2
*/
resistance?: number;
/**
* 기본적으로 설정된 dismiss 방향으로 드래그하는 동안 배경 `opacity`가 점진적으로 감소합니다.
* @remarks `false`이면 이 애니메이션이 비활성화됩니다.
* @defaultValue true
*/
fadeBackdrop?: boolean;
};
/**
* 좌우 스와이프 제스처를 제어합니다.
* @remarks `false`이면 가로 제스처가 비활성화됩니다.
* @defaultValue true
*/
enableHorizontalSwipe?: boolean;
/**
* 줌이 활성화된 경우에만 동작하며, 확대된 상태에서 아이템 위치를 이동할 수 있게 합니다.
* @remarks `false`이면 줌 중 제스처 이동이 비활성화됩니다.
* @defaultValue true
*/
enablePanWhenZoomed?: boolean;
/**
* 두 손가락 핀치 제스처를 제어합니다.
* @remarks `false`이면 두 손가락 줌 제스처가 비활성화됩니다.
* @defaultValue true
*/
enablePinchZoom?: boolean;
/**
* 더블 탭 줌 제스처를 제어합니다.
* @remarks `false`이면 더블 탭 줌 제스처가 비활성화됩니다.
* @defaultValue true
*/
enableDoubleTapZoom?: boolean;
/**
* 무한 루프 탐색을 활성화합니다.
* @defaultValue false
*/
enableLoop?: boolean;
/**
* 스냅 스크롤 모드를 활성화합니다.
*
* @remarks
* **`false` (기본값)**: 페이징 모드 (`pagingEnabled: true`)
* - 화면 전체 크기 단위로 스크롤됩니다.
*
* **`true`**: 스냅 모드 (`snapToInterval` 자동 계산)
* - `snapToInterval`은 `width`와 `itemSpacing` 값을 기준으로 자동 계산됩니다.
* - 아이템 간격이 필요할 때 이 옵션을 사용하세요.
* @defaultValue false
*
*/
enableSnapMode?: boolean;
/**
* 아이템 사이 간격(픽셀)입니다.
* @remarks `enableSnapMode`가 `true`일 때만 적용됩니다.
* @defaultValue 0
*/
itemSpacing?: number;
/**
* 최대 줌 배율입니다.
* @defaultValue 2
*/
maxZoomScale?: number;
/**
* 트리거 기반 애니메이션 설정입니다.
* @remarks 애니메이션 지속 시간, easing, 시스템 reduce-motion 동작을 커스터마이즈할 수 있습니다.
*
* @example
* ```tsx
* <GestureViewer
* triggerAnimation={{
* duration: 250,
* easing: Easing.out(Easing.cubic),
* reduceMotion: 'system',
* onAnimationComplete: () => {
* console.log('애니메이션 완료');
* },
* }}
* />
* ```
*/
triggerAnimation?: TriggerAnimationConfig;
}