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)}
/>
);
}
panInertia (기본값: false)
확대한 이미지를 드래그하고 손을 떼면 관성으로 이동하다 감속합니다. 기본 설정은 true, 세부 설정은 enabled를 명시한 객체로 전달합니다.
<GestureViewer
data={data}
renderItem={renderItem}
panInertia
/>
<GestureViewer
data={data}
renderItem={renderItem}
panInertia={{
enabled: true,
deceleration: 0.9998,
velocityFactor: 1,
rubberBandEffect: true,
rubberBandFactor: 3,
}}
/>
type GestureViewerPanInertiaConfig = {
enabled: boolean;
deceleration?: number;
velocityFactor?: number;
rubberBandEffect?: boolean;
rubberBandFactor?: number;
};
// panInertia?: boolean | GestureViewerPanInertiaConfig
생략하거나 false, { enabled: false }를 전달하면 기존처럼 관성 없이 멈춥니다. 빈 객체는 허용하지 않으며 enablePanWhenZoomed도 켜져 있어야 합니다.
필요한 값만 지정하면 생략한 항목에는 다음 기본값을 사용합니다.
deceleration은 0보다 크고 1보다 작은 유한한 값이어야 합니다. velocityFactor와 rubberBandFactor는 0보다 큰 유한한 값이어야 합니다. 잘못된 값은 각 항목의 기본값으로 대체합니다. 설정 변경은 다음 드래그 종료부터 적용하며, 관성을 비활성화하면 현재 애니메이션을 중단하고 경계를 넘은 위치도 정리합니다.
탄성은 손을 뗀 뒤의 관성 이동에 적용됩니다. 콘텐츠 경계 안에서 멈추며 페이지를 전환하지 않습니다. 실제 콘텐츠 경계를 사용하려면 getItemDimensions 또는 setItemDimensions로 크기를 제공하세요. 없으면 뷰어 크기를 기준으로 제한합니다. 새 터치는 경계 밖이라도 잡은 위치를 유지하고, 손을 떼면 경계로 돌아옵니다. 핀치, 확대·회전·크기 변경, 페이지 이동, 닫기도 관성을 중단합니다. 실제 드래그 속도와 경계, 시스템의 동작 줄이기 설정은 뷰어 내부에서 관리하며 panInertia로 변경할 수 없습니다.
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 `enablePanWhenZoomed`가 활성화되어 있어야 합니다. 기본 설정은 `true`, 사용자 설정은 `enabled: true`를 포함한 객체로 전달합니다. 콘텐츠 경계와 시스템의 동작 줄이기 설정을 따릅니다.
* @defaultValue false
*/
panInertia?:
| boolean
| {
/** 설정 객체를 사용할 때 관성 활성화 여부를 명시합니다. */
enabled: boolean;
/**
* 속도가 줄어드는 정도입니다. `1`에 가까울수록 오래 미끄러집니다.
* @remarks `0`보다 크고 `1`보다 작은 유한한 값만 허용합니다. 잘못된 값은 기본값으로 대체합니다.
* @defaultValue 0.9997
*/
deceleration?: number;
/**
* 손을 뗄 때의 속도에 적용해 이동량을 조절하는 배율입니다.
* @remarks `0`보다 큰 유한한 값만 허용합니다. 잘못된 값은 기본값으로 대체합니다.
* @defaultValue 0.5
*/
velocityFactor?: number;
/**
* 콘텐츠 경계를 잠깐 넘었다가 가장자리로 돌아오는 탄성을 적용합니다.
* @defaultValue true
*/
rubberBandEffect?: boolean;
/**
* 경계를 넘은 뒤 돌아오는 힘의 크기입니다. `rubberBandEffect`가 false이면 무시합니다.
* @remarks `0`보다 큰 유한한 값만 허용합니다. 잘못된 값은 기본값으로 대체합니다.
* @defaultValue 1
*/
rubberBandFactor?: number;
};
/**
* 두 손가락 핀치 제스처를 제어합니다.
* @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;
}