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

Media3 একটি ডিফল্ট PlayerView প্রদান করে যা কিছু কাস্টমাইজেশন বিকল্প প্রদান করে। আরও কাস্টমাইজেশনের জন্য, অ্যাপ বিকাশকারীরা তাদের নিজস্ব UI উপাদানগুলি বাস্তবায়ন করবে বলে আশা করা হচ্ছে।

সর্বোত্তম অনুশীলন

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

প্লে/পজ বোতাম

প্লে এবং পজ বোতামটি সরাসরি একক প্লেয়ার স্টেটের সাথে মিলে না। উদাহরণস্বরূপ, একজন ব্যবহারকারী প্লেব্যাকটি শেষ হওয়ার পরে বা ব্যর্থ হওয়ার পরে প্লেব্যাক পুনরায় চালু করতে সক্ষম হওয়া উচিত এমনকি প্লেয়ারটিকে বিরতি দেওয়া না থাকলেও৷

বাস্তবায়ন সহজ করার জন্য, Media3 কোন বোতামটি দেখাতে হবে ( Util.shouldShowPlayButton ) এবং বোতাম টিপগুলি পরিচালনা করার জন্য ( Util.handlePlayPauseButtonAction ):

কোটলিন

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 আপডেটগুলি ট্রিগার করা সাধারণত ভাল:

কোটলিন

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 বাস্তবায়নের সাথে কাজ করার প্রয়োজন হতে পারে বোতামগুলি দেখানো বা লুকাতে এবং অসমর্থিত পদ্ধতিতে কল করা এড়াতে উপলব্ধ প্লেয়ার কমান্ডগুলি পরীক্ষা করা উচিত:

কোটলিন

nextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)

জাভা

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

প্রথম ফ্রেম শাটার এবং ইমেজ ডিসপ্লে

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

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

কোটলিন

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

,

Media3 একটি ডিফল্ট PlayerView প্রদান করে যা কিছু কাস্টমাইজেশন বিকল্প প্রদান করে। আরও কাস্টমাইজেশনের জন্য, অ্যাপ বিকাশকারীরা তাদের নিজস্ব UI উপাদানগুলি বাস্তবায়ন করবে বলে আশা করা হচ্ছে।

সর্বোত্তম অনুশীলন

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

প্লে/পজ বোতাম

প্লে এবং পজ বোতামটি সরাসরি একক প্লেয়ার স্টেটের সাথে মিলে না। উদাহরণস্বরূপ, একজন ব্যবহারকারী প্লেব্যাকটি শেষ হওয়ার পরে বা ব্যর্থ হওয়ার পরে প্লেব্যাক পুনরায় চালু করতে সক্ষম হওয়া উচিত এমনকি প্লেয়ারটিকে বিরতি দেওয়া না থাকলেও৷

বাস্তবায়ন সহজ করার জন্য, Media3 কোন বোতামটি দেখাতে হবে ( Util.shouldShowPlayButton ) এবং বোতাম টিপগুলি পরিচালনা করার জন্য ( Util.handlePlayPauseButtonAction ):

কোটলিন

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 আপডেটগুলি ট্রিগার করা সাধারণত ভাল:

কোটলিন

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 বাস্তবায়নের সাথে কাজ করার প্রয়োজন হতে পারে বোতামগুলি দেখানো বা লুকাতে এবং অসমর্থিত পদ্ধতিতে কল করা এড়াতে উপলব্ধ প্লেয়ার কমান্ডগুলি পরীক্ষা করা উচিত:

কোটলিন

nextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)

জাভা

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

প্রথম ফ্রেম শাটার এবং ইমেজ ডিসপ্লে

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

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

কোটলিন

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

,

Media3 একটি ডিফল্ট PlayerView প্রদান করে যা কিছু কাস্টমাইজেশন বিকল্প প্রদান করে। আরও কাস্টমাইজেশনের জন্য, অ্যাপ বিকাশকারীরা তাদের নিজস্ব UI উপাদানগুলি বাস্তবায়ন করবে বলে আশা করা হচ্ছে।

সর্বোত্তম অনুশীলন

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

প্লে/পজ বোতাম

প্লে এবং পজ বোতামটি সরাসরি একক প্লেয়ার স্টেটের সাথে মিলে না। উদাহরণস্বরূপ, একজন ব্যবহারকারী প্লেব্যাকটি শেষ হওয়ার পরে বা ব্যর্থ হওয়ার পরে প্লেব্যাক পুনরায় চালু করতে সক্ষম হওয়া উচিত এমনকি প্লেয়ারটিকে বিরতি দেওয়া না থাকলেও৷

বাস্তবায়ন সহজ করার জন্য, Media3 কোন বোতামটি দেখাতে হবে ( Util.shouldShowPlayButton ) এবং বোতাম টিপগুলি পরিচালনা করার জন্য ( Util.handlePlayPauseButtonAction ):

কোটলিন

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 আপডেটগুলি ট্রিগার করা সাধারণত ভাল:

কোটলিন

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 বাস্তবায়নের সাথে কাজ করার প্রয়োজন হতে পারে বোতামগুলি দেখানো বা লুকাতে এবং অসমর্থিত পদ্ধতিতে কল করা এড়াতে উপলব্ধ প্লেয়ার কমান্ডগুলি পরীক্ষা করা উচিত:

কোটলিন

nextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)

জাভা

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

প্রথম ফ্রেম শাটার এবং ইমেজ ডিসপ্লে

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

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

কোটলিন

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