overridefunonEvents(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.}}overridefunonImageAvailable(presentationTimeUs:Long,bitmap:Bitmap){// Show shutter, set image and show image view.}
Java
@OverridepublicvoidonEvents(Playerplayer,Eventsevents){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.}}@OverridepublicvoidonImageAvailable(longpresentationTimeUs,Bitmapbitmap){// Show shutter, set image and show image view.}
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-08-27 UTC。"],[],[],null,["Media3 provides a default [`PlayerView`](/guide/topics/media/ui/playerview) that provides some customization\noptions.\n\nOverride drawables **Caution:** We don't guarantee that the customizations described in the following section will continue to work in future versions of the library. The resource IDs may change name, or some may be deleted entirely. This is indicated by the [resource IDs being marked 'private'](/studio/projects/android-library#PrivateResources).\n\n`PlayerView` uses `PlayerControlView` to display the playback controls and\nprogress bar. The drawables used by `PlayerControlView` can be overridden by\ndrawables with the same names defined in your application. See the\n[`PlayerControlView`](/reference/androidx/media3/ui/PlayerControlView) documentation for a list of control drawables that can\nbe overridden.\n\nFor any further customization, app developers are expected to implement their\nown UI components. However, here are some best practices that can help you get\nstarted.\n\nBest practices\n\nWhen implementing a media UI that connects to a Media3 `Player` (for example\n`ExoPlayer`, `MediaController` or a custom `Player` implementation), apps are\nadvised to follow these best practices for the best UI experience.\n\nPlay/Pause button\n\nThe play and pause button does not directly correspond to a single player state.\nFor example, a user should be able to restart playback after it ended or failed\neven if the player isn't paused.\n\nTo simplify the implementation, Media3 provides util methods to decide which\nbutton to show (`Util.shouldShowPlayButton`) and to handle button presses\n(`Util.handlePlayPauseButtonAction`): \n\nKotlin \n\n```kotlin\nval shouldShowPlayButton: Boolean = Util.shouldShowPlayButton(player)\nplayPauseButton.setImageDrawable(if (shouldShowPlayButton) playDrawable else pauseDrawable)\nplayPauseButton.setOnClickListener { Util.handlePlayPauseButtonAction(player) }\n```\n\nJava \n\n```java\nboolean shouldShowPlayButton = Util.shouldShowPlayButton(player);\nplayPauseButton.setImageDrawable(shouldShowPlayButton ? playDrawable : pauseDrawable);\nplayPauseButton.setOnClickListener(view -\u003e Util.handlePlayPauseButtonAction(player));\n```\n\n\u003cbr /\u003e\n\nListen to state updates\n\nThe UI component needs to add a `Player.Listener` to be informed of state\nchanges that require a corresponding UI update. See [Listen to playback\nevents](/guide/topics/media/exoplayer/listening-to-player-events) for details.\n\nRefreshing the UI can be costly and multiple player events often arrive\ntogether. To avoid refreshing the UI too often in a short period of time, it's\ngenerally better to listen to just `onEvents` and trigger UI updates from there: \n\nKotlin \n\n```kotlin\nplayer.addListener(object : Player.Listener{\n override fun onEvents(player: Player, events: Player.Events){\n if (events.containsAny(\n Player.EVENT_PLAY_WHEN_READY_CHANGED,\n Player.EVENT_PLAYBACK_STATE_CHANGED,\n Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED)) {\n updatePlayPauseButton()\n }\n if (events.containsAny(Player.EVENT_REPEAT_MODE_CHANGED)) {\n updateRepeatModeButton()\n }\n }\n})\n```\n\nJava \n\n```java\nplayer.addListener(new Player.Listener() {\n @Override\n public void onEvents(Player player, Player.Events events) {\n if (events.containsAny(\n Player.EVENT_PLAY_WHEN_READY_CHANGED,\n Player.EVENT_PLAYBACK_STATE_CHANGED,\n Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED)) {\n updatePlayPauseButton();\n }\n if (events.containsAny(Player.EVENT_REPEAT_MODE_CHANGED)) {\n updateRepeatModeButton();\n }\n }\n});\n```\n\n\u003cbr /\u003e\n\nHandle available commands\n\nA general purpose UI component that may need to work with different `Player`\nimplementations should check the available player commands to show or hide\nbuttons and to avoid calling unsupported methods: \n\nKotlin \n\n```kotlin\nnextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)\n```\n\nJava \n\n```java\nnextButton.setEnabled(player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT));\n```\n\n\u003cbr /\u003e\n\nFirst frame shutter and image display\n\nWhen a UI component displays video or images, it typically uses a placeholder\nshutter view until the real first frame or image is available. In addition,\nmixed video and image playback requires to hide and show the image view at\nappropriate times.\n\nA common pattern to handle these updates is to listen to\n[`Player.Listener.onEvents()`](/reference/androidx/media3/exoplayer/Player.Listener#onEvents(androidx.media3.exoplayer.Player,%20androidx.media3.exoplayer.Player.Events)) for any change in selected tracks\n(`EVENT_TRACKS_CHANGED`) and for when the first video frame has been rendered\n(`EVENT_RENDERED_FIRST_FRAME`), as well as [`ImageOutput.onImageAvailable()`](/reference/androidx/media3/ui/ImageOutput#onImageAvailable(long,%20android.graphics.Bitmap))\nfor when a new image is available: \n\nKotlin \n\n```kotlin\noverride fun onEvents(player: Player, events: Player.Events) {\n if (events.contains(Player.EVENT_TRACKS_CHANGED)) {\n // If no video or image track: show shutter, hide image view.\n // Otherwise: do nothing to wait for first frame or image.\n }\n if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) {\n // Hide shutter, hide image view.\n }\n}\n\noverride fun onImageAvailable(presentationTimeUs: Long, bitmap: Bitmap) {\n // Show shutter, set image and show image view.\n}\n```\n\nJava \n\n```java\n@Override\npublic void onEvents(Player player, Events events) {\n if (events.contains(Player.EVENT_TRACKS_CHANGED)) {\n // If no video or image track: show shutter, hide image view.\n // Otherwise: do nothing to wait for first frame or image.\n }\n if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) {\n // Hide shutter, hide image view.\n }\n}\n\n@Override\npublic void onImageAvailable(long presentationTimeUs, Bitmap bitmap) {\n // Show shutter, set image and show image view.\n}\n```\n\n\u003cbr /\u003e"]]