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 bằng Compose
Tạo giao diện người dùng đẹp mắt với mã tối thiểu bằng Jetpack Compose cho hệ điều hành Android TV.

Bộ công cụ giao diện người dùng Leanback có các chế độ kiểm soát 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ợ tính năng tua video bằng các nút điều khiển tua đi và tua lại. Trong khi bạn kéo dấu chấm tua, màn hình sẽ hiển thị hình thu nhỏ để giúp bạn di chuyển qua 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 dựng sẵn, có sẵn, giúp nhà phát triển có quyề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 được tạo sẵn, bạn có thể nhanh chóng tạo một ứng dụng già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 bất kỳ thành phần dựng sẵn nào của thư viện.

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

Bộ công cụ giao diện người dùng Leanback tách giao diện người dùng của các nút điều khiển truyền dữ liệu khỏi trình phát phát video. Điều này được thực hiện bằng 2 thành phần: phân đoạn hỗ trợ phát lại để hiển thị các nút điều khiển thao tác (và video nếu muốn) và bộ chuyển đổi trình phát để đóng gói một trình phát nội dung nghe nhìn.

Đoạn phát

Hoạt động giao diện người dùng của ứng dụng phải sử dụng PlaybackSupportFragment hoặc VideoSupportFragment. Cả hai đều có nút điều khiển truyền Leanback:

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 một hàng "video có liên quan".

PlayerAdapter

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

Dán các mảnh lại với nhau

Bạn phải sử dụng một số "control glue" để kết nối đoạn phát với trình phát. Thư viện leanback cung cấp 2 loại lớp kết dính:

  • PlaybackBannerControlGlue vẽ các nút điều khiển thao tác phát trong mảnh phát theo "kiểu cũ", đặt các nút này bên trong một nền mờ. (PlaybackBannerControlGlue thay thế PlaybackControlGlue, phương thức này đã không còn được dùng.)
  • PlaybackTransportControlGlue sử dụng các chế độ kiểm soát "kiểu mới" có nền trong suốt.

keo dán nút điều khiển truyền Leanback

Nếu muốn ứng dụng của mình hỗ trợ tính năng tua video, bạn phải sử dụng PlaybackTransportControlGlue.

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

Sau đây là hình minh hoạ cho thấy cách các thành phần của chế độ điều khiển phương tiện ở chế độ xem lớn kết hợp với nhau:

keo dán nút điều khiển truyền Leanback

Mã kết dính ứng dụng của bạn phải nằm trong PlaybackSupportFragment hoặc VideoSupportFragment xác định giao diện người dùng.

Trong ví dụ sau, ứng dụng sẽ tạo một thực thể PlaybackTransportControlGlue, đặt tên là playerGlue và kết nối VideoSupportFragment với 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 bên trong 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 một PlayerAdapter.Callback để xử lý các sự kiện từ trình phát nội dung nghe nhìn.

Tuỳ chỉnh lớp kết dính 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 chế độ điều khiển 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ế độ kiểm soát

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

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

Bạn có thể thêm các thao tác 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 những trường hợp đặc biệt, bạn có thể muốn triển khai PlaybackTransportRowPresenter của riêng mình để kết xuất các chế độ kiểm soát tuỳ chỉnh và phản hồi các thao tác tìm kiếm bằng cách sử dụng PlaybackSeekUi.

Thao tác tua video

Nếu ứng dụng của bạn dùng VideoSupportFragment và bạn muốn hỗ trợ tính năng tua video.

tua

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