레이아웃 시스템

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 거치지 않음)
SettingBtnSettingsMenu 토글 (화질/재생속도/자막)
PrevBtn이전 트랙
NextBtn다음 트랙
NextPrevBtn이전/다음 통합 버튼
BackBtn뒤로가기. events.backPress 호출
ShareBtnReact Native Share API 호출
SkipForwardBtn10초 앞으로 이동
SkipBackBtn10초 뒤로 이동
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 시 더블탭 비활성화 (단일탭 토글만 동작)

관련 가이드

React Native