UI কাস্টমাইজেশন

Media3-তে একটি ডিফল্ট PlayerView থাকে যা কিছু কাস্টমাইজেশন বিকল্প প্রদান করে।

ড্রয়েবল ওভাররাইড করা

প্লেব্যাক কন্ট্রোল ও প্রগ্রেস বার দেখাতে PlayerView, PlayerControlView ব্যবহার করে। PlayerControlView-এর ব্যবহার করা ড্রয়েবলকে আপনার অ্যাপ্লিকেশনে একই নামে সংজ্ঞায়িত ড্রয়েবল দিয়ে ওভাররাইড করা যেতে পারে। ওভাররাইড করা যায় এমন কন্ট্রোল ড্রয়েবলগুলির তালিকার জন্য PlayerControlView ডকুমেন্টেশন দেখুন।

আরও কাস্টমাইজ করার জন্য, অ্যাপ ডেভেলপারদের নিজস্ব UI কম্পোনেন্ট প্রয়োগ করতে হবে। তবে, এখানে কিছু পেশাদার পদ্ধতি দেওয়া হল যা আপনাকে শুরু করতে সাহায্য করতে পারে।

পেশাদার পদ্ধতি

Media3-এর সাথে কানেক্ট করে এমন মিডিয়া UI প্রয়োগ করার সময় Player (যেমন ExoPlayer, MediaController বা কাস্টম Player প্রয়োগ), অ্যাপগুলিকে সেরা UI অভিজ্ঞতার জন্য এইসব পেশাদার পদ্ধতি অনুসরণ করার পরামর্শ দেওয়া হয়।

চালানো/পজ করার বোতাম

চালানো ও পজ করার বোতাম সরাসরি কোনও একটি প্লেয়ারের অবস্থার সাথে সম্পর্কিত নয়। যেমন, প্লেব্যাক শেষ হয়ে গেলে বা কাজ না করলে ব্যবহারকারীকে সেটি আবার চালু করতে দিতে হবে, এমনকি প্লেয়ার পজ করা না থাকলেও এটি করতে দিতে হবে।

ইমপ্লিমেন্টেশন সহজ করতে, Media3 কোন বোতামটি দেখাবেন (Util.shouldShowPlayButton) এবং বোতাম প্রেস করা (Util.handlePlayPauseButtonAction) হ্যান্ডেল করার জন্য ইউটিল পদ্ধতি প্রদান করে:

Kotlin

val shouldShowPlayButton: Boolean = Util.shouldShowPlayButton(player)
playPauseButton.setImageDrawable(if (shouldShowPlayButton) playDrawable else pauseDrawable)
playPauseButton.setOnClickListener { Util.handlePlayPauseButtonAction(player) }

জাভা

boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
playPauseButton.setImageDrawable(shouldShowPlayButton ? playDrawable : pauseDrawable);
playPauseButton.setOnClickListener(view -> Util.handlePlayPauseButtonAction(player));

রাজ্যের আপডেট শুনুন

UI কম্পোনেন্টকে Player.Listener যোগ করতে হবে যাতে UI আপডেট করতে হলে স্ট্যাটাস পরিবর্তন সম্পর্কে জানানো যায়। বিবরণের জন্য প্লেব্যাক ইভেন্ট শুনুন দেখুন।

UI রিফ্রেশ করা ব্যয়বহুল হতে পারে এবং একাধিক প্লেয়ার ইভেন্ট প্রায়ই একসাথে আসে। কম সময়ের মধ্যে UI বারংবার রিফ্রেশ করা এড়াতে, সাধারণত শুধু onEvents শোনা এবং সেখান থেকে UI আপডেট ট্রিগার করা ভালো:

Kotlin

player.addListener(
  object : Player.Listener {
    override fun onEvents(player: Player, events: Player.Events) {
      if (
        events.containsAny(
          Player.EVENT_PLAY_WHEN_READY_CHANGED,
          Player.EVENT_PLAYBACK_STATE_CHANGED,
          Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED,
        )
      ) {
        updatePlayPauseButton()
      }
      if (events.containsAny(Player.EVENT_REPEAT_MODE_CHANGED)) {
        updateRepeatModeButton()
      }
    }
  }
)

জাভা

player.addListener(
    new Player.Listener() {
      @Override
      public void onEvents(Player player, Player.Events events) {
        if (events.containsAny(
            Player.EVENT_PLAY_WHEN_READY_CHANGED,
            Player.EVENT_PLAYBACK_STATE_CHANGED,
            Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED)) {
          updatePlayPauseButton();
        }
        if (events.containsAny(Player.EVENT_REPEAT_MODE_CHANGED)) {
          updateRepeatModeButton();
        }
      }
    });

উপলভ্য কমান্ড ম্যানেজ করা

সাধারণ উদ্দেশ্য পূরণের জন্য UI কম্পোনেন্ট যা বিভিন্ন Player ইমপ্লিমেন্টেশনের সাথে কাজ করতে পারে, সেটির উপলভ্য প্লেয়ার কমান্ড চেক করা উচিত যাতে বোতাম দেখানো বা লুকানো যায় এবং অনুপযুক্ত মেথড কল করা এড়ানো যায়:

Kotlin

nextButton.isEnabled = player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)

জাভা

nextButton.setEnabled(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT));

প্রথম ফ্রেম শাটার ও ছবি ডিসপ্লে

কোনও UI কম্পোনেন্ট ভিডিও বা ছবি দেখালে, আসল প্রথম ফ্রেম বা ছবি উপলভ্য না হওয়া পর্যন্ত এটি সাধারণত প্লেসহোল্ডার শাটার ভিউ ব্যবহার করে। এছাড়াও, ভিডিও ও ছবি একসাথে চালানোর সময়, উপযুক্ত সময়ে ছবি ভিউ লুকাতে ও দেখাতে হয়।

এইসব আপডেট ম্যানেজ করার একটি সাধারণ প্যাটার্ন হল, Player.Listener.onEvents()-এর মাধ্যমে বেছে নেওয়া ট্র্যাকের কোনও পরিবর্তন (EVENT_TRACKS_CHANGED) এবং প্রথম ভিডিও ফ্রেম রেন্ডার করা হলে (EVENT_RENDERED_FIRST_FRAME) সেই সম্পর্কে শোনা, সেইসাথে নতুন ছবি উপলভ্য হলে ImageOutput.onImageAvailable() শোনা:

Kotlin

override fun onEvents(player: Player, events: Player.Events) {
  if (events.contains(Player.EVENT_TRACKS_CHANGED)) {
    // If no video or image track: show shutter, hide image view.
    // Otherwise: do nothing to wait for first frame or image.
  }
  if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) {
    // Hide shutter, hide image view.
  }
}

override fun onImageAvailable(presentationTimeUs: Long, bitmap: Bitmap) {
  // Show shutter, set image and show image view.
}

জাভা

@Override
public void onEvents(Player player, Player.Events events) {
  if (events.contains(Player.EVENT_TRACKS_CHANGED)) {
    // If no video or image track: show shutter, hide image view.
    // Otherwise: do nothing to wait for first frame or image.
  }
  if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) {
    // Hide shutter, hide image view.
  }
}

@Override
public void onImageAvailable(long presentationTimeUs, Bitmap bitmap) {
  // Show shutter, set image and show image view.
}