You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExoPlayer开发:如何为自定义布局按钮添加OnClickListener

ExoPlayer 自定义按钮点击事件绑定实现(Kotlin + DataBinding)

以下两种方案都可以实现,根据你的项目习惯选即可:


方案1:纯DataBinding绑定写法(推荐,代码更解耦)

第一步:调整布局配置

  1. 首先确保你的Activity根布局用<layout>标签包裹,声明DataBinding需要的变量
  2. 如果你把自定义按钮放在ExoPlayer自定义控制器布局(即PlayerView的app:controller_layout_id指向的布局)里,这个控制器布局也需要用<layout>标签包裹,否则DataBinding不生效
  3. 给自定义按钮直接在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:06:09