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

如何自定义监听器实现ExoPlayer UI控件仅在onTouch触发时显示?

实现ExoPlayer仅在Touch事件触发时显示播放控制器

我来给你分享两种可行的实现方案,帮你定制ExoPlayer的控制器显示逻辑,满足「仅在Touch事件触发时才显示控件」的需求:

方案一:继承PlayerControlView修改默认行为

默认的PlayerControlView会在点击、长按、拖拽等交互时自动显示控制器,我们可以通过继承它并重写相关方法,拦截不需要的触发逻辑,只保留Touch事件的显示触发:

步骤1:创建自定义PlayerControlView子类

public class TouchOnlyControlView extends PlayerControlView {

    public TouchOnlyControlView(Context context) {
        super(context);
        initView();
    }

    public TouchOnlyControlView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public TouchOnlyControlView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        // 禁用默认的点击/长按触发显示逻辑
        setOnClickListener(v -> {});
        setOnLongClickListener(v -> true);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 仅在触摸按下(ACTION_DOWN)时显示控制器
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            show(); // 调用父类的显示方法
        }
        // 拦截后续事件,避免触发默认的点击/拖拽显示逻辑
        return true;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        // 拦截进度条拖拽的默认显示触发
        SeekBar progressBar = findViewById(R.id.exo_progress);
        if (progressBar != null) {
            progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    if (fromUser) {
                        // 仅处理进度更新,不触发控制器显示
                        getPlayer().seekTo((getPlayer().getDuration() * progress) / 100);
                    }
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                    // 空实现,避免触发默认的显示逻辑
                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    // 空实现,或添加自定义逻辑
                }
            });
        }
    }
}

步骤2:在布局中使用自定义控件

把布局里的com.google.android.exoplayer2.ui.PlayerControlView替换成你的自定义类:

<com.yourpackage.TouchOnlyControlView
    android:id="@+id/player_control_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:player_layout_id="@layout/exo_player_view"/>

步骤3:绑定播放器

在代码中把播放器和自定义控制器绑定:

SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build();
TouchOnlyControlView controlView = findViewById(R.id.player_control_view);
controlView.setPlayer(player);

方案二:完全自定义控制器布局(更灵活)

如果你想要完全掌控控制器的显示/隐藏逻辑,可以自己写控制器布局,手动处理触摸事件和播放器控制:

步骤1:创建自定义控制器布局

比如custom_player_control.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_control_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp"
    android:background="#80000000"
    android:visibility="gone"> <!-- 默认隐藏 -->

    <ImageButton
        android:id="@+id/play_pause_btn"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:src="@drawable/exo_icon_play"/>

    <SeekBar
        android:id="@+id/progress_seek_bar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginHorizontal="16dp"/>

    <!-- 其他控件比如音量、全屏按钮等 -->
</LinearLayout>

步骤2:在PlayerView布局中引入该控制器

<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_player_control"/>

步骤3:在代码中处理触摸和控制逻辑

PlayerView playerView = findViewById(R.id.player_view);
LinearLayout controlLayout = findViewById(R.id.custom_control_layout);
SimpleExoPlayer player = new SimpleExoPlayer.Builder(this).build();
playerView.setPlayer(player);

// 播放器视图的触摸监听:仅在触摸按下时显示控制器
playerView.setOnTouchListener((v, event) -> {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        controlLayout.setVisibility(View.VISIBLE);
        // 3秒后自动隐藏(播放状态下)
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            if (player.isPlaying()) {
                controlLayout.setVisibility(View.GONE);
            }
        }, 3000);
    }
    return true; // 消耗事件,避免触发默认点击逻辑
});

// 播放/暂停按钮逻辑
ImageButton playPauseBtn = findViewById(R.id.play_pause_btn);
playPauseBtn.setOnClickListener(v -> {
    if (player.isPlaying()) {
        player.pause();
        playPauseBtn.setImageResource(R.drawable.exo_icon_play);
    } else {
        player.play();
        playPauseBtn.setImageResource(R.drawable.exo_icon_pause);
        // 播放时启动自动隐藏
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            if (player.isPlaying()) {
                controlLayout.setVisibility(View.GONE);
            }
        }, 3000);
    }
});

// 进度条拖拽逻辑
SeekBar seekBar = findViewById(R.id.progress_seek_bar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
            long duration = player.getDuration();
            long position = (duration * progress) / 100;
            player.seekTo(position);
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // 拖拽时保持控制器显示
        controlLayout.setVisibility(View.VISIBLE);
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        // 拖拽结束后重新启动自动隐藏
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            if (player.isPlaying()) {
                controlLayout.setVisibility(View.GONE);
            }
        }, 3000);
    }
});

两种方案各有优劣:方案一适合想保留ExoPlayer默认控制器大部分功能,只修改显示触发逻辑的场景;方案二更灵活,适合需要完全自定义控制器样式和交互的场景。

内容的提问来源于stack exchange,提问作者Elnur Hajiyev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:20:55