레이아웃 시스템
VPE React Native SDK는 웹 SDK에서 포팅된 layout-driven ControlBar 시스템을 제공합니다. JSON 선언으로 컨트롤 버튼의 배치, 그룹화, 환경별(PC/모바일/전체화면) × 콘텐츠 유형별(VOD/Live) 구성을 정의할 수 있습니다.
AndroidiOS
개요
layout prop에 레이아웃 객체를 전달하여 ControlBar의 모든 영역을 사용자 정의할 수 있습니다. layout prop이 없을 경우 기본 반응형 레이아웃이 사용됩니다.
- 5개 섹션:
top,upper,center,lower,bottom - 환경별 분리:
pc/mobile/fullscreen - 콘텐츠 유형 분리:
vod/live - 모바일 판정 breakpoint: 기본 768
- 사용자 layout × 디폴트 layout 자동 병합 (섹션 단위 replace)
구성 구조
layout.json
{
"pc": {
"vod": { ... },
"live": { ... }
},
"mobile": {
"vod": { ... },
"live": { ... }
},
"fullscreen": {
"vod": { ... },
"live": { ... }
},
"breakpoint": 768
}각 variant 내부는 5개 섹션의 순서와 그룹/아이템 정렬로 구성됩니다.
variant.json
{
"order": ["top", "upper", "center", "lower", "bottom"],
"top": [
{ "wrapper": "Group", "items": ["BackBtn"] },
{ "wrapper": "Blank" },
{ "wrapper": "Group", "items": ["ShareBtn", "SettingBtn"] }
],
"center": [
{ "wrapper": "Blank", "items": ["BigPlayBtn"] }
],
"bottom": {
"seekbar": ["SeekBar"],
"left": [
{ "wrapper": "Group", "items": ["PlayBtn", "VolumeBtn"] },
{ "wrapper": "Group", "items": ["TimeBtn"] }
],
"right": [
{ "wrapper": "Group", "items": ["SubtitleBtn", "FullscreenBtn"] }
]
}
}사용 가능한 컨트롤 아이템
items 배열에 다음 이름들을 사용할 수 있습니다.
| 이름 | 설명 |
|---|---|
| PlayBtn | 재생/일시정지/다시보기 토글 (isEnded 분기) |
| BigPlayBtn | 중앙 큰 재생 버튼. playlist > 1 시 양옆 prev/next 자동 표시 |
| VolumeBtn | 음량 토글 |
| MuteBtn | 음소거 전용 버튼 |
| TimeBtn | 현재시간 / 총시간 또는 LIVE 인디케이터 |
| CurrentTimeBtn | 현재 재생 시간 (분리 버전) |
| DurationBtn | 총 재생 시간 (분리 버전) |
| SeekBar | 진행도 슬라이더 |
| FullscreenBtn | 전체화면 토글 |
| SubtitleBtn | 자막 즉시 토글 (SettingsMenu 거치지 않음) |
| SettingBtn | SettingsMenu 토글 (화질/재생속도/자막) |
| PrevBtn | 이전 트랙 |
| NextBtn | 다음 트랙 |
| NextPrevBtn | 이전/다음 통합 버튼 |
| BackBtn | 뒤로가기. events.backPress 호출 |
| ShareBtn | React Native Share API 호출 |
| SkipForwardBtn | 10초 앞으로 이동 |
| SkipBackBtn | 10초 뒤로 이동 |
| MetaDesc | 영상 메타데이터 (제목/프로필/등록일) |
| Blank | 자식이 없으면 spacer(flex:1), 있으면 정렬용 row |
참고: React Native에서는 명시적 PIP 버튼(
PipBtn)이 비표준이므로 폐지되었습니다. 대신 playerRef.current.pip() 또는 options.allowsPictureInPicture lifecycle을 사용하세요.wrapper 종류
Group— 디폴트 알약 모양 그룹 (반투명 배경, borderRadius 999). 단일 자식이면 원형(aspectRatio:1) 처리,TimeBtn은 단독일 때 우회.Blank— 자식이 없으면 spacer, 자식이 있으면 align 적용 row.
기본 사용 예제
import { VpePlayer } from 'vpe-react-native';
const myLayout = {
pc: {
vod: {
order: ['top', 'center', 'bottom'],
top: [
{ wrapper: 'Group', items: ['BackBtn'] },
{ wrapper: 'Blank' },
{ wrapper: 'Group', items: ['ShareBtn', 'SettingBtn'] },
],
center: [{ wrapper: 'Blank', items: ['BigPlayBtn'] }],
bottom: {
seekbar: ['SeekBar'],
left: [
{ wrapper: 'Group', items: ['PlayBtn', 'VolumeBtn'] },
{ wrapper: 'Group', items: ['TimeBtn'] },
],
right: [
{ wrapper: 'Group', items: ['SubtitleBtn', 'FullscreenBtn'] },
],
},
},
live: { /* ... */ },
},
mobile: {
vod: { /* ... */ },
live: { /* ... */ },
},
fullscreen: {
vod: { /* ... */ },
live: { /* ... */ },
},
breakpoint: 768,
};
export default function MyPlayer() {
return (
<VpePlayer
accessKey={'YOUR_ACCESS_KEY'}
layout={myLayout}
options={{
playlist: [{ file: 'https://CDN도메인/master.m3u8' }],
aspectRatio: '16/9',
}}
/>
);
}레이아웃 병합 동작
사용자가 전달한 layout은 디폴트 layout과 자동 병합됩니다. 일부 환경(예: pc만) 또는 일부 섹션만 정의해도 나머지는 디폴트가 사용됩니다. 단, 섹션 단위 replace 방식이므로 한 섹션을 정의하면 디폴트의 같은 섹션은 완전히 대체됩니다.
개발(__DEV__) 모드에서는 잘못된 아이템 이름, 누락된 필수 섹션 등에 대해 콘솔 경고가 출력됩니다.
터치 제스처
ControlBar는 단일/더블탭 제스처를 처리합니다. 화면을 좌/중/우 1/3 영역으로 나누어 더블탭 시 10초씩 누적 seek가 발생하며, 단일탭은 컨트롤바 토글입니다.
- 단일탭 토글은 300ms 지연 (그동안 두 번째 탭이 들어오면 더블탭으로 처리되어 컨트롤 깜빡임을 방지)
- 더블탭 좌/우 → 10초 누적 seek (500ms 후 실제 seek 실행)
options.touchGestures: false시 더블탭 비활성화 (단일탭 토글만 동작)