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

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

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

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

ตัวควบคุมและโปรแกรมเล่น

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

ส่วนย่อยการเล่น

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

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

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

PlayerAdapter

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

ปะติดปะต่อชิ้นส่วนเข้าด้วยกัน

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

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

leanback transport control glue

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

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

ภาพต่อไปนี้แสดงวิธีที่ตัวควบคุมการนําทางแบบ Leanback ทำงานร่วมกัน

leanback transport control glue

โค้ดที่เชื่อมโยงแอปเข้าด้วยกันควรอยู่ภายใน 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 Glue

คุณสามารถปรับแต่ง 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