ExoPlayer开发:如何为自定义布局按钮添加OnClickListener
ExoPlayer 自定义按钮点击事件绑定实现(Kotlin + DataBinding)
以下两种方案都可以实现,根据你的项目习惯选即可:
方案1:纯DataBinding绑定写法(推荐,代码更解耦)
第一步:调整布局配置
- 首先确保你的Activity根布局用
<layout>标签包裹,声明DataBinding需要的变量 - 如果你把自定义按钮放在ExoPlayer自定义控制器布局(即
PlayerView的app:controller_layout_id指向的布局)里,这个控制器布局也需要用<layout>标签包裹,否则DataBinding不生效 - 给自定义按钮直接在xml里绑定点击回调
布局代码示例:
<!-- Activity主布局 --> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="playerAct" type="你的应用包名.PlayerActivity" /> </data> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.exoplayer2.ui.PlayerView android:id="@+id/player_view" android:layout_width="match_parent" android:layout_height="match_parent" app:controller_layout_id="@layout/custom_exo_controller"/> </FrameLayout> </layout>
<!-- 自定义控制器布局 custom_exo_controller.xml 示例,新增倍速按钮 --> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="#80000000"> <!-- 保留系统自带控制按钮,新增自定义按钮 --> <ImageButton android:id="@+id/btn_play_speed" android:layout_width="48dp" android:layout_height="48dp" android:layout_gravity="center_vertical|start" android:layout_marginStart="16dp" android:src="@drawable/ic_speed" android:background="?attr/selectableItemBackgroundBorderless" android:onClick="@{() -> playerAct.onSpeedClick()}" /> <!-- 其他原有控制控件... --> </FrameLayout> </layout>
第二步:Activity里实现绑定和逻辑
class PlayerActivity : AppCompatActivity() { private lateinit var binding: ActivityPlayerBinding private var exoPlayer: ExoPlayer? = null private var currentSpeed = 1f override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_player) // 必须给布局里声明的变量赋值,否则绑定失效 binding.playerAct = this binding.lifecycleOwner = this // 正常初始化ExoPlayer exoPlayer = ExoPlayer.Builder(this).build().also { binding.playerView.player = it // 自行添加媒体源准备、播放逻辑 } } // 自定义按钮点击逻辑直接写在这里,可直接操作ExoPlayer实例 fun onSpeedClick() { currentSpeed = when(currentSpeed) { 1f -> 1.5f 1.5f -> 2f else -> 1f } // 调用ExoPlayer API修改播放参数 exoPlayer?.playbackParameters = PlaybackParameters(currentSpeed) Toast.makeText(this, "当前倍速:${currentSpeed}x", Toast.LENGTH_SHORT).show() } override fun onDestroy() { super.onDestroy() exoPlayer?.release() exoPlayer = null } }
方案2:代码直接设置点击监听(适合少量按钮,不用改多层DataBinding配置)
如果不想给控制器布局单独开DataBinding,可以直接在代码里找到自定义按钮设置监听,注意要等控制器布局加载完成再找控件,不然会返回null:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_player) // 初始化ExoPlayer逻辑不变... // 等PlayerView的控制器布局加载完成再找控件 binding.playerView.post { val speedBtn = binding.playerView.findViewById<ImageButton>(R.id.btn_play_speed) speedBtn.setOnClickListener { // 点击逻辑直接写在这里,和普通按钮没有区别 currentSpeed = when(currentSpeed) { 1f -> 1.5f 1.5f -> 2f else -> 1f } exoPlayer?.playbackParameters = PlaybackParameters(currentSpeed) } } }
常见踩坑点
- 不要直接在Activity的binding里拿控制器布局的控件id,因为控制器布局是inflate到PlayerView内部的,不在Activity直接绑定的视图层级里,必须通过
playerView.findViewById()找 - 如果点击事件触发后操作ExoPlayer空指针,先检查播放器初始化时机、是否在页面销毁时已经release
- 如果要做按钮状态联动(比如倍速选中态、字幕开关态),建议把状态存在ViewModel里用LiveData观察,和普通DataBinding绑定UI的写法完全一致
内容的提问来源于stack exchange,提问作者user16238776
相关产品推荐
相关产品推荐

