از کنترل های حمل و نقل استفاده کنید

با Compose بهتر بسازید
با استفاده از Jetpack Compose برای سیستم عامل Android TV، رابط‌های کاربری زیبا با حداقل کد ایجاد کنید.

جعبه ابزار Leanback UI دارای کنترل‌های بازپخش است که تجربه کاربری بهتری را ارائه می‌دهد. برای برنامه‌های ویدیویی، کنترل‌های حمل و نقل از تمیز کردن ویدیو با کنترل‌های جلو و عقب پشتیبانی می‌کنند. هنگام تمیز کردن صفحه نمایش، تصاویر کوچکی را نشان می دهد تا به حرکت در ویدیو کمک کند.

این کتابخانه شامل کلاس های انتزاعی و همچنین پیاده سازی های از پیش ساخته شده ای است که کنترل دقیق تری را برای توسعه دهندگان فراهم می کند. با استفاده از پیاده سازی های از پیش ساخته شده، می توانید به سرعت یک برنامه غنی از ویژگی ها را بدون کدنویسی زیاد بسازید. اگر به سفارشی سازی بیشتری نیاز دارید، می توانید هر یک از اجزای از پیش ساخته شده کتابخانه را گسترش دهید.

کنترل و پخش کننده

جعبه ابزار Leanback UI رابط کنترل های حمل و نقل را از پخش کننده ای که ویدیو را پخش می کند جدا می کند. این کار با دو جزء انجام می شود: یک قطعه پشتیبانی از پخش برای نمایش کنترل های حمل و نقل (و در صورت اختیاری ویدیو) و یک آداپتور پخش کننده برای محصور کردن یک پخش کننده رسانه.

قطعه پخش

فعالیت رابط کاربری برنامه شما باید از PlaybackSupportFragment یا VideoSupportFragment استفاده کند. هر دو شامل کنترل‌های حمل و نقل لیانبک هستند:

  • یک PlaybackSupportFragment کنترل های حمل و نقل خود را متحرک می کند تا در صورت لزوم آنها را پنهان یا نشان دهد.
  • یک VideoSupportFragment PlaybackSupportFragment را گسترش می‌دهد و یک SurfaceView برای ارائه ویدیو دارد.

می‌توانید ObjectAdapter یک قطعه را برای بهبود رابط کاربری سفارشی کنید. برای مثال، از setAdapter() برای افزودن ردیف «ویدیوهای مرتبط» استفاده کنید.

Player Adapter

PlayerAdapter یک کلاس انتزاعی است که پخش کننده رسانه زیرین را کنترل می کند. توسعه دهندگان می توانند پیاده سازی MediaPlayerAdapter از پیش ساخته شده را انتخاب کنند یا پیاده سازی خود را از این کلاس بنویسند.

چسباندن قطعات به هم

شما باید از مقداری "چسب کنترل" برای اتصال قطعه پخش به پخش کننده استفاده کنید. کتابخانه leanback دو نوع چسب ارائه می دهد:

  • PlaybackBannerControlGlue کنترل‌های انتقال را در قطعه پخش به سبک قدیمی ترسیم می‌کند و آنها را در یک پس‌زمینه مات قرار می‌دهد. ( PlaybackBannerControlGlue جایگزین PlaybackControlGlue می شود که منسوخ شده است.)
  • PlaybackTransportControlGlue از کنترل‌های «سبک جدید» با پس‌زمینه شفاف استفاده می‌کند.

چسب کنترل حمل و نقل leanback

اگر می‌خواهید برنامه شما از تمیز کردن ویدیو پشتیبانی کند، باید از PlaybackTransportControlGlue استفاده کنید.

همچنین باید یک "میزبان چسب" مشخص کنید که چسب را به قطعه پخش متصل می کند، کنترل های انتقال را در رابط کاربری ترسیم می کند و حالت آنها را حفظ می کند، و رویدادهای کنترل حمل و نقل را به چسب منتقل می کند. میزبان باید با نوع قطعه پخش مطابقت داشته باشد. از PlaybackSupportFragmentGlueHost با PlaybackFragment و VideoSupportFragmentGlueHost با VideoFragment استفاده کنید.

در اینجا تصویری وجود دارد که نشان می‌دهد چگونه قطعات یک کنترل حمل‌ونقل پشتی با هم قرار می‌گیرند:

چسب کنترل حمل و نقل leanback

کدی که برنامه شما را به هم می چسباند باید در PlaybackSupportFragment یا VideoSupportFragment باشد که رابط کاربری را تعریف می کند.

در مثال زیر، برنامه یک نمونه از PlaybackTransportControlGlue می سازد و نام آن را playerGlue می گذارد و VideoSupportFragment خود را به MediaPlayerAdapter تازه ایجاد شده متصل می کند. از آنجایی که این یک VideoSupportFragment است، کد راه‌اندازی setHost() را فراخوانی می‌کند تا یک VideoSupportFragmentGlueHost را به playerGlue متصل کند. کد داخل کلاسی که VideoSupportFragment را گسترش می‌دهد گنجانده شده است.

کاتلین

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

جاوا

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() را لغو کنید:

کاتلین

override fun onCreateRowPresenter(): PlaybackRowPresenter {
    return super.onCreateRowPresenter().apply {
        (this as? PlaybackTransportRowPresenter)
                ?.setDescriptionPresenter(MyCustomDescriptionPresenter())
    }
}

جاوا

@Override
protected PlaybackRowPresenter onCreateRowPresenter() {
  PlaybackTransportRowPresenter presenter = (PlaybackTransportRowPresenter) super.onCreateRowPresenter();
  presenter.setDescriptionPresenter(new MyCustomDescriptionPresenter());
  return presenter;
}

اضافه کردن کنترل ها

چسب کنترل، کنترل‌های اعمال را در PlaybackControlsRow نمایش می‌دهد.

اقدامات موجود در PlaybackControlsRow به دو گروه اختصاص داده می شوند: اقدامات اولیه و اقدامات ثانویه . کنترل‌های گروه اصلی در بالای نوار جستجو و کنترل‌های گروه ثانویه در زیر نوار جستجو ظاهر می‌شوند. در ابتدا، تنها یک اکشن اصلی برای دکمه پخش/مکث وجود دارد و هیچ اقدام ثانویه وجود ندارد.

می‌توانید با نادیده گرفتن onCreatePrimaryActions() و onCreateSecondaryActions() اقداماتی را به گروه‌های اولیه و ثانویه اضافه کنید.

کاتلین

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

جاوا

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() را لغو کنید.

کاتلین

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

جاوا

@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 ببینید. .