ใช้ตัวควบคุมการนำส่ง

สร้างแอปที่ดีขึ้นด้วย Compose
สร้าง UI ที่สวยงามด้วยโค้ดเพียงเล็กน้อยโดยใช้ Jetpack Compose สำหรับระบบปฏิบัติการ Android TV

ชุดเครื่องมือ UI ของ Leanback มีตัวควบคุมการเล่นที่ช่วยปรับปรุง ประสบการณ์ของผู้ใช้ สำหรับแอปวิดีโอ ตัวควบคุมการขนส่งจะรองรับการกรอวิดีโอ ด้วยตัวควบคุมไปข้างหน้าและย้อนกลับ ขณะกรอแสดงภาพปกเพื่อช่วยในการไปยังส่วนต่างๆ ของวิดีโอ

ไลบรารีประกอบด้วยคลาสแบบนามธรรม รวมถึงการใช้งานที่สร้างไว้ล่วงหน้าและพร้อมใช้งาน ซึ่งช่วยให้นักพัฒนาแอปควบคุมได้ละเอียดยิ่งขึ้น การใช้การติดตั้งใช้งานที่สร้างไว้ล่วงหน้า ช่วยให้คุณสร้างแอปที่มีฟีเจอร์มากมายได้อย่างรวดเร็วโดยไม่ต้องเขียนโค้ดมากนัก หากต้องการปรับแต่งเพิ่มเติม คุณสามารถขยายคอมโพเนนต์ที่สร้างไว้ล่วงหน้าของไลบรารีได้

การควบคุมและเพลเยอร์

ชุดเครื่องมือ UI ของ Leanback จะแยก UI ของตัวควบคุมการส่งออกจาก เพลเยอร์ที่เล่นวิดีโอ ซึ่งทำได้โดยใช้ 2 องค์ประกอบ ได้แก่ Fragment ที่รองรับการเล่นสำหรับแสดงตัวควบคุมการขนส่ง (และวิดีโอหากต้องการ) และอแดปเตอร์ของเพลเยอร์เพื่อห่อหุ้มมีเดียเพลเยอร์

Fragment การเล่น

กิจกรรม UI ของแอปควรใช้ PlaybackSupportFragment หรือ VideoSupportFragment ทั้ง 2 อย่างมีส่วนควบคุมการส่ง Leanback ดังนี้

  • PlaybackSupportFragment จะเคลื่อนไหวตัวควบคุมการขนส่งเพื่อซ่อน/แสดงตามต้องการ
  • VideoSupportFragment จะขยาย PlaybackSupportFragmentและมี SurfaceView เพื่อแสดงผลวิดีโอ

คุณปรับแต่ง Fragment ObjectAdapter เพื่อเพิ่มประสิทธิภาพ UI ได้ เช่น ใช้ setAdapter() เพื่อเพิ่มแถว "วิดีโอที่เกี่ยวข้อง"

PlayerAdapter

PlayerAdapter เป็นคลาสแบบนามธรรมที่ ควบคุมมีเดียเพลเยอร์พื้นฐาน นักพัฒนาแอปสามารถเลือกMediaPlayerAdapterการติดตั้งใช้งานที่สร้างไว้ล่วงหน้า หรือเขียนการติดตั้งใช้งานคลาสนี้ด้วยตนเองได้

ติดชิ้นส่วนต่างๆ เข้าด้วยกัน

คุณต้องใช้ "กาวควบคุม" เพื่อเชื่อมต่อส่วนการเล่น กับเพลเยอร์ ไลบรารี Leanback มีกาว 2 ชนิด ได้แก่

  • PlaybackBannerControlGlue จะวาด การควบคุมการขนส่งใน Fragment การเล่นใน "สไตล์เก่า" โดยวางไว้ ภายในพื้นหลังทึบแสง (PlaybackBannerControlGlue แทนที่ PlaybackControlGlue ซึ่งเลิกใช้งานแล้ว)
  • PlaybackTransportControlGlue ใช้ตัวควบคุม "รูปแบบใหม่" ที่มีพื้นหลังโปร่งใส

การเชื่อมต่อส่วนควบคุมการส่ง Leanback

หากต้องการให้แอปของคุณรองรับการกรอวิดีโอ คุณต้องใช้ PlaybackTransportControlGlue

นอกจากนี้ คุณยังต้องระบุ "โฮสต์กาว" ที่ เชื่อมโยงกาวกับ ส่วนการเล่น วาดส่วนควบคุมการส่งใน UI และรักษาสถานะของส่วนควบคุม รวมถึงส่งเหตุการณ์ส่วนควบคุมการส่งกลับไปยังกาว โฮสต์ต้องตรงกับประเภท Fragment การเล่น ใช้ PlaybackSupportFragmentGlueHost กับ PlaybackFragment และ VideoSupportFragmentGlueHost กับ VideoFragment

ภาพต่อไปนี้แสดงให้เห็นว่าชิ้นส่วนของตัวควบคุมการขนส่งในโหมด Leanback ทำงานร่วมกันอย่างไร

การเชื่อมต่อส่วนควบคุมการส่ง Leanback

โค้ดที่เชื่อมต่อแอปของคุณควรอยู่ภายใน PlaybackSupportFragment หรือ VideoSupportFragment ที่กำหนด UI

ในตัวอย่างต่อไปนี้ แอปจะสร้างอินสแตนซ์ของ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 จะได้รับการกําหนดให้กับ 2 กลุ่ม ได้แก่ การกระทําหลักและการกระทํารอง การควบคุมสำหรับกลุ่มหลักจะปรากฏเหนือแถบเลื่อน และการควบคุมสำหรับ กลุ่มรองจะปรากฏใต้แถบเลื่อน ในตอนแรกจะมีเพียงการกระทำหลักเดียว สำหรับปุ่มเล่น/หยุดชั่วคราว และไม่มีการกระทำรอง

คุณเพิ่มการกระทําลงในกลุ่มหลักและกลุ่มรองได้โดยการลบล้าง 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.
}

ในกรณีพิเศษ คุณอาจต้องการใช้ PlaybackTransportRowPresenter เพื่อแสดงผลการควบคุมที่กำหนดเองและตอบสนองต่อการดำเนินการค้นหาโดยใช้ PlaybackSeekUi

การกรอวิดีโอ

หากแอปของคุณใช้ VideoSupportFragment และคุณต้องการรองรับการกรอวิดีโอ

ขัดพื้น

คุณต้องระบุการใช้งาน PlaybackSeekDataProvider คอมโพเนนต์นี้แสดงภาพขนาดย่อของวิดีโอที่ใช้เมื่อเลื่อน คุณต้องติดตั้งใช้งานผู้ให้บริการของคุณเองโดยขยาย PlaybackSeekDataProvider ดูตัวอย่างได้ใน แอป Leanback Showcase