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

สร้างสิ่งที่ดีขึ้นด้วย Compose
สร้าง UI ที่สวยงามด้วยโค้ดที่น้อยที่สุดโดยใช้ Jetpack Compose สำหรับ Android TV OS

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

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

ตัวควบคุมและเพลเยอร์

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

แฟรกเมนต์การเล่น

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

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

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

PlayerAdapter

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

การเชื่อมโยงส่วนต่างๆ เข้าด้วยกัน

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

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

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

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

นอกจากนี้ คุณยังต้องระบุ "โฮสต์ตัวเชื่อม" ที่ผูกตัวเชื่อมกับแฟรกเมนต์การเล่น วาดตัวควบคุมการส่งใน UI และรักษาสถานะของตัวควบคุมการส่ง รวมถึงส่งเหตุการณ์ตัวควบคุมการส่งกลับไปยังตัวเชื่อม โฮสต์ต้องตรงกับประเภทแฟรกเมนต์การเล่น ใช้ 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