MediaController未锚定到视频帧布局问题求助
MediaController未锚定到视频帧布局问题求助
我太懂你这种头疼了——滚动页面时MediaController直接跑到按钮区域,完全脱离了VideoView,这体验简直糟心。我帮你捋捋代码里的问题,再给你可行的解决方案:
问题分析
- 布局结构错位:你在XML里给VideoView加了个平级的
custom_media_controller容器,但实际代码里根本没把MediaController放进这个容器,反而直接用系统默认的控制器锚定到VideoView,这种平级布局很容易导致锚定失效,滚动时控制器就乱跑了。 - ViewHolder复用混乱:每次
onBindViewHolder都新建MediaController,RecyclerView复用ViewHolder时,旧的控制器锚点没清理,就会出现控制器和视频不匹配的情况。 - 无效的布局设置:你给
customMediaController设置了居中参数,但这个容器根本没关联实际的MediaController,等于做了无用功。
解决方案
第一步:简化XML布局
去掉那个没用的custom_media_controller,让MediaController直接锚定到VideoView的父容器video_container,这个容器本身是居中对齐视频的,能保证控制器始终在视频区域内:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp"> <!-- Pulsante Play --> <Button android:id="@+id/playButton" android:layout_width="@dimen/larghezza_bottone_piccolo" android:layout_height="@dimen/altezza_bottone_piccolo" android:text="@string/avvia" android:layout_marginTop="3dp" android:layout_marginStart="50dp" /> <FrameLayout android:id="@+id/video_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_centerHorizontal="true" android:layout_below="@+id/playButton"> <VideoView android:id="@+id/videoView" android:layout_width="300dp" android:layout_height="300dp" /> <!-- 移除多余的custom_media_controller,直接用父容器做锚点 --> </FrameLayout> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/deleteButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/delete_icon" android:contentDescription="@string/elimina" android:layout_marginTop="3dp" android:layout_marginStart="20dp" android:layout_toRightOf="@+id/playButton"/> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/downloadButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/baseline_download_24" android:contentDescription="@string/download" android:layout_marginTop="3dp" android:layout_toRightOf="@+id/deleteButton" android:layout_marginStart="20dp" /> </RelativeLayout>
第二步:优化Adapter的ViewHolder和绑定逻辑
把MediaController的初始化移到ViewHolder里,避免每次绑定都新建,同时确保锚点始终是视频的父容器:
// 修改VideoViewHolder,提前初始化MediaController public class VideoViewHolder extends RecyclerView.ViewHolder { public VideoView videoView; public FrameLayout videoContainer; public MediaController mediaController; public Button playButton; public FloatingActionButton deleteButton, downloadButton; public VideoViewHolder(@NonNull View itemView) { super(itemView); videoView = itemView.findViewById(R.id.videoView); videoContainer = itemView.findViewById(R.id.video_container); playButton = itemView.findViewById(R.id.playButton); deleteButton = itemView.findViewById(R.id.deleteButton); downloadButton = itemView.findViewById(R.id.downloadButton); // 在ViewHolder初始化时创建MediaController,复用的时候就不会重复创建 mediaController = new MediaController(itemView.getContext()); // 锚定到视频的父容器,确保控制器跟着视频走 mediaController.setAnchorView(videoContainer); videoView.setMediaController(mediaController); } } // 修改onBindViewHolder方法 @Override public void onBindViewHolder(@NonNull VideoViewHolder holder, int position) { String videoURL = videoURLs.get(position); VideoView videoView = holder.videoView; // 重置锚点,防止ViewHolder复用导致的错位 holder.mediaController.setAnchorView(holder.videoContainer); videoView.setMediaController(holder.mediaController); // 设置视频路径(这里根据你的实际情况调整,比如用Uri) videoView.setVideoURI(Uri.parse(videoURL)); // 你的其他逻辑,比如播放按钮点击事件等... holder.playButton.setOnClickListener(v -> { if (videoView.isPlaying()) { videoView.pause(); holder.playButton.setText(R.string.avvia); } else { videoView.start(); holder.playButton.setText(R.string.pausa); } }); // 其他按钮逻辑... }
第三步:滚动时的额外优化
为了彻底避免滚动时控制器乱跑,可以给RecyclerView加滚动监听,滚动时暂停视频并隐藏控制器:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 当开始滚动或滚动中时,暂停所有可见视频并隐藏控制器 if (newState == RecyclerView.SCROLL_STATE_DRAGGING || newState == RecyclerView.SCROLL_STATE_SETTLING) { for (int i = 0; i < recyclerView.getChildCount(); i++) { View child = recyclerView.getChildAt(i); VideoViewHolder holder = (VideoViewHolder) recyclerView.getChildViewHolder(child); if (holder.videoView.isPlaying()) { holder.videoView.pause(); holder.playButton.setText(R.string.avvia); } holder.mediaController.hide(); } } } });
这样改完之后,MediaController应该会牢牢锚定在视频区域,滚动时也不会乱跑了。你可以先试试前两步,第三步是锦上添花的优化,能让体验更流畅。
备注:内容来源于stack exchange,提问作者Arianna Garaglia
相关产品推荐
相关产品推荐

