Dùng các phương thức điều khiển phương tiện giao thông

Tạo dựng ứng dụng hiệu quả hơn với Compose
Tạo giao diện người dùng đẹp mắt mà không cần nhiều mã nguồn bằng Jetpack Compose cho hệ điều hành Android TV.

Bộ công cụ Leanback UI có các nút điều khiển chế độ phát, giúp cải thiện trải nghiệm người dùng. Đối với các ứng dụng video, các nút điều khiển truyền tải hỗ trợ cử chỉ tua video bằng nút điều khiển tiến và lùi. Trong khi tua vào màn hình, màn hình sẽ hiện các hình thu nhỏ để giúp bạn di chuyển trong video.

Thư viện này bao gồm các lớp trừu tượng cũng như các phương thức triển khai tích hợp sẵn, tích hợp sẵn giúp nhà phát triển kiểm soát chi tiết hơn. Bằng cách sử dụng các phương thức triển khai dựng sẵn, bạn có thể nhanh chóng tạo một ứng dụng có nhiều tính năng mà không cần lập trình nhiều. Nếu cần tuỳ chỉnh thêm, bạn có thể mở rộng mọi thành phần tạo sẵn của thư viện.

Các nút điều khiển và trình phát

Bộ công cụ Leanback UI tách giao diện người dùng điều khiển truyền tải khỏi trình phát phát lại video. Quá trình này được thực hiện bằng 2 thành phần: mảnh hỗ trợ phát dùng để hiển thị các thành phần điều khiển truyền tải (và tuỳ ý là video) và bộ chuyển đổi trình phát để đóng gói trình phát nội dung đa phương tiện.

Mảnh phát

Hoạt động trên giao diện người dùng của ứng dụng nên sử dụng PlaybackSupportFragment hoặc VideoSupportFragment. Cả hai đều chứa các trình điều khiển truyền tảiLeanback:

Bạn có thể tuỳ chỉnh ObjectAdapter của một mảnh để cải thiện giao diện người dùng. Ví dụ: sử dụng setAdapter() để thêm hàng "video có liên quan".

Bộ chuyển đổi trình phát

PlayerAdapter là một lớp trừu tượng điều khiển trình phát nội dung đa phương tiện cơ bản. Nhà phát triển có thể chọn phương thức triển khai MediaPlayerAdapter tạo sẵn hoặc tự viết phương thức triển khai lớp này.

Keo các mảnh lại với nhau

Bạn phải dùng một số "keo điều khiển" để kết nối mảnh phát với trình phát. Thư viện Leanback cung cấp 2 loại keo:

  • PlaybackBannerControlGlue vẽ các thành phần điều khiển truyền tải trong mảnh phát theo "kiểu cũ", đặt các thành phần đó bên trong nền mờ. (PlaybackBannerControlGlue thay thế PlaybackControlGlue (đã ngừng hoạt động).
  • PlaybackTransportControlGlue sử dụng các chế độ điều khiển "kiểu mới" có nền trong suốt.

keo kiểm soát truyền tải Leanback

Nếu muốn ứng dụng của mình hỗ trợ lọc bỏ trong video, bạn phải sử dụng PlaybackTransportControlGlue.

Bạn cũng cần chỉ định một "máy chủ lưu trữ keo" liên kết keo với mảnh phát, vẽ các thành phần điều khiển truyền tải trong giao diện người dùng và duy trì trạng thái của các thành phần đó, đồng thời truyền các sự kiện điều khiển truyền tải trở lại keo. Máy chủ lưu trữ phải khớp với loại mảnh phát. Sử dụng PlaybackSupportFragmentGlueHost với PlaybackFragmentVideoSupportFragmentGlueHost với VideoFragment.

Dưới đây là hình minh hoạ cách các thành phần của bộ điều khiển vận chuyển Leanback kết hợp với nhau:

keo kiểm soát truyền tải Leanback

Mã gắn ứng dụng của bạn với nhau phải nằm bên trong PlaybackSupportFragment hoặc VideoSupportFragment xác định giao diện người dùng.

Trong ví dụ sau, ứng dụng tạo một thực thể của PlaybackTransportControlGlue, đặt tên thành playerGlue và kết nối VideoSupportFragment của nó với một MediaPlayerAdapter mới tạo. Vì đây là VideoSupportFragment nên mã thiết lập sẽ gọi setHost() để đính kèm VideoSupportFragmentGlueHost vào playerGlue. Mã này được đưa vào lớp mở rộng 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));
  }
}

Xin lưu ý rằng mã thiết lập cũng xác định PlayerAdapter.Callback để xử lý các sự kiện từ trình phát nội dung đa phương tiện.

Tuỳ chỉnh keo giao diện người dùng

Bạn có thể tuỳ chỉnh PlaybackBannerControlGluePlaybackTransportControlGlue để thay đổi PlaybackControlsRow.

Tuỳ chỉnh tiêu đề và nội dung mô tả

Để tuỳ chỉnh tiêu đề và nội dung mô tả ở đầu các nút điều khiển chế độ phát, hãy ghi đè 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;
}

Thêm chế độ điều khiển

Keo điều khiển hiển thị chế độ điều khiển cho các thao tác trong PlaybackControlsRow.

Các thao tác trong PlaybackControlsRow được gán cho 2 nhóm: hành động chínhhành động phụ. Các nút điều khiển của nhóm chính xuất hiện phía trên thanh tua và các chế độ điều khiển của nhóm phụ xuất hiện bên dưới thanh tua. Ban đầu, chỉ có một hành động chính duy nhất cho nút phát/tạm dừng và không có hành động phụ nào.

Bạn có thể thêm hành động vào nhóm chính và nhóm phụ bằng cách ghi đè 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);
}

Bạn phải ghi đè onActionClicked() để xử lý các thao tác mới.

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.
}

Trong các trường hợp đặc biệt, bạn nên triển khai PlaybackTransportRowPresenter của riêng mình để hiển thị các chế độ điều khiển tuỳ chỉnh và phản hồi các thao tác tìm kiếm bằng PlaybackSeekUi.

Loại bỏ video

Nếu ứng dụng của bạn dùng VideoSupportFragment và bạn muốn hỗ trợ lọc bỏ trong video.

đang chà

Bạn cần cung cấp phương thức triển khai PlaybackSeekDataProvider. Thành phần này cung cấp hình thu nhỏ video được dùng khi cuộn. Bạn phải triển khai trình cung cấp của riêng mình bằng cách mở rộng PlaybackSeekDataProvider. Xem ví dụ trong ứng dụng Leanback Showcase.