Leanback UI 도구 키트에는 개선된 사용자 환경을 제공하는 재생 컨트롤이 있습니다. 동영상 앱의 경우 전송 컨트롤은 앞으로 및 뒤로 컨트롤로 동영상 스크러빙을 지원합니다. 스크러빙하는 동안 디스플레이에는 동영상을 탐색하는 데 도움이 되는 썸네일이 표시됩니다.
라이브러리에는 추상 클래스뿐만 아니라 개발자에게 더 세부적인 제어를 제공하는 사전 빌드된 즉시 사용 가능한 구현이 포함되어 있습니다. 사전 빌드된 구현을 사용하면 코딩을 많이 하지 않고도 기능이 풍부한 앱을 빠르게 빌드할 수 있습니다. 추가 맞춤설정이 필요한 경우 라이브러리의 미리 빌드된 구성요소를 확장하면 됩니다.
컨트롤 및 플레이어
Leanback UI 툴킷은 전송 컨트롤 UI를 동영상을 재생하는 플레이어와 분리합니다. 이 작업은 전송 컨트롤 (및 선택적으로 동영상)을 표시하기 위한 재생 지원 프래그먼트와 미디어 플레이어를 캡슐화하는 플레이어 어댑터, 이렇게 두 가지 구성요소를 사용하여 실행됩니다.
재생 프래그먼트
앱의 UI 활동은 PlaybackSupportFragment
또는 VideoSupportFragment
를 사용해야 합니다.
둘 다 leanback 전송 컨트롤을 포함하고 있습니다.
PlaybackSupportFragment
는 전송 컨트롤을 애니메이션 처리하여 필요에 따라 숨기거나 표시합니다.VideoSupportFragment
는PlaybackSupportFragment
를 확장하고, 동영상을 렌더링하는SurfaceView
를 포함합니다.
프래그먼트의 ObjectAdapter
를 맞춤설정하여 UI를 개선할 수 있습니다. 예를 들어 setAdapter()
를 사용하여 '관련 동영상' 행을 추가할 수 있습니다.
PlayerAdapter
PlayerAdapter
는 기본 미디어 플레이어를 제어하는 추상 클래스입니다. 개발자는 사전 빌드된 MediaPlayerAdapter
구현을 선택하거나 이 클래스의 구현을 직접 작성할 수 있습니다.
요소 연결
'컨트롤 글루'를 사용하여 재생 프래그먼트를 플레이어에 연결해야 합니다. Leanback 라이브러리는 두 가지 종류의 접착제를 제공합니다.
PlaybackBannerControlGlue
는 재생 프래그먼트에서 '이전 스타일'의 전송 컨트롤을 가져와 불투명한 배경 내에 배치합니다. (PlaybackBannerControlGlue
은 지원 중단된PlaybackControlGlue
를 대체합니다.)PlaybackTransportControlGlue
는 투명한 배경과 함께 '새로운 스타일' 컨트롤을 사용합니다.
앱에서 동영상 스크러빙을 지원하려면 PlaybackTransportControlGlue
를 사용해야 합니다.
또한 글루를 재생 프래그먼트에 바인딩하고, UI의 전송 컨트롤을 그리고 컨트롤의 상태를 유지하고, 전송 컨트롤 이벤트를 다시 글루에 전달하는 '글루 호스트'도 지정해야 합니다. 이 호스트는 재생 프래그먼트 유형과 일치해야 합니다. PlaybackSupportFragmentGlueHost
를 PlaybackFragment
와 함께 사용하고 VideoSupportFragmentGlueHost
를 VideoFragment
와 함께 사용합니다.
다음 그림은 leanback 전송 컨트롤의 요소가 어떻게 조화를 이루는지 보여줍니다.
앱을 결합하는 코드는 UI를 정의하는 PlaybackSupportFragment
또는 VideoSupportFragment
내에 있어야 합니다.
다음 예에서 앱은 PlaybackTransportControlGlue
의 인스턴스를 생성하고 이름을 playerGlue
로 지정하고 VideoSupportFragment
를 새로 만든 MediaPlayerAdapter
에 연결합니다. VideoSupportFragment
이므로 설정 코드는 setHost()
를 호출하여 VideoSupportFragmentGlueHost
를 playerGlue
에 연결합니다. 이 코드는 VideoSupportFragment
를 확장하는 클래스 내에 포함되어 있습니다.
Kotlin
class MyVideoFragment : VideoSupportFragment() { fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) val playerGlue = PlaybackTransportControlGlue(getActivity(), MediaPlayerAdapter(getActivity())) playerGlue.setHost(VideoSupportFragmentGlueHost(this)) playerGlue.addPlayerCallback(object : PlaybackGlue.PlayerCallback() { override fun onPreparedStateChanged(glue: PlaybackGlue) { if (glue.isPrepared()) { playerGlue.seekProvider = MySeekProvider() playerGlue.play() } } }) playerGlue.setSubtitle("Leanback artist") playerGlue.setTitle("Leanback team at work") val uriPath = "android.resource://com.example.android.leanback/raw/video" playerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath)) } }
Java
public class MyVideoFragment extends VideoSupportFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final PlaybackTransportControlGlue<MediaPlayerAdapter> playerGlue = new PlaybackTransportControlGlue(getActivity(), new MediaPlayerAdapter(getActivity())); playerGlue.setHost(new VideoSupportFragmentGlueHost(this)); playerGlue.addPlayerCallback(new PlaybackGlue.PlayerCallback() { @Override public void onPreparedStateChanged(PlaybackGlue glue) { if (glue.isPrepared()) { playerGlue.setSeekProvider(new MySeekProvider()); playerGlue.play(); } } }); playerGlue.setSubtitle("Leanback artist"); playerGlue.setTitle("Leanback team at work"); String uriPath = "android.resource://com.example.android.leanback/raw/video"; playerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath)); } }
설정 코드는 미디어 플레이어의 이벤트를 처리하기 위해 PlayerAdapter.Callback
도 정의합니다.
UI 글루 맞춤설정
PlaybackBannerControlGlue
및 PlaybackTransportControlGlue
를 맞춤설정하여 PlaybackControlsRow
를 변경할 수 있습니다.
제목과 설명 맞춤설명
재생 컨트롤 상단의 제목과 설명을 맞춤설정하려면 onCreateRowPresenter()
를 재정의합니다.
Kotlin
override fun onCreateRowPresenter(): PlaybackRowPresenter { return super.onCreateRowPresenter().apply { (this as? PlaybackTransportRowPresenter) ?.setDescriptionPresenter(MyCustomDescriptionPresenter()) } }
Java
@Override protected PlaybackRowPresenter onCreateRowPresenter() { PlaybackTransportRowPresenter presenter = (PlaybackTransportRowPresenter) super.onCreateRowPresenter(); presenter.setDescriptionPresenter(new MyCustomDescriptionPresenter()); return presenter; }
컨트롤 추가
컨트롤 글루에서는 PlaybackControlsRow
에 작업 컨트롤을 표시합니다.
PlaybackControlsRow
의 작업은 두 그룹, 즉 기본 작업과 보조 작업에 할당됩니다. 기본 그룹용 컨트롤은 탐색바 위에 표시되고 보조 그룹용 컨트롤은 탐색바 아래에 표시됩니다. 처음에는 재생/일시중지 버튼의 기본 작업이 하나만 있고 보조 작업은 없습니다.
onCreatePrimaryActions()
와 onCreateSecondaryActions()
를 재정의하여 기본 그룹과 보조 그룹에 작업을 추가할 수 있습니다.
Kotlin
private lateinit var repeatAction: PlaybackControlsRow.RepeatAction private lateinit var pipAction: PlaybackControlsRow.PictureInPictureAction private lateinit var thumbsUpAction: PlaybackControlsRow.ThumbsUpAction private lateinit var thumbsDownAction: PlaybackControlsRow.ThumbsDownAction private lateinit var skipPreviousAction: PlaybackControlsRow.SkipPreviousAction private lateinit var skipNextAction: PlaybackControlsRow.SkipNextAction private lateinit var fastForwardAction: PlaybackControlsRow.FastForwardAction private lateinit var rewindAction: PlaybackControlsRow.RewindAction override fun onCreatePrimaryActions(primaryActionsAdapter: ArrayObjectAdapter) { // Order matters, super.onCreatePrimaryActions() will create the play / pause action. // Will display as follows: // play/pause, previous, rewind, fast forward, next // > /|| |< << >> >| super.onCreatePrimaryActions(primaryActionsAdapter) primaryActionsAdapter.apply { add(skipPreviousAction) add(rewindAction) add(fastForwardAction) add(skipNextAction) } } override fun onCreateSecondaryActions(adapter: ArrayObjectAdapter?) { super.onCreateSecondaryActions(adapter) adapter?.apply { add(thumbsDownAction) add(thumbsUpAction) } }
Java
private PlaybackControlsRow.RepeatAction repeatAction; private PlaybackControlsRow.PictureInPictureAction pipAction; private PlaybackControlsRow.ThumbsUpAction thumbsUpAction; private PlaybackControlsRow.ThumbsDownAction thumbsDownAction; private PlaybackControlsRow.SkipPreviousAction skipPreviousAction; private PlaybackControlsRow.SkipNextAction skipNextAction; private PlaybackControlsRow.FastForwardAction fastForwardAction; private PlaybackControlsRow.RewindAction rewindAction; @Override protected void onCreatePrimaryActions(ArrayObjectAdapter primaryActionsAdapter) { // Order matters, super.onCreatePrimaryActions() will create the play / pause action. // Will display as follows: // play/pause, previous, rewind, fast forward, next // > /|| |< << >> >| super.onCreatePrimaryActions(primaryActionsAdapter); primaryActionsAdapter.add(skipPreviousAction); primaryActionsAdapter.add(rewindAction); primaryActionsAdapter.add(fastForwardAction); primaryActionsAdapter.add(skipNextAction); } @Override protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) { super.onCreateSecondaryActions(adapter); adapter.add(thumbsDownAction); adapter.add(thumbsUpAction); }
새 작업을 처리하려면 onActionClicked()
를 재정의해야 합니다.
Kotlin
override fun onActionClicked(action: Action) { when(action) { rewindAction -> { // Handle Rewind } fastForwardAction -> { // Handle FastForward } thumbsDownAction -> { // Handle ThumbsDown } thumbsUpAction -> { // Handle ThumbsUp } else -> // The superclass handles play/pause and delegates next/previous actions to abstract methods, // so those two methods should be overridden rather than handling the actions here. super.onActionClicked(action) } } override fun next() { // Skip to next item in playlist. } override fun previous() { // Skip to previous item in playlist. }
Java
@Override public void onActionClicked(Action action) { if (action == rewindAction) { // Handle Rewind } else if (action == fastForwardAction ) { // Handle FastForward } else if (action == thumbsDownAction) { // Handle ThumbsDown } else if (action == thumbsUpAction) { // Handle ThumbsUp } else { // The superclass handles play/pause and delegates next/previous actions to abstract methods, // so those two methods should be overridden rather than handling the actions here. super.onActionClicked(action); } } @Override public void next() { // Skip to next item in playlist. } @Override public void previous() { // Skip to previous item in playlist. }
특별한 경우에는 PlaybackSeekUi
를 사용하여 맞춤 컨트롤을 렌더링하고 탐색 작업에 응답하도록 자체 PlaybackTransportRowPresenter
를 구현하는 것이 좋습니다.
동영상 스크러빙
앱에서 VideoSupportFragment
를 사용하며 동영상 스크러빙을 지원하려는 경우
PlaybackSeekDataProvider
구현을 제공해야 합니다.
이 구성요소는 스크롤할 때 사용되는 동영상 미리보기 이미지를 제공합니다.
PlaybackSeekDataProvider
를 확장하여 자체 제공자를 구현해야 합니다.
Leanback 쇼케이스 앱에서 예를 참고하세요.